Add workspace context to provider requests
This commit is contained in:
1 parent
e81a0e2d26
commit
cf2ed628b0
3 files changed
+49
-7
No files matched your search
@@ -135,6 +135,7 @@ export function SettingsPage({ snapshot, actions }: PageProps) {
|
||||
providers={providers}
|
||||
catalog={snapshot.providerCatalog}
|
||||
agents={agents}
|
||||
workspaces={workspaces}
|
||||
providerRateLimits={providerRateLimits}
|
||||
providerRequests={providerRequests}
|
||||
actions={actions}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState, type FormEvent } from "react";
|
||||
import type { ProviderCatalogEntry, ProviderRecord, ProviderRequestRecord } from "../../../../shared/domain";
|
||||
import type { ProviderCatalogEntry, ProviderRecord, ProviderRequestRecord, WorkspaceRecord } from "../../../../shared/domain";
|
||||
import { PROVIDER_DATA_POLICY, PROVIDER_EXECUTION_MODE, PROVIDER_REQUEST_STATE, type ProviderExecutionMode } from "../../../../shared/domain";
|
||||
import type { SnapshotActions } from "../../app/useSnapshot";
|
||||
import { Button, Field, Icon, Pill, Segmented } from "../../shared/ui";
|
||||
@@ -8,6 +8,7 @@ interface ProviderRequestPanelProps {
|
||||
orgId: string;
|
||||
providers: ProviderRecord[];
|
||||
catalog: ProviderCatalogEntry[];
|
||||
workspaces: WorkspaceRecord[];
|
||||
providerRequests: ProviderRequestRecord[];
|
||||
actions: SnapshotActions;
|
||||
}
|
||||
@@ -26,15 +27,18 @@ export function ProviderRequestPanel({
|
||||
orgId,
|
||||
providers,
|
||||
catalog,
|
||||
workspaces,
|
||||
providerRequests,
|
||||
actions,
|
||||
}: ProviderRequestPanelProps) {
|
||||
const executableProviders = providers.filter((provider) => provider.enabled && provider.authType === "api_key");
|
||||
const [providerId, setProviderId] = useState(executableProviders[0]?.id ?? "");
|
||||
const [workspaceId, setWorkspaceId] = useState(workspaces[0]?.id ?? "");
|
||||
const [mode, setMode] = useState<ProviderExecutionMode>(PROVIDER_EXECUTION_MODE.FOREGROUND);
|
||||
const selectedProvider = resolveSelectedProvider(executableProviders, providerId);
|
||||
const canRunBackground = selectedProvider ? isBackgroundReady(selectedProvider, catalog) : false;
|
||||
const selectedMode = canRunBackground ? mode : PROVIDER_EXECUTION_MODE.FOREGROUND;
|
||||
const effectiveWorkspaceId = selectedWorkspaceValue(workspaces, workspaceId);
|
||||
const recentRequests = providerRequests
|
||||
.filter((request) => executableProviders.some((provider) => provider.id === request.providerId))
|
||||
.slice(0, 8);
|
||||
@@ -51,6 +55,7 @@ export function ProviderRequestPanel({
|
||||
void actions.run(() => window.agentCompany.createProviderResponse({
|
||||
orgId,
|
||||
providerId: requireProviderId(selectedProvider),
|
||||
workspaceId: selectedWorkspaceId(workspaces, effectiveWorkspaceId),
|
||||
prompt,
|
||||
instructions: instructions || null,
|
||||
executionMode: selectedMode,
|
||||
@@ -61,7 +66,7 @@ export function ProviderRequestPanel({
|
||||
<>
|
||||
<div className="section-label" style={{ marginBottom: 10 }}>Requests</div>
|
||||
<form className="card" style={{ marginBottom: 10 }} onSubmit={submit}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "minmax(150px, 1fr) minmax(200px, 1fr) auto", gap: 10, alignItems: "end" }}>
|
||||
<div style={{ display: "grid", gridTemplateColumns: "minmax(150px, 1fr) minmax(150px, 1fr) minmax(200px, 1fr) auto", gap: 10, alignItems: "end" }}>
|
||||
<Field label="Provider">
|
||||
<select
|
||||
className="input"
|
||||
@@ -74,6 +79,20 @@ export function ProviderRequestPanel({
|
||||
))}
|
||||
</select>
|
||||
</Field>
|
||||
<Field label="Workspace">
|
||||
<select
|
||||
className="input"
|
||||
aria-label="Request workspace"
|
||||
value={effectiveWorkspaceId}
|
||||
disabled={workspaces.length === 0}
|
||||
onChange={(event) => setWorkspaceId(event.target.value)}
|
||||
>
|
||||
{workspaces.length === 0 && <option value="">Organization</option>}
|
||||
{workspaces.map((workspace) => (
|
||||
<option key={workspace.id} value={workspace.id}>{workspace.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</Field>
|
||||
<div className="field">
|
||||
<span>Mode</span>
|
||||
<div style={{ alignSelf: "flex-start" }}>
|
||||
@@ -99,9 +118,9 @@ export function ProviderRequestPanel({
|
||||
</Field>
|
||||
</form>
|
||||
{recentRequests.length > 0 && (
|
||||
<div className="card" style={{ padding: 0, overflow: "hidden", marginBottom: 28 }}>
|
||||
<div className="table-row head" style={{ gridTemplateColumns: "minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px" }}>
|
||||
<div>Provider</div><div>Mode</div><div>State</div><div>Output</div><div>Action</div>
|
||||
<div className="card" style={{ padding: 0, overflowX: "auto", marginBottom: 28 }}>
|
||||
<div className="table-row head" style={{ gridTemplateColumns: "minmax(120px, 1fr) minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px", minWidth: 760 }}>
|
||||
<div>Provider</div><div>Workspace</div><div>Mode</div><div>State</div><div>Output</div><div>Action</div>
|
||||
</div>
|
||||
{recentRequests.map((request, index) => (
|
||||
<ProviderRequestRow
|
||||
@@ -109,6 +128,7 @@ export function ProviderRequestPanel({
|
||||
orgId={orgId}
|
||||
request={request}
|
||||
provider={requireRequestProvider(providers, request)}
|
||||
workspace={resolveRequestWorkspace(workspaces, request)}
|
||||
last={index === recentRequests.length - 1}
|
||||
actions={actions}
|
||||
/>
|
||||
@@ -123,12 +143,14 @@ function ProviderRequestRow({
|
||||
orgId,
|
||||
request,
|
||||
provider,
|
||||
workspace,
|
||||
last,
|
||||
actions,
|
||||
}: {
|
||||
orgId: string;
|
||||
request: ProviderRequestRecord;
|
||||
provider: ProviderRecord;
|
||||
workspace: WorkspaceRecord | null;
|
||||
last: boolean;
|
||||
actions: SnapshotActions;
|
||||
}) {
|
||||
@@ -140,7 +162,8 @@ function ProviderRequestRow({
|
||||
<div
|
||||
className="table-row"
|
||||
style={{
|
||||
gridTemplateColumns: "minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px",
|
||||
gridTemplateColumns: "minmax(120px, 1fr) minmax(120px, 1fr) 92px 100px minmax(120px, 1fr) 86px",
|
||||
minWidth: 760,
|
||||
borderBottom: last ? "none" : "1px solid var(--border-soft)",
|
||||
}}
|
||||
>
|
||||
@@ -148,6 +171,7 @@ function ProviderRequestRow({
|
||||
<div style={{ fontWeight: 540, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{provider.label}</div>
|
||||
<div className="mono" style={{ fontSize: 11, color: "var(--text-3)" }}>{request.model}</div>
|
||||
</div>
|
||||
<div className="mono" style={{ color: "var(--text-2)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{workspace?.name ?? "Organization"}</div>
|
||||
<div className="mono" style={{ color: "var(--text-2)" }}>{request.executionMode}</div>
|
||||
<div><Pill tone={stateTone(request.state)}>{request.state}</Pill></div>
|
||||
<div className="mono" style={{ color: "var(--text-2)" }}>{request.outputCharCount} chars</div>
|
||||
@@ -179,6 +203,20 @@ function resolveSelectedProvider(providers: ProviderRecord[], providerId: string
|
||||
return provider ?? providers[0] ?? null;
|
||||
}
|
||||
|
||||
function selectedWorkspaceId(workspaces: WorkspaceRecord[], workspaceId: string): string | null {
|
||||
return workspaces.some((workspace) => workspace.id === workspaceId) ? workspaceId : null;
|
||||
}
|
||||
|
||||
function selectedWorkspaceValue(workspaces: WorkspaceRecord[], workspaceId: string): string {
|
||||
if (workspaces.some((workspace) => workspace.id === workspaceId)) return workspaceId;
|
||||
return workspaces[0]?.id ?? "";
|
||||
}
|
||||
|
||||
function resolveRequestWorkspace(workspaces: WorkspaceRecord[], request: ProviderRequestRecord): WorkspaceRecord | null {
|
||||
if (!request.workspaceId) return null;
|
||||
return workspaces.find((workspace) => workspace.id === request.workspaceId) ?? null;
|
||||
}
|
||||
|
||||
function requireProviderId(provider: ProviderRecord | null): string {
|
||||
if (!provider) throw new Error("Provider is required.");
|
||||
return provider.id;
|
||||
|
||||
@@ -7,6 +7,7 @@ import type {
|
||||
ProviderRateLimitStateRecord,
|
||||
ProviderRecord,
|
||||
ProviderRequestRecord,
|
||||
WorkspaceRecord,
|
||||
} from "../../../../shared/domain";
|
||||
import { PROVIDER_DATA_POLICY } from "../../../../shared/domain";
|
||||
import { ProviderLogo } from "./ProviderLogo";
|
||||
@@ -19,6 +20,7 @@ interface ProvidersPanelProps {
|
||||
providers: ProviderRecord[];
|
||||
catalog: ProviderCatalogEntry[];
|
||||
agents: AgentRecord[];
|
||||
workspaces: WorkspaceRecord[];
|
||||
providerRateLimits: ProviderRateLimitStateRecord[];
|
||||
providerRequests: ProviderRequestRecord[];
|
||||
actions: SnapshotActions;
|
||||
@@ -35,7 +37,7 @@ const CLOUD_DEFAULTS: CloudFields = { baseUrl: "", region: "", projectId: "", de
|
||||
const POLICY_GRID = "minmax(150px, 1.2fr) minmax(118px, 0.8fr) minmax(140px, 1fr) 112px 124px 92px";
|
||||
type WorkspaceScope = "organization" | "workspace";
|
||||
|
||||
export function ProvidersPanel({ orgId, employeeId, providers, catalog, agents, providerRateLimits, providerRequests, actions }: ProvidersPanelProps) {
|
||||
export function ProvidersPanel({ orgId, employeeId, providers, catalog, agents, workspaces, providerRateLimits, providerRequests, actions }: ProvidersPanelProps) {
|
||||
const [active, setActive] = useState<ProviderRecord | null>(null);
|
||||
const [signInLaunched, setSignInLaunched] = useState(false);
|
||||
const connected = providers.filter((provider) => provider.enabled);
|
||||
@@ -96,6 +98,7 @@ export function ProvidersPanel({ orgId, employeeId, providers, catalog, agents,
|
||||
orgId={orgId}
|
||||
providers={connected}
|
||||
catalog={catalog}
|
||||
workspaces={workspaces}
|
||||
providerRequests={providerRequests}
|
||||
actions={actions}
|
||||
/>
|
||||
|
||||
Reference in new issue
Block a user