@kortix/ui 0.14.6 → 0.14.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_vendor/kortix-shared.js +490 -382
- package/dist/_vendor/shared/runtime-versions.d.ts +4 -0
- package/dist/access/access/access-dialog-share.js +4 -7
- package/dist/access/access/access-dialog.js +2 -1
- package/dist/access/access/principal-picker.js +6 -5
- package/dist/customize/agents/agent-authority-card.js +1 -2
- package/dist/customize/agents/agent-cover-card.d.ts +17 -0
- package/dist/customize/agents/agent-cover-card.js +13 -0
- package/dist/customize/agents/agent-detail-aside.js +15 -14
- package/dist/customize/agents/agent-drives-section.js +5 -6
- package/dist/customize/agents/agent-grant-pages.js +68 -70
- package/dist/customize/agents/agent-page.js +27 -19
- package/dist/customize/agents/agent-people-section.js +18 -17
- package/dist/customize/agents/agent-triggers-section.js +6 -5
- package/dist/customize/agents/agents-page.js +43 -49
- package/dist/customize/connectors/catalog/catalog-entry.d.ts +14 -0
- package/dist/customize/connectors/catalog/catalog-entry.js +18 -1
- package/dist/customize/connectors/catalog/connector-browse.d.ts +28 -0
- package/dist/customize/connectors/catalog/connector-browse.js +18 -5
- package/dist/customize/connectors/detail/app-page.js +19 -5
- package/dist/customize/connectors/detail/connector-modal.d.ts +10 -13
- package/dist/customize/connectors/detail/connector-modal.js +18 -101
- package/dist/customize/connectors/detail/connector-notice.js +6 -2
- package/dist/customize/connectors/detail/connector-page.d.ts +30 -0
- package/dist/customize/connectors/detail/connector-page.js +26 -13
- package/dist/customize/migrate-to-v2/migration-prompt.d.ts +1 -0
- package/dist/customize/migrate-to-v2/migration-prompt.js +1 -0
- package/dist/customize/sections/llm-provider/custom-provider-form.js +24 -7
- package/dist/customize/sections/llm-provider/custom-provider-panel.js +44 -8
- package/dist/customize/sections/llm-provider/types.d.ts +3 -0
- package/dist/customize/sections/llm-provider/utils.js +2 -2
- package/dist/customize/sections/view/agent-editor-access-fields.d.ts +9 -16
- package/dist/customize/sections/view/agent-editor-access-fields.js +30 -30
- package/dist/customize/sections/view/agent-editor-basics-fields.js +3 -10
- package/dist/customize/sections/view/agent-editor-primitives.d.ts +28 -10
- package/dist/customize/sections/view/agent-editor-primitives.js +32 -19
- package/dist/customize/sections/view/agent-editor.js +3 -3
- package/dist/customize/sections/view/channels-view.js +2 -6
- package/dist/customize/sections/view/gateway/gateway-routing.js +3 -3
- package/dist/customize/sections/view/grant-mode-field.d.ts +2 -5
- package/dist/customize/sections/view/grant-mode-field.js +10 -18
- package/dist/customize/sections/view/permission-editor.js +11 -8
- package/dist/customize/sections/view/secrets-view.js +2 -1
- package/dist/customize/settings/tabs/general-tab.d.ts +9 -2
- package/dist/customize/settings/tabs/general-tab.js +33 -11
- package/dist/customize/settings/tabs/transfer-workspace-dialog.d.ts +4 -0
- package/dist/customize/settings/tabs/transfer-workspace-dialog.js +82 -0
- package/dist/customize/shared/new-entity-menu.js +4 -1
- package/dist/customize/skills/skills-page.js +4 -5
- package/dist/customize/triggers/schedule/then-fields.js +1 -5
- package/dist/customize/triggers/schedule-view.js +4 -2
- package/dist/files/project/api/runtime-files.js +3 -2
- package/dist/files/project/file-source.js +18 -1
- package/dist/files/project/hooks/use-file-content.js +2 -0
- package/dist/files/viewer/file-header.js +1 -1
- package/dist/files/viewer/file-preview-modal.d.ts +1 -1
- package/dist/files/viewer/file-preview-modal.js +12 -2
- package/dist/files/viewer/file-source.d.ts +3 -1
- package/dist/files/viewer/use-file-content-state.js +26 -7
- package/dist/files/viewer/viewer-actions.js +2 -2
- package/dist/i18n/en.d.ts +393 -12
- package/dist/i18n/en.js +400 -19
- package/dist/internal/components/agent-mark.d.ts +38 -0
- package/dist/internal/components/agent-mark.js +38 -0
- package/dist/internal/files/types.d.ts +2 -0
- package/dist/internal/goals/goal-meta.d.ts +30 -0
- package/dist/internal/goals/goal-meta.js +55 -0
- package/dist/internal/lib/pixel-mark.d.ts +33 -0
- package/dist/internal/lib/pixel-mark.js +152 -0
- package/dist/internal/lib/query-client-singleton.d.ts +9 -3
- package/dist/internal/lib/query-client-singleton.js +18 -12
- package/dist/internal/lib/use-project-feature-flags.js +3 -3
- package/dist/internal/share/session-shares-modal.js +3 -7
- package/dist/internal/stores/kortix-computer-store.js +14 -2
- package/dist/internal/stores/session-hover-store.d.ts +32 -0
- package/dist/internal/stores/session-hover-store.js +38 -0
- package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
- package/dist/internal/stores/sidebar-nav-store.js +3 -1
- package/dist/lib/routes.d.ts +2 -0
- package/dist/lib/routes.js +1 -0
- package/dist/markdown/genui/components/inline.d.ts +1 -1
- package/dist/markdown/setup-links/app-credentials-form.d.ts +12 -0
- package/dist/markdown/setup-links/app-credentials-form.js +115 -0
- package/dist/markdown/setup-links/secret-intake-form.d.ts +10 -0
- package/dist/markdown/setup-links/secret-intake-form.js +1 -1
- package/dist/primitives/entity-avatar.d.ts +4 -1
- package/dist/primitives/entity-avatar.js +4 -2
- package/dist/primitives/settings-section-header.d.ts +1 -1
- package/dist/primitives/user-avatar.d.ts +3 -1
- package/dist/primitives/user-avatar.js +4 -2
- package/dist/providers/ui-provider.d.ts +1 -1
- package/dist/session/composer/agent-selector.d.ts +7 -1
- package/dist/session/composer/agent-selector.js +20 -10
- package/dist/session/composer/attachment-tile.d.ts +0 -2
- package/dist/session/composer/attachment-tile.js +0 -8
- package/dist/session/composer/clipboard-files.d.ts +2 -1
- package/dist/session/composer/composer-draft-recovery.d.ts +1 -2
- package/dist/session/composer/composer-draft-recovery.js +0 -13
- package/dist/session/composer/context-ring.d.ts +1 -1
- package/dist/session/composer/context-ring.js +2 -2
- package/dist/session/composer/context-usage.d.ts +8 -6
- package/dist/session/composer/context-usage.js +9 -7
- package/dist/session/composer/inbox-row-claims.d.ts +2 -2
- package/dist/session/composer/inbox-row-claims.js +1 -1
- package/dist/session/composer/queue-projection.d.ts +3 -2
- package/dist/session/composer/queued-prompt-edit.d.ts +1 -1
- package/dist/session/composer/reasoning-effort-selector.d.ts +2 -1
- package/dist/session/composer/session-composer-readiness.d.ts +7 -22
- package/dist/session/composer/session-composer-readiness.js +12 -40
- package/dist/session/composer/token-progress.d.ts +1 -1
- package/dist/session/composer/token-progress.js +6 -6
- package/dist/session/header/export-transcript-modal.d.ts +3 -2
- package/dist/session/header/export-transcript-modal.js +6 -3
- package/dist/session/header/session-goal-indicator.d.ts +1 -0
- package/dist/session/header/session-goal-indicator.js +41 -0
- package/dist/session/header/session-site-header.js +2 -1
- package/dist/session/models/model-selector.d.ts +3 -1
- package/dist/session/models/model-selector.js +3 -2
- package/dist/session/panel/easy/plan-card.d.ts +2 -0
- package/dist/session/panel/easy/plan-card.js +2 -0
- package/dist/session/panel/session-action-panel-column.js +11 -1
- package/dist/session/panel/session-audit-shared.d.ts +0 -4
- package/dist/session/panel/session-audit-shared.js +1 -1
- package/dist/session/panel/session-changes-shared.d.ts +2 -1
- package/dist/session/prompts/session-permission-prompt.js +6 -3
- package/dist/session/status/provisioning-failure.d.ts +2 -1
- package/dist/session/status/session-error-banner.js +8 -6
- package/dist/session/status/session-starting-loader.d.ts +24 -31
- package/dist/session/status/session-starting-loader.js +32 -81
- package/dist/session/thread/chat-minimap-items.d.ts +4 -4
- package/dist/session/thread/first-prompt-handover.d.ts +3 -2
- package/dist/session/thread/message-parsing.d.ts +3 -3
- package/dist/session/thread/plan-surface.d.ts +1 -0
- package/dist/session/thread/plan-surface.js +1 -0
- package/dist/session/thread/session-chat.js +5 -12
- package/dist/session/thread/session-context-metrics.d.ts +15 -0
- package/dist/session/thread/session-context-metrics.js +10 -1
- package/dist/session/thread/session-context-modal.d.ts +4 -2
- package/dist/session/thread/session-context-modal.js +16 -9
- package/dist/session/thread/session-history-scroll.d.ts +2 -1
- package/dist/session/thread/session-thread.js +1 -1
- package/dist/session/thread/transcript.d.ts +4 -0
- package/dist/session/thread/transcript.js +18 -5
- package/dist/session/thread/turn-share.d.ts +16 -0
- package/dist/session/thread/turn-share.js +162 -0
- package/dist/session/tool/tools/apply-patch-tool.d.ts +1 -0
- package/dist/session/tool/tools/apply-patch-tool.js +1 -0
- package/dist/session/tool/tools/pty-kill-tool.d.ts +1 -0
- package/dist/session/tool/tools/pty-kill-tool.js +1 -0
- package/dist/session/tool/tools/pty-read-tool.d.ts +2 -0
- package/dist/session/tool/tools/pty-read-tool.js +2 -0
- package/dist/session/tool/tools/pty-spawn-tool.d.ts +1 -0
- package/dist/session/tool/tools/pty-spawn-tool.js +1 -0
- package/dist/session/tool/tools/pty-write-tool.d.ts +1 -0
- package/dist/session/tool/tools/pty-write-tool.js +1 -0
- package/dist/session/tool/tools/todo-write-tool.d.ts +1 -0
- package/dist/session/tool/tools/todo-write-tool.js +1 -0
- package/dist/session/turn/message-author-label.js +6 -2
- package/dist/session/turn/plan-anchor.d.ts +3 -0
- package/dist/session/turn/plan-anchor.js +3 -0
- package/dist/session/turn/plan-card.d.ts +7 -0
- package/dist/session/turn/plan-card.js +7 -0
- package/dist/styles.css +1 -1
- package/dist/terminal/pty-connection.d.ts +5 -4
- package/dist/terminal/session-terminal-connect-bar.js +2 -1
- package/dist/workspace/index.d.ts +1 -0
- package/dist/workspace/index.js +1 -0
- package/dist/workspace/saved-session-skeleton-shape.d.ts +4 -3
- package/dist/workspace/saved-session-skeleton.d.ts +5 -1
- package/dist/workspace/saved-session-skeleton.js +5 -4
- package/dist/workspace/session-workspace.js +4 -5
- package/dist/workspace/sidebar/footer/project-goals-nav.d.ts +6 -0
- package/dist/workspace/sidebar/footer/project-goals-nav.js +26 -0
- package/dist/workspace/sidebar/modal/session-embed-section.d.ts +25 -0
- package/dist/workspace/sidebar/modal/session-embed-section.js +71 -0
- package/dist/workspace/sidebar/modal/share-session-modal.js +2 -2
- package/dist/workspace/sidebar/nav-row-meta.js +14 -2
- package/dist/workspace/sidebar/project-nav-items.js +3 -0
- package/dist/workspace/sidebar/project-session-list.js +12 -3
- package/dist/workspace/sidebar/session-brief-hover-card.js +33 -9
- package/package.json +12 -4
- package/skills/kortix-ui/references/modules.md +2 -0
- package/dist/session/status/use-readiness-settling.d.ts +0 -18
- package/dist/session/status/use-readiness-settling.js +0 -43
- package/dist/workspace/sidebar/modal/session-public-link-section.d.ts +0 -13
- package/dist/workspace/sidebar/modal/session-public-link-section.js +0 -66
|
@@ -47,13 +47,13 @@ import { useTranslations } from '../../../../i18n/index.js';
|
|
|
47
47
|
*
|
|
48
48
|
* | Capability | Where it is now |
|
|
49
49
|
* | --- | --- |
|
|
50
|
-
* | Inherit / custom / no fallback | "When
|
|
50
|
+
* | Inherit / custom / no fallback | "When a model fails" row (primary) |
|
|
51
51
|
* | Ordered default chain, reorder + remove, max 8 | Chain row — one line per step (primary) |
|
|
52
52
|
* | Fallback condition (transient / any error) | "Retry on" line, inside the chain it belongs to |
|
|
53
53
|
* | Per-model override rules, max 20 | "Per-model overrides" — one row per rule, promoted second (primary) |
|
|
54
54
|
* | Vision (image-input) override | "Vision model" row, inside Advanced |
|
|
55
55
|
* | Per-model generation defaults | "Generation defaults" section, inside Advanced |
|
|
56
|
-
* | Provider-availability preview | `AvailabilityBadge`,
|
|
56
|
+
* | Provider-availability preview | `AvailabilityBadge`, on every chain step and override |
|
|
57
57
|
* | Reset / dirty / validation / save | Header action + sticky footer, unchanged |
|
|
58
58
|
*
|
|
59
59
|
* The data contract is untouched: same props in, same `routing.set` /
|
|
@@ -438,7 +438,7 @@ export function GatewayRouting({ projectId, canWrite, projectDefaultPending, })
|
|
|
438
438
|
};
|
|
439
439
|
});
|
|
440
440
|
};
|
|
441
|
-
return (_jsxs(RoutingSection, { action: writable ? (_jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: controlsDisabled, onClick: () => setResetOpen(true), children: [_jsx(RotateCcw, { className: "size-3.5" }), " ", tI18nComplete.raw('textdaee7606b339')] })) : (_jsx(Badge, { variant: "muted", size: "sm", children: tI18nComplete.raw('text8ac767353080') })), children: [_jsxs("div", { className: "space-y-8", children: [_jsxs("section", { className: "space-y-1", children: [_jsx(Label, { className: "text-foreground", children: tI18nComplete.raw('text325e84939c64') }), _jsxs("div", { className: "flex flex-col", children: [_jsx(RoutingRow, { label: tI18nComplete.raw('text146b38e7fa80'), hint: tI18nComplete.raw('textd48d1b0dbdd6'), children: _jsxs(Select, { value: fallbackMode, disabled: controlsDisabled, onValueChange: (mode) => changeFallbackMode(mode), children: [_jsx(SelectTrigger, { className: "w-48 max-w-full", "aria-label": tI18nComplete.raw('textdf33a10e5579'), children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "inherit", children: tI18nComplete.raw('text975aa2ab538e') }), _jsx(SelectItem, { value: "custom", children: tI18nComplete.raw('texta913ec01bd04') }), _jsx(SelectItem, { value: "disabled", children: tI18nComplete.raw('text3822b0412ed7') })] })] }) }), fallbackMode === 'custom' && draft.defaultFallback ? (_jsx(RoutingRow, { align: "start", label:
|
|
441
|
+
return (_jsxs(RoutingSection, { action: writable ? (_jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: controlsDisabled, onClick: () => setResetOpen(true), children: [_jsx(RotateCcw, { className: "size-3.5" }), " ", tI18nComplete.raw('textdaee7606b339')] })) : (_jsx(Badge, { variant: "muted", size: "sm", children: tI18nComplete.raw('text8ac767353080') })), children: [_jsxs("div", { className: "space-y-8", children: [_jsxs("section", { className: "space-y-1", children: [_jsx(Label, { className: "text-foreground", children: tI18nComplete.raw('text325e84939c64') }), _jsxs("div", { className: "flex flex-col", children: [_jsx(RoutingRow, { label: tI18nComplete.raw('text146b38e7fa80'), hint: tI18nComplete.raw('textd48d1b0dbdd6'), children: _jsxs(Select, { value: fallbackMode, disabled: controlsDisabled, onValueChange: (mode) => changeFallbackMode(mode), children: [_jsx(SelectTrigger, { className: "w-48 max-w-full", "aria-label": tI18nComplete.raw('textdf33a10e5579'), children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "inherit", children: tI18nComplete.raw('text975aa2ab538e') }), _jsx(SelectItem, { value: "custom", children: tI18nComplete.raw('texta913ec01bd04') }), _jsx(SelectItem, { value: "disabled", children: tI18nComplete.raw('text3822b0412ed7') })] })] }) }), fallbackMode === 'custom' && draft.defaultFallback ? (_jsx(RoutingRow, { align: "start", label: tI18nComplete.raw('texte75d99a42dba'), hint: tI18nComplete.raw('textc3ecd3cd791b'), children: _jsx("div", { className: "space-y-1.5", children: _jsx(ChainRows, { primary: primaryModel, chain: draft.defaultFallback, models: models, disabled: controlsDisabled, availability: availability, onChange: (defaultFallback) => setDraft({ ...draft, defaultFallback }) }) }) })) : fallbackMode === 'inherit' ? (_jsx(RoutingRow, { label: tI18nComplete.raw('text74a1a0f65906'), children: _jsx("p", { className: "text-muted-foreground truncate font-mono text-xs", children: inheritedRoute }) })) : (_jsx(RoutingRow, { label: tI18nComplete.raw('text0af465ef42c0'), children: _jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: tI18nComplete.raw('texta3df3f9e4422') }) }))] })] }), _jsxs("section", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Label, { className: "text-foreground", children: tI18nComplete.raw('text5c63c15261bb') }), draft.rules.length > 0 ? (_jsx(Badge, { variant: "secondary", size: "sm", children: draft.rules.length })) : null] }), writable ? (_jsxs(Button, { type: "button", size: "sm", variant: "secondary", disabled: controlsDisabled || !newRuleModel || draft.rules.length >= MAX_RULES, onClick: () => newRuleModel &&
|
|
442
442
|
setDraft({
|
|
443
443
|
...draft,
|
|
444
444
|
rules: [
|
|
@@ -7,11 +7,9 @@ export declare function grantSummary(v: AgentGrantSetV2 | undefined, tI18nComple
|
|
|
7
7
|
label: string;
|
|
8
8
|
tone: 'muted' | 'outline';
|
|
9
9
|
};
|
|
10
|
-
export declare function GrantModeField({ value, onChange,
|
|
10
|
+
export declare function GrantModeField({ value, onChange, alwaysRender, children, }: {
|
|
11
11
|
value: AgentGrantSetV2 | undefined;
|
|
12
12
|
onChange: (v: AgentGrantSetV2) => void;
|
|
13
|
-
allLabel: string;
|
|
14
|
-
noneLabel: string;
|
|
15
13
|
/** Render `children` in every mode, not only Pick — for a catalog that
|
|
16
14
|
* stays on screen and shows each card as included / excluded. */
|
|
17
15
|
alwaysRender?: boolean;
|
|
@@ -34,12 +32,11 @@ export interface GrantOption {
|
|
|
34
32
|
/** At the row's right edge — a `Badge` for a connector that needs auth. */
|
|
35
33
|
trailing?: ReactNode;
|
|
36
34
|
}
|
|
37
|
-
export declare function GrantSetField({ value, onChange, options, emptyLabel,
|
|
35
|
+
export declare function GrantSetField({ value, onChange, options, emptyLabel, rowAccessory, }: {
|
|
38
36
|
value: AgentGrantSetV2 | undefined;
|
|
39
37
|
onChange: (v: AgentGrantSetV2) => void;
|
|
40
38
|
options: GrantOption[];
|
|
41
39
|
emptyLabel: string;
|
|
42
|
-
allLabel: string;
|
|
43
40
|
/** Optional control rendered BESIDE each granted row (e.g. the connectors
|
|
44
41
|
* field's "personal" toggle). The row itself is a `<button>`, so an
|
|
45
42
|
* interactive accessory cannot be nested inside it — when this returns a
|
|
@@ -7,9 +7,9 @@ import { useTranslations as useI18nTranslations } from '../../../i18n/index.js';
|
|
|
7
7
|
* (kortix_permissions) share the same state transitions instead of re-implementing
|
|
8
8
|
* them twice.
|
|
9
9
|
*/
|
|
10
|
-
import { Tabs,
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { Tabs, TabsList, TabsTrigger } from '../../../primitives/tabs.js';
|
|
11
|
+
import { Badge } from '../../../primitives/badge.js';
|
|
12
|
+
import { Checkbox } from '../../../primitives/checkbox.js';
|
|
13
13
|
import { useState } from 'react';
|
|
14
14
|
import { KORTIX_PERMISSIONS_CATALOG } from './agent-editor-catalog.js';
|
|
15
15
|
import { useUiParams } from '../../../providers/ui-provider.js';
|
|
@@ -31,7 +31,7 @@ const GRANT_MODES = [
|
|
|
31
31
|
{ value: 'pick', label: 'Pick' },
|
|
32
32
|
{ value: 'none', label: 'None' },
|
|
33
33
|
];
|
|
34
|
-
export function GrantModeField({ value, onChange,
|
|
34
|
+
export function GrantModeField({ value, onChange, alwaysRender = false, children, }) {
|
|
35
35
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
36
36
|
const mode = value === 'all' ? 'all' : value === 'none' || value === undefined ? 'none' : 'pick';
|
|
37
37
|
const [wantPick, setWantPick] = useState(() => Array.isArray(value) && value.length > 0);
|
|
@@ -57,13 +57,13 @@ export function GrantModeField({ value, onChange, allLabel, noneLabel, alwaysRen
|
|
|
57
57
|
next.add(id);
|
|
58
58
|
onChange([...next]);
|
|
59
59
|
};
|
|
60
|
-
return (_jsxs("div", { className: "space-y-
|
|
60
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsx(Tabs, { value: effectiveMode, onValueChange: (m) => pick(m), children: _jsx(TabsList, { "aria-label": tI18nComplete.raw('text74009e6664f5'), children: GRANT_MODES.map((m) => (_jsx(TabsTrigger, { value: m.value, children: m.label }, m.value))) }) }), effectiveMode === 'pick' || alwaysRender
|
|
61
61
|
? children({ selected, toggle, mode: effectiveMode })
|
|
62
62
|
: null] }));
|
|
63
63
|
}
|
|
64
|
-
export function GrantSetField({ value, onChange, options, emptyLabel,
|
|
64
|
+
export function GrantSetField({ value, onChange, options, emptyLabel, rowAccessory, }) {
|
|
65
65
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
66
|
-
return (_jsx(GrantModeField, { value: value, onChange: onChange,
|
|
66
|
+
return (_jsx(GrantModeField, { value: value, onChange: onChange, children: ({ selected, toggle }) => {
|
|
67
67
|
const optionIds = new Set(options.map((o) => o.id));
|
|
68
68
|
const orphans = [];
|
|
69
69
|
for (const id of selected) {
|
|
@@ -71,14 +71,11 @@ export function GrantSetField({ value, onChange, options, emptyLabel, allLabel,
|
|
|
71
71
|
orphans.push({ id, label: id });
|
|
72
72
|
}
|
|
73
73
|
const rows = [...options, ...orphans];
|
|
74
|
-
return rows.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs", children: emptyLabel })) : (_jsx("
|
|
74
|
+
return rows.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs", children: emptyLabel })) : (_jsx("ul", { className: "bg-popover divide-border max-h-96 divide-y overflow-y-auto rounded-md border", children: rows.map((o) => {
|
|
75
75
|
const isSel = selected.has(o.id);
|
|
76
76
|
const isOrphan = !optionIds.has(o.id);
|
|
77
77
|
const accessory = rowAccessory?.(o.id, isSel);
|
|
78
|
-
|
|
79
|
-
? 'border-foreground bg-foreground text-background'
|
|
80
|
-
: 'border-border/70'), children: isSel ? _jsx(CheckIcon, { className: "size-2.5" }) : null }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate font-mono", children: o.label }), o.description ? (_jsx("span", { className: "text-muted-foreground block truncate text-xs leading-4", children: o.description })) : null] }), o.trailing ? _jsx("span", { className: "shrink-0", children: o.trailing }) : null, isOrphan && (_jsx("span", { className: "text-kortix-orange shrink-0", children: tI18nComplete.raw('textffa63583dfa6') }))] }, o.id));
|
|
81
|
-
return accessory ? (_jsxs("div", { className: "flex items-center gap-1", children: [row, accessory] }, o.id)) : (row);
|
|
78
|
+
return (_jsxs("li", { className: "flex items-center gap-3 px-4 py-2.5", children: [_jsx(Checkbox, { variant: "black", checked: isSel, onCheckedChange: () => toggle(o.id), "aria-label": o.label }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "text-foreground block truncate font-mono text-sm", children: o.label }), o.description ? (_jsx("span", { className: "text-muted-foreground block truncate text-xs", children: o.description })) : null] }), isOrphan ? (_jsx(Badge, { variant: "warning", size: "xs", children: tI18nComplete.raw('textffa63583dfa6') })) : null, o.trailing, accessory] }, o.id));
|
|
82
79
|
}) }));
|
|
83
80
|
} }));
|
|
84
81
|
}
|
|
@@ -88,10 +85,5 @@ export function KortixPermissionsField({ value, onChange, }) {
|
|
|
88
85
|
const params = useUiParams();
|
|
89
86
|
const { flags } = useProjectFeatureFlags(typeof params.id === 'string' ? params.id : null);
|
|
90
87
|
const groups = KORTIX_PERMISSIONS_CATALOG.filter((grp) => !grp.featureFlag || flags[grp.featureFlag] === true);
|
|
91
|
-
return (_jsx(GrantModeField, { value: value, onChange: onChange,
|
|
92
|
-
const isSel = selected.has(action);
|
|
93
|
-
return (_jsx("button", { type: "button", "aria-pressed": isSel, onClick: () => toggle(action), className: cn('rounded px-1.5 py-1 font-mono text-xs transition-[color,background-color,transform] active:scale-[0.96]', isSel
|
|
94
|
-
? 'bg-foreground text-background'
|
|
95
|
-
: 'bg-muted/40 text-muted-foreground hover:bg-muted'), children: action.replace(/^project\./, '') }, action));
|
|
96
|
-
}) })] }, grp.group))) })) }));
|
|
88
|
+
return (_jsx(GrantModeField, { value: value, onChange: onChange, children: ({ selected, toggle }) => (_jsx("div", { className: "bg-popover divide-border divide-y rounded-md border", children: groups.map((grp) => (_jsxs("div", { className: "space-y-2.5 px-4 py-3", children: [_jsx("p", { className: "text-muted-foreground text-xs font-medium", children: grp.group }), _jsx("div", { className: "-mx-3 grid gap-x-2 gap-y-0.5 sm:grid-cols-2", children: grp.actions.map((action) => (_jsx(Checkbox, { variant: "black", checked: selected.has(action), onCheckedChange: () => toggle(action), label: _jsx("span", { className: "font-mono text-xs", children: action.replace(/^project\./, '') }) }, action))) })] }, grp.group))) })) }));
|
|
97
89
|
}
|
|
@@ -3,7 +3,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useTranslations as useI18nTranslations } from '../../../i18n/index.js';
|
|
4
4
|
/** The tool-permission editor — a default action plus per-tool rules (a bare
|
|
5
5
|
* action, or a map of path/command patterns to actions). */
|
|
6
|
-
import { Badge } from '../../../primitives/badge.js';
|
|
7
6
|
import { Button } from '../../../primitives/button.js';
|
|
8
7
|
import Hint from '../../../primitives/hint.js';
|
|
9
8
|
import { Input } from '../../../primitives/input.js';
|
|
@@ -12,6 +11,8 @@ import { PlusIcon as Plus, TrashIcon as Trash2 } from '@phosphor-icons/react';
|
|
|
12
11
|
import { AnimatePresence, m } from 'motion/react';
|
|
13
12
|
import { useState } from 'react';
|
|
14
13
|
import { PERMISSION_ACTION_LABEL, PERMISSION_ACTION_ONLY_GROUP_LABEL, PERMISSION_ACTION_ONLY_KEYS, PERMISSION_ACTIONS, PERMISSION_KEY_HELP, PERMISSION_KEY_LABEL, PERMISSION_RULE_GROUPS, PERMISSION_RULE_KEYS, } from './agent-editor-catalog.js';
|
|
14
|
+
import { SettingsRow, SettingsRowGroup } from '../../../primitives/settings-row.js';
|
|
15
|
+
import { SettingsSubsectionHeader } from '../../../primitives/settings-subsection-header.js';
|
|
15
16
|
import { EditorSection } from './agent-editor-primitives.js';
|
|
16
17
|
/** Radix forbids `""` as an item value, so the inherit state carries a sentinel. */
|
|
17
18
|
const INHERIT = '__inherit__';
|
|
@@ -41,7 +42,7 @@ function asPermObject(permission) {
|
|
|
41
42
|
* leads; the token stays because people grep for it and hand-edit the YAML.
|
|
42
43
|
*/
|
|
43
44
|
function PermissionKeyName({ permKey }) {
|
|
44
|
-
return (_jsx(Hint, { label: PERMISSION_KEY_HELP[permKey] ?? permKey, side: "top", children: _jsxs("span", { className: "flex min-w-0 cursor-default items-baseline gap-2", children: [_jsx("span", { className: "text-foreground truncate text-sm", children: PERMISSION_KEY_LABEL[permKey] ?? permKey }), _jsx("span", { className: "text-muted-foreground
|
|
45
|
+
return (_jsx(Hint, { label: PERMISSION_KEY_HELP[permKey] ?? permKey, side: "top", children: _jsxs("span", { className: "flex min-w-0 cursor-default items-baseline gap-2", children: [_jsx("span", { className: "text-foreground truncate text-sm", children: PERMISSION_KEY_LABEL[permKey] ?? permKey }), _jsx("span", { className: "text-muted-foreground shrink-0 font-mono text-xs", children: permKey })] }) }));
|
|
45
46
|
}
|
|
46
47
|
/** One action-typed key: a bare allow/ask/deny/inherit, plus expandable
|
|
47
48
|
* pattern → action rules. */
|
|
@@ -68,7 +69,7 @@ function PermissionRuleRow({ label, rule, onChange, }) {
|
|
|
68
69
|
next[k === from ? to : k] = v;
|
|
69
70
|
onChange(next);
|
|
70
71
|
};
|
|
71
|
-
return (_jsxs("div", { className: "space-y-2 px-
|
|
72
|
+
return (_jsxs("div", { className: "space-y-2 px-4 py-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx(PermissionKeyName, { permKey: label }), _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [_jsx(ActionSelect, { value: isMap ? undefined : bare, onChange: setBare, inheritLabel: tI18nComplete.raw('text3f72f0385768'), label: tI18nComplete('textfaaaefbff336', {
|
|
72
73
|
value0: PERMISSION_KEY_LABEL[label] ?? label,
|
|
73
74
|
}) }), _jsxs(Button, { type: "button", variant: isMap || showRules ? 'secondary' : 'outline', size: "sm", className: "gap-1 px-2 text-xs", "aria-expanded": showRules, onClick: () => setShowRules((s) => !s), children: [tI18nComplete.raw('text4228aeb07c41'), ruleCount > 0 ? _jsx("span", { className: "tabular-nums", children: ruleCount }) : null] })] })] }), _jsx(AnimatePresence, { initial: false, children: showRules && (_jsx(m.div, { initial: { opacity: 0, height: 0 }, animate: { opacity: 1, height: 'auto' }, exit: { opacity: 0, height: 0 }, transition: { type: 'spring', duration: 0.3, bounce: 0 }, className: "overflow-hidden", children: _jsxs("div", { className: "bg-muted/40 space-y-1.5 rounded-md p-2", children: [ruleCount === 0 ? (_jsx("p", { className: "text-muted-foreground px-1 pt-0.5 text-xs text-pretty", children: tI18nComplete.raw('text8d1833ac5f65') })) : null, Object.entries(map).map(([pattern, action]) => (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Input, { value: pattern, "aria-label": tI18nComplete.raw('text4288ade73ff9'), placeholder: tI18nComplete.raw('textcf134a1de504'), variant: "popover", className: "h-8 flex-1 font-mono text-xs", onChange: (e) => renameRule(pattern, e.target.value) }), _jsx(ActionSelect, { value: action, label: tI18nComplete('text494cb0162c19', {
|
|
74
75
|
value0: pattern || tI18nComplete.raw('textc6fbcde46fa9'),
|
|
@@ -92,9 +93,9 @@ export function ToolsSection({ permission, onChange, }) {
|
|
|
92
93
|
: permission && Object.keys(permission).length > 0
|
|
93
94
|
? `${Object.keys(permission).length} tool${Object.keys(permission).length === 1 ? '' : 's'} customized`
|
|
94
95
|
: 'Every tool follows the runtime default';
|
|
95
|
-
return (_jsx(EditorSection, { title: tI18nComplete.raw('textea93d6a262ec'), description: tI18nComplete.raw('text765f388e2ce6'),
|
|
96
|
+
return (_jsx(EditorSection, { title: tI18nComplete.raw('textea93d6a262ec'), description: tI18nComplete.raw('text765f388e2ce6'), lead: true, bare: true, children: _jsx(PermissionEditor, { permission: permission, onChange: onChange, summary: summary }) }));
|
|
96
97
|
}
|
|
97
|
-
function PermissionEditor({ permission, onChange, }) {
|
|
98
|
+
function PermissionEditor({ permission, onChange, summary, }) {
|
|
98
99
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
99
100
|
const obj = asPermObject(permission);
|
|
100
101
|
const bareDefault = typeof permission === 'string' ? permission : undefined;
|
|
@@ -111,7 +112,9 @@ function PermissionEditor({ permission, onChange, }) {
|
|
|
111
112
|
next[key] = value;
|
|
112
113
|
onChange(Object.keys(next).length ? next : undefined);
|
|
113
114
|
};
|
|
114
|
-
return (_jsxs("div", { className: "space-y-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
return (_jsxs("div", { className: "space-y-8", children: [_jsx(SettingsRowGroup, { children: _jsx(SettingsRow, { label: tI18nComplete.raw('text9b99443d24c5'), description: bareDefault
|
|
116
|
+
? tI18nComplete.raw('textabba11786cee')
|
|
117
|
+
: Object.keys(obj).length > 0
|
|
118
|
+
? `${summary}.`
|
|
119
|
+
: tI18nComplete.raw('texte640da5d14fd'), children: _jsx(ActionSelect, { value: bareDefault, onChange: setDefault, inheritLabel: tI18nComplete.raw('text8d2dd4e8c7ca'), label: tI18nComplete.raw('text9b99443d24c5') }) }) }), PERMISSION_RULE_GROUPS.map((group) => (_jsxs("section", { className: "space-y-3", children: [_jsx(SettingsSubsectionHeader, { title: group.label }), _jsx("div", { className: "bg-popover divide-border divide-y rounded-md border", children: group.keys.map((key) => (_jsx(PermissionRuleRow, { label: key, rule: obj[key], onChange: (next) => setKey(key, next) }, key))) })] }, group.label))), _jsxs("section", { className: "space-y-3", children: [_jsx(SettingsSubsectionHeader, { title: PERMISSION_ACTION_ONLY_GROUP_LABEL }), _jsx("div", { className: "bg-popover divide-border divide-y rounded-md border", children: PERMISSION_ACTION_ONLY_KEYS.map((key) => (_jsxs("div", { className: "flex items-center justify-between gap-3 px-4 py-3", children: [_jsx(PermissionKeyName, { permKey: key }), _jsx(ActionSelect, { value: typeof obj[key] === 'string' ? obj[key] : undefined, onChange: (v) => setKey(key, v), inheritLabel: tI18nComplete.raw('text3f72f0385768'), label: PERMISSION_KEY_LABEL[key] ?? key })] }, key))) })] })] }));
|
|
117
120
|
}
|
|
@@ -14,6 +14,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
|
|
|
14
14
|
import { Field, FieldDescription, FieldLabel } from '../../../primitives/field.js';
|
|
15
15
|
import Hint from '../../../primitives/hint.js';
|
|
16
16
|
import { HoverCard, HoverCardContent, HoverCardTrigger } from '../../../primitives/hover-card.js';
|
|
17
|
+
import { Alert, AlertDescription, AlertTitle } from '../../../primitives/alert.js';
|
|
17
18
|
import { InfoBanner } from '../../../primitives/info-banner.js';
|
|
18
19
|
import { Input } from '../../../primitives/input.js';
|
|
19
20
|
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupSearch, InputGroupSearchClear, InputGroupSearchIcon, InputGroupSearchInput, } from '../../../primitives/input-group.js';
|
|
@@ -666,7 +667,7 @@ function SecretDialog({ open, onOpenChange, projectId, row, connectors, connecto
|
|
|
666
667
|
/* Read-only, because another flow assigned it. Same treatment
|
|
667
668
|
the git-connection secret always had, now covering the LLM
|
|
668
669
|
gateway and connector rows it was always true of. */
|
|
669
|
-
_jsxs("div", { id: "secret-dialog-delivery", className: "border-border bg-sidebar rounded-md border p-3", children: [_jsx(Badge, { variant: selectedDelivery.tone, size: "sm", children: selectedDelivery.label }), _jsxs("p", { className: "text-muted-foreground mt-2 text-xs text-pretty", children: [selectedDelivery.description, " ", tI18nComplete.raw('text5740535823f9')] })] })) : (_jsxs(Select, { value: exposure, onValueChange: (next) => setPickedExposure(next), disabled: save.isPending, children: [_jsx(SelectTrigger, { id: "secret-dialog-delivery", className: "min-h-10 w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: exposureOptions.map((option) => (_jsx(SelectItem, { value: option.exposure, description: option.description, children: option.label }, option.exposure))) })] })), !usageAssigned && (_jsx(FieldDescription, { children: selectedDelivery.description }))] }), strategy === 'runtime' && (
|
|
670
|
+
_jsxs("div", { id: "secret-dialog-delivery", className: "border-border bg-sidebar rounded-md border p-3", children: [_jsx(Badge, { variant: selectedDelivery.tone, size: "sm", children: selectedDelivery.label }), _jsxs("p", { className: "text-muted-foreground mt-2 text-xs text-pretty", children: [selectedDelivery.description, " ", tI18nComplete.raw('text5740535823f9')] })] })) : (_jsxs(Select, { value: exposure, onValueChange: (next) => setPickedExposure(next), disabled: save.isPending, children: [_jsx(SelectTrigger, { id: "secret-dialog-delivery", className: "min-h-10 w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: exposureOptions.map((option) => (_jsx(SelectItem, { value: option.exposure, description: option.description, children: option.label }, option.exposure))) })] })), !usageAssigned && (_jsx(FieldDescription, { children: selectedDelivery.description }))] }), strategy === 'runtime' && (_jsxs(Alert, { variant: "warning", children: [_jsx(AlertTitle, { children: tI18nComplete.raw('text4fb8319405f3') }), _jsx(AlertDescription, { children: tI18nComplete.raw('textdb71b63b5778') })] })), grantNotice && (_jsxs(InfoBanner, { tone: "warning", icon: _jsx(DangerTriangleSolid, { weight: "fill" }), title: grantNotice.title, className: "[&_[data-slot=alert-content]]:min-w-0", children: [_jsx("span", { className: "block text-pretty", children: grantNotice.body }), grantPlan.candidates.length > 0 && (_jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [grantPlan.candidates.length > 1 && (_jsxs(Select, { value: selectedGrantAgent ?? '', onValueChange: setGrantAgent, disabled: grant.isPending, children: [_jsx(SelectTrigger, { "aria-label": tI18nComplete.raw('text33e745179bcb'), className: "h-8 w-48", children: _jsx(SelectValue, { placeholder: tI18nComplete.raw('textb6890bc23a9c') }) }), _jsx(SelectContent, { children: grantPlan.candidates.map((candidate) => (_jsx(SelectItem, { value: candidate.name, description: agentGrantCandidateHint(candidate) ?? undefined, children: candidate.name }, candidate.name))) })] })), _jsxs(Button, { type: "button", size: "sm", onClick: startGrant, disabled: !selectedGrantAgent || grant.isPending, children: [grant.isPending ? _jsx(Loading, { className: "size-3.5 shrink-0" }) : null, agentGrantActionLabel(grantPlan, selectedGrantAgent)] })] })), grantPlan.candidates.length === 0 && (_jsx("span", { className: "text-muted-foreground mt-2 block text-xs text-pretty", children: tI18nComplete.raw('textf23c70160b5b') })), selectedGrantHint && (_jsx("span", { className: "text-muted-foreground mt-2 block text-xs text-pretty", children: selectedGrantHint })), grant.error && (_jsx("span", { className: "text-kortix-red mt-2 block text-xs text-pretty", children: agentGrantErrorMessage(grant.error) })), _jsx("pre", { className: "border-border bg-muted mt-2 overflow-x-auto rounded-sm border p-2 font-mono text-xs leading-relaxed", children: grantManifest })] })), needsHosts && (_jsxs("div", { className: "border-border bg-sidebar space-y-4 rounded-md border p-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium", children: tI18nComplete.raw('textd3297c00f7a2') }), _jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: tI18nComplete.raw('text76f48924ee10') })] }), _jsxs(InfoBanner, { tone: "neutral", title: echoNotice.title, className: "[&_[data-slot=alert-content]]:min-w-0", children: [_jsx("span", { className: "block text-pretty", children: echoNotice.body }), _jsx("pre", { className: "border-border bg-muted mt-2 overflow-x-auto rounded-sm border p-2 font-mono text-xs leading-relaxed", children: echoNotice.probe }), _jsx(Link, { href: echoNotice.docsHref, target: "_blank", rel: "noreferrer", className: "text-muted-foreground hover:text-foreground mt-2 inline-block text-xs underline underline-offset-2", children: echoNotice.docsLabel })] }), _jsxs(Field, { children: [_jsx(FieldLabel, { htmlFor: "secret-dialog-hosts", children: tI18nComplete.raw('textbba9af131107') }), _jsx(Textarea, { id: "secret-dialog-hosts", value: hosts, onChange: (event) => setEditedHosts(event.target.value), placeholder: tI18nComplete.raw('text07de8e6e567f'), minHeight: 56, maxHeight: 112, variant: "outline", className: "font-mono text-xs", disabled: save.isPending }), _jsx(FieldDescription, { children: tI18nComplete.raw('text80befc2e0620') })] }), legacyDetail && (_jsxs("div", { className: "border-border bg-popover space-y-2 rounded-md border p-3", children: [_jsx("p", { className: "text-sm font-medium", children: legacyDetail.title }), _jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: legacyDetail.body }), _jsx("dl", { className: "text-muted-foreground space-y-0.5 font-mono text-xs", children: legacyDetail.lines.map((line) => (_jsx("dd", { children: line }, line))) }), _jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => setLegacyInject(null), disabled: save.isPending, children: tI18nComplete.raw('text4a72652fb7e7') })] }))] })), row?.consumer === 'connector' && (_jsx("div", { className: "border-border bg-sidebar space-y-4 rounded-md border p-3", children: _jsxs(Field, { children: [_jsx(FieldLabel, { children: tI18nComplete.raw('textc3d2e79ebdd0') }), connectorsLoading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-12 rounded-md" }), _jsx(Skeleton, { className: "h-12 rounded-md" })] })) : connectorOptions.length === 0 ? (_jsx(InfoBanner, { tone: "neutral", title: tI18nComplete.raw('text10798ef769fd'), children: tI18nComplete.raw('text0b834e60371f') })) : (_jsx("div", { className: "bg-popover overflow-hidden rounded-md border", children: connectorOptions.map((option, index) => (_jsxs("label", { className: cn('flex min-h-12 items-center gap-3 px-3 py-2', index > 0 && 'border-t', option.disabled ? 'cursor-not-allowed opacity-60' : 'cursor-pointer'), children: [_jsx(Checkbox, { checked: effectiveSelectedConnectorSlugSet.has(option.slug), disabled: option.disabled || save.isPending, onCheckedChange: (checked) => {
|
|
670
671
|
setSelectedConnectorSlugs((current) => checked
|
|
671
672
|
? [
|
|
672
673
|
...new Set([
|
|
@@ -34,7 +34,7 @@ export interface GeneralTabViewProps {
|
|
|
34
34
|
* `useQuery`/mutations, so it can't render under `renderToStaticMarkup`
|
|
35
35
|
* with no providers. */
|
|
36
36
|
/** Whether the Delete-workspace section shows at all — gated on
|
|
37
|
-
* `project.delete`, NOT the broader `project.write` gate
|
|
37
|
+
* `project.delete`, NOT the broader `project.settings.write` gate
|
|
38
38
|
* `generalFieldsSlot`'s fields use. Deleting and editing are separate
|
|
39
39
|
* permissions, so a custom role can grant one without the other. */
|
|
40
40
|
canDelete?: boolean;
|
|
@@ -44,6 +44,13 @@ export interface GeneralTabViewProps {
|
|
|
44
44
|
onCloseArchiveDialog?: () => void;
|
|
45
45
|
onConfirmArchive?: () => void;
|
|
46
46
|
isArchivePending?: boolean;
|
|
47
|
+
/** `TransferWorkspaceEntry` — the second danger-zone row and its dialog.
|
|
48
|
+
* A slot for the same reason the others are: the dialog owns its own
|
|
49
|
+
* accounts query and mutation, so it cannot render under
|
|
50
|
+
* `renderToStaticMarkup` with no providers. Shares the Delete section's
|
|
51
|
+
* `canDelete` gate — the API's source gate for a transfer is the same
|
|
52
|
+
* destructive tier that gates delete. */
|
|
53
|
+
transferSlot?: ReactNode;
|
|
47
54
|
}
|
|
48
55
|
export interface GeneralTabCopy {
|
|
49
56
|
loadFailed: string;
|
|
@@ -64,7 +71,7 @@ export interface GeneralTabCopy {
|
|
|
64
71
|
* `ProfileTabView`/`ConnectedAccountsTabView` for the same split. Every
|
|
65
72
|
* prop is optional with a safe default so the bare `<GeneralTabView />`
|
|
66
73
|
* the test file renders shows the Delete-workspace section fully formed. */
|
|
67
|
-
export declare function GeneralTabView({ copy, isLoading, isError, errorMessage, onRetry, generalFieldsSlot, canDelete, workspaceName, archiveOpen, onOpenArchiveDialog, onCloseArchiveDialog, onConfirmArchive, isArchivePending, }: GeneralTabViewProps): import("react").JSX.Element;
|
|
74
|
+
export declare function GeneralTabView({ copy, isLoading, isError, errorMessage, onRetry, generalFieldsSlot, canDelete, workspaceName, archiveOpen, onOpenArchiveDialog, onCloseArchiveDialog, onConfirmArchive, isArchivePending, transferSlot, }: GeneralTabViewProps): import("react").JSX.Element;
|
|
68
75
|
export interface RunProjectArchiveClient {
|
|
69
76
|
archiveProject: (projectId: string) => Promise<unknown>;
|
|
70
77
|
}
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { Button } from '../../../primitives/button.js';
|
|
5
5
|
import { Input } from '../../../primitives/input.js';
|
|
6
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../primitives/select.js';
|
|
6
7
|
import { SettingsRow, SettingsRowGroup } from '../../../primitives/settings-row.js';
|
|
7
8
|
import { SettingsSubsectionHeader } from '../../../primitives/settings-subsection-header.js';
|
|
8
9
|
import { Skeleton } from '../../../primitives/skeleton.js';
|
|
@@ -19,17 +20,30 @@ import { forgetLastProjectId } from '../../../internal/lib/onboarding/last-proje
|
|
|
19
20
|
import { PROJECT_ACTIONS } from '../../../internal/lib/project-actions.js';
|
|
20
21
|
import { useProjectCans } from '../../../internal/lib/use-project-can.js';
|
|
21
22
|
import { useSettingsPanelStore } from '../../../internal/stores/settings-panel-store.js';
|
|
22
|
-
import {
|
|
23
|
+
import { TransferWorkspaceEntry } from './transfer-workspace-dialog.js';
|
|
24
|
+
import { archiveProject, getProject, setDefaultReasoningEffort, updateProject, } from '@kortix/sdk';
|
|
23
25
|
import { contract, invalidateProjectIdentity, qk } from '@kortix/sdk/react';
|
|
24
26
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
25
27
|
import { useUiRouter, useUiViewerId } from '../../../providers/ui-provider.js';
|
|
26
28
|
import { SettingsTabHeader } from '../settings-tab-header.js';
|
|
27
|
-
/** Asked for in ONE batched probe. `project.delete` and `project.write` are
|
|
29
|
+
/** Asked for in ONE batched probe. `project.delete` and `project.settings.write` are
|
|
28
30
|
* separate permissions — see `ProjectSettingsGeneralProps.canDelete`. */
|
|
29
31
|
const GENERAL_TAB_ACTIONS = [
|
|
30
|
-
PROJECT_ACTIONS.
|
|
32
|
+
PROJECT_ACTIONS.PROJECT_SETTINGS_WRITE,
|
|
31
33
|
PROJECT_ACTIONS.PROJECT_DELETE,
|
|
32
34
|
];
|
|
35
|
+
/** The effort ladder the default-effort picker offers. These are models.dev
|
|
36
|
+
* variant ids — technical values, shown capitalized like the composer's
|
|
37
|
+
* own effort selector does (its `label`), never translated.
|
|
38
|
+
*
|
|
39
|
+
* The API clamps the stored default at delivery to what the session's model
|
|
40
|
+
* actually publishes (`effortVariantForPrompt`), so a pick the session's
|
|
41
|
+
* model does not carry degrades to Automatic rather than breaking the turn;
|
|
42
|
+
* the picker still offers the superset the catalog carries. */
|
|
43
|
+
const DEFAULT_EFFORT_OPTIONS = ['none', 'low', 'medium', 'high', 'xhigh', 'max'];
|
|
44
|
+
const DEFAULT_EFFORT_AUTOMATIC = '';
|
|
45
|
+
/** `medium` → `Medium` — same casing rule as the composer's effort selector. */
|
|
46
|
+
const effortOptionLabel = (value) => value.charAt(0).toUpperCase() + value.slice(1);
|
|
33
47
|
export const DELETE_WORKSPACE_CONSEQUENCES = [
|
|
34
48
|
'Every session in this workspace, with its files, history, and outputs',
|
|
35
49
|
'All scheduled runs and triggers — they stop firing straight away',
|
|
@@ -61,8 +75,8 @@ const DEFAULT_GENERAL_COPY = {
|
|
|
61
75
|
* `ProfileTabView`/`ConnectedAccountsTabView` for the same split. Every
|
|
62
76
|
* prop is optional with a safe default so the bare `<GeneralTabView />`
|
|
63
77
|
* the test file renders shows the Delete-workspace section fully formed. */
|
|
64
|
-
export function GeneralTabView({ copy = DEFAULT_GENERAL_COPY, isLoading = false, isError = false, errorMessage = '', onRetry = () => { }, generalFieldsSlot, canDelete = true, workspaceName = '', archiveOpen = false, onOpenArchiveDialog = () => { }, onCloseArchiveDialog = () => { }, onConfirmArchive = () => { }, isArchivePending = false, }) {
|
|
65
|
-
return (_jsxs("div", { className: "mx-auto w-full max-w-2xl space-y-8", children: [_jsx(SettingsTabHeader, { tab: "general" }), isLoading ? (_jsxs("div", { className: "space-y-5", children: [_jsx(Skeleton, { className: "h-40 rounded-md" }), _jsx(Skeleton, { className: "h-20 rounded-md" })] })) : isError ? (_jsx(ErrorState, { size: "sm", title: copy.loadFailed, description: errorMessage, action: _jsx(Button, { variant: "outline", size: "sm", onClick: onRetry, children: copy.retry }) })) : (_jsxs(_Fragment, { children: [generalFieldsSlot, canDelete ? (_jsxs("section", { className: "space-y-3", children: [_jsx(SettingsSubsectionHeader, { title: copy.dangerZone }),
|
|
78
|
+
export function GeneralTabView({ copy = DEFAULT_GENERAL_COPY, isLoading = false, isError = false, errorMessage = '', onRetry = () => { }, generalFieldsSlot, canDelete = true, workspaceName = '', archiveOpen = false, onOpenArchiveDialog = () => { }, onCloseArchiveDialog = () => { }, onConfirmArchive = () => { }, isArchivePending = false, transferSlot, }) {
|
|
79
|
+
return (_jsxs("div", { className: "mx-auto w-full max-w-2xl space-y-8", children: [_jsx(SettingsTabHeader, { tab: "general" }), isLoading ? (_jsxs("div", { className: "space-y-5", children: [_jsx(Skeleton, { className: "h-40 rounded-md" }), _jsx(Skeleton, { className: "h-20 rounded-md" })] })) : isError ? (_jsx(ErrorState, { size: "sm", title: copy.loadFailed, description: errorMessage, action: _jsx(Button, { variant: "outline", size: "sm", onClick: onRetry, children: copy.retry }) })) : (_jsxs(_Fragment, { children: [generalFieldsSlot, canDelete ? (_jsxs("section", { className: "space-y-3", children: [_jsx(SettingsSubsectionHeader, { title: copy.dangerZone }), _jsxs(SettingsRowGroup, { children: [_jsx(SettingsRow, { label: copy.deleteWorkspace, description: copy.deleteDescription, children: _jsx(Button, { variant: "ghost", size: "sm", className: "text-destructive hover:bg-destructive/10 hover:text-destructive", onClick: onOpenArchiveDialog, children: copy.deleteWorkspace }) }), transferSlot] })] })) : null] })), _jsx(TypeToConfirmDialog, { open: archiveOpen, onOpenChange: (open) => {
|
|
66
80
|
if (!open)
|
|
67
81
|
onCloseArchiveDialog();
|
|
68
82
|
}, title: copy.deleteTitle, description: copy.deleteDialog(workspaceName), consequencesTitle: copy.consequencesTitle, consequences: copy.consequences, reassurance: copy.reassurance,
|
|
@@ -125,7 +139,7 @@ export function withoutProject(data, projectId) {
|
|
|
125
139
|
* `GeneralProjectCard` (name — see this file's header comment for what's
|
|
126
140
|
* byte-identical) and extended with icon editing, reusing `ProjectIconField`
|
|
127
141
|
* / `buildProjectEditPatch` unmodified — see this file's header comment. */
|
|
128
|
-
function GeneralWorkspaceCard({ project, canManage, }) {
|
|
142
|
+
function GeneralWorkspaceCard({ project, canManage, canManageEffort, }) {
|
|
129
143
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
130
144
|
const t = useTranslations('settings.workspace');
|
|
131
145
|
const queryClient = useQueryClient();
|
|
@@ -157,6 +171,13 @@ function GeneralWorkspaceCard({ project, canManage, }) {
|
|
|
157
171
|
onSettled: () => renameOnSettled(queryClient, project.project_id),
|
|
158
172
|
});
|
|
159
173
|
const { mutate: mutateName, isPending: isRenamePending } = renameMutation;
|
|
174
|
+
const effortMutation = useMutation({
|
|
175
|
+
mutationFn: (effort) => setDefaultReasoningEffort(project.project_id, effort),
|
|
176
|
+
onSuccess: (updated) => {
|
|
177
|
+
queryClient.setQueryData(qk.project.summary(project.project_id), updated);
|
|
178
|
+
},
|
|
179
|
+
onError: (error) => errorToast(error.message || t('updateFailed')),
|
|
180
|
+
});
|
|
160
181
|
useEffect(() => {
|
|
161
182
|
if (!canManage || isRenamePending)
|
|
162
183
|
return;
|
|
@@ -215,7 +236,7 @@ function GeneralWorkspaceCard({ project, canManage, }) {
|
|
|
215
236
|
// Not `variant="popover"` any more: the group it now sits in is
|
|
216
237
|
// itself `bg-popover`, so a popover-tinted input would vanish into
|
|
217
238
|
// it. The default `bg-input` is what makes it read as a control.
|
|
218
|
-
className: "h-8 w-56" })] })] }));
|
|
239
|
+
className: "h-8 w-56" })] }), _jsx(SettingsRow, { label: t('defaultEffort'), description: t('defaultEffortDescription'), children: _jsxs(Select, { value: project.default_reasoning_effort ?? DEFAULT_EFFORT_AUTOMATIC, onValueChange: (v) => effortMutation.mutate(v === DEFAULT_EFFORT_AUTOMATIC ? null : v), disabled: !canManageEffort || effortMutation.isPending, children: [_jsx(SelectTrigger, { "aria-label": t('defaultEffort'), className: "h-8 w-40 shrink-0", children: _jsx(SelectValue, { placeholder: t('defaultEffortAutomatic') }) }), _jsxs(SelectContent, { align: "end", children: [_jsx(SelectItem, { value: DEFAULT_EFFORT_AUTOMATIC, children: t('defaultEffortAutomatic') }), DEFAULT_EFFORT_OPTIONS.map((effort) => (_jsx(SelectItem, { value: effort, children: effortOptionLabel(effort) }, effort)))] })] }) })] }));
|
|
219
240
|
}
|
|
220
241
|
/** Container: owns every hook (React Query, IAM probe, archive dialog state)
|
|
221
242
|
* and renders `GeneralTabView` with real data + slots. Only ever mounted
|
|
@@ -235,12 +256,13 @@ export function GeneralTab({ projectId }) {
|
|
|
235
256
|
});
|
|
236
257
|
const project = projectQuery.data;
|
|
237
258
|
// Two DIFFERENT permissions, asked for separately. `project.delete` gates the
|
|
238
|
-
// Delete-workspace section; `project.write` gates the fields. Reading a
|
|
259
|
+
// Delete-workspace section; `project.settings.write` gates the fields. Reading a
|
|
239
260
|
// `manager` role label instead would have hidden Delete from a custom role
|
|
240
261
|
// that holds `project.delete`, and shown it to one that does not.
|
|
241
262
|
const caps = useProjectCans(projectId, GENERAL_TAB_ACTIONS);
|
|
242
263
|
const canDelete = caps[PROJECT_ACTIONS.PROJECT_DELETE]?.allowed === true;
|
|
243
|
-
const canEdit = caps[PROJECT_ACTIONS.
|
|
264
|
+
const canEdit = caps[PROJECT_ACTIONS.PROJECT_SETTINGS_WRITE]?.allowed === true;
|
|
265
|
+
const canEditEffort = canEdit;
|
|
244
266
|
const archiveMutation = useMutation({
|
|
245
267
|
mutationFn: () => runProjectArchive(projectId, { archiveProject },
|
|
246
268
|
// The archived project must stop being where `/` and the settings
|
|
@@ -283,8 +305,8 @@ export function GeneralTab({ projectId }) {
|
|
|
283
305
|
],
|
|
284
306
|
reassurance: t('reassurance'),
|
|
285
307
|
keepWorkspace: t('keepWorkspace'),
|
|
286
|
-
}, isLoading: projectQuery.isLoading, isError: projectQuery.isError, errorMessage: projectQuery.error?.message ?? '', onRetry: () => projectQuery.refetch(), generalFieldsSlot: project ? _jsx(GeneralWorkspaceCard, { project: project, canManage: canEdit }) : undefined,
|
|
308
|
+
}, isLoading: projectQuery.isLoading, isError: projectQuery.isError, errorMessage: projectQuery.error?.message ?? '', onRetry: () => projectQuery.refetch(), generalFieldsSlot: project ? _jsx(GeneralWorkspaceCard, { project: project, canManage: canEdit, canManageEffort: canEditEffort }) : undefined,
|
|
287
309
|
// No git-repo slot: Git repo is its own Settings section since
|
|
288
310
|
// 2026-09-03 (`project-settings-sections.ts`).
|
|
289
|
-
canDelete: canDelete, workspaceName: project?.name, archiveOpen: archiveOpen, onOpenArchiveDialog: () => setArchiveOpen(true), onCloseArchiveDialog: () => setArchiveOpen(false), onConfirmArchive: () => archiveMutation.mutate(), isArchivePending: archiveMutation.isPending }));
|
|
311
|
+
canDelete: canDelete, workspaceName: project?.name, archiveOpen: archiveOpen, onOpenArchiveDialog: () => setArchiveOpen(true), onCloseArchiveDialog: () => setArchiveOpen(false), onConfirmArchive: () => archiveMutation.mutate(), isArchivePending: archiveMutation.isPending, transferSlot: _jsx(TransferWorkspaceEntry, { projectId: projectId, currentAccountId: project?.account_id }) }));
|
|
290
312
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Transfer-workspace entry point — the settings row and its dialog.
|
|
5
|
+
*
|
|
6
|
+
* The API (POST /v1/projects/:id/transfer) refuses a caller who holds the
|
|
7
|
+
* destructive tier on the project but no rights on the TARGET organization,
|
|
8
|
+
* and answers with the target's project cap when the move would exceed its
|
|
9
|
+
* plan — so this dialog only has to pick a target and say plainly what
|
|
10
|
+
* moves: sessions, files, settings and member grants follow the project;
|
|
11
|
+
* the usage ledger stays with the organization that consumed it.
|
|
12
|
+
*
|
|
13
|
+
* The project may land in an organization the mover cannot see afterwards
|
|
14
|
+
* (they are not a member there) — the same outcome the Delete flow produces,
|
|
15
|
+
* so success leaves the project the same way: forget the remembered landing
|
|
16
|
+
* target, close the settings overlay, replace into the landing door.
|
|
17
|
+
*/
|
|
18
|
+
import { useMemo, useState } from 'react';
|
|
19
|
+
import { Button } from '../../../primitives/button.js';
|
|
20
|
+
import { ConfirmDialog } from '../../../primitives/confirm-dialog.js';
|
|
21
|
+
import { SettingsRow } from '../../../primitives/settings-row.js';
|
|
22
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../../primitives/select.js';
|
|
23
|
+
import { errorToast, successToast } from '../../../primitives/toast.js';
|
|
24
|
+
import { useSettingsPanelStore } from '../../../internal/stores/settings-panel-store.js';
|
|
25
|
+
import { useUiRouter, useUiViewerId } from '../../../providers/ui-provider.js';
|
|
26
|
+
import { useAccountsList } from '../../../internal/hooks/account/use-accounts-list.js';
|
|
27
|
+
import { PROJECT_LANDING_PATH } from '../../../internal/lib/onboarding/landing-destination.js';
|
|
28
|
+
import { forgetLastProjectId } from '../../../internal/lib/onboarding/last-project-cookie.js';
|
|
29
|
+
import { transferProject } from '@kortix/sdk';
|
|
30
|
+
import { qk } from '@kortix/sdk/react';
|
|
31
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
32
|
+
import { useTranslations } from '../../../i18n/index.js';
|
|
33
|
+
export function TransferWorkspaceEntry({ projectId, currentAccountId, }) {
|
|
34
|
+
const t = useTranslations('settings.workspace');
|
|
35
|
+
const [open, setOpen] = useState(false);
|
|
36
|
+
return (_jsxs(_Fragment, { children: [_jsx(SettingsRow, { label: t('transferWorkspace'), description: t('transferDescription'), children: _jsx(Button, { variant: "ghost", size: "sm", className: "text-destructive hover:bg-destructive/10 hover:text-destructive", onClick: () => setOpen(true), children: t('transferWorkspace') }) }), _jsx(TransferWorkspaceDialog, { projectId: projectId, currentAccountId: currentAccountId, open: open, onOpenChange: setOpen })] }));
|
|
37
|
+
}
|
|
38
|
+
function TransferWorkspaceDialog({ projectId, currentAccountId, open, onOpenChange, }) {
|
|
39
|
+
const t = useTranslations('settings.workspace');
|
|
40
|
+
const queryClient = useQueryClient();
|
|
41
|
+
const router = useUiRouter();
|
|
42
|
+
const viewerId = useUiViewerId();
|
|
43
|
+
const [targetId, setTargetId] = useState('');
|
|
44
|
+
// Same freshness contract as every other account-list reader: fetch only
|
|
45
|
+
// while the dialog is open.
|
|
46
|
+
const accountsQuery = useAccountsList({ enabled: open });
|
|
47
|
+
// The target cannot be the account the project already lives in — the API
|
|
48
|
+
// refuses that anyway — and a stale `currentAccountId` (project query still
|
|
49
|
+
// in flight) is harmless: the API re-checks.
|
|
50
|
+
const targetOptions = useMemo(() => (accountsQuery.data ?? []).filter((account) => account.account_id !== currentAccountId), [accountsQuery.data, currentAccountId]);
|
|
51
|
+
const transferMutation = useMutation({
|
|
52
|
+
mutationFn: () => transferProject(projectId, targetId),
|
|
53
|
+
onSuccess: () => {
|
|
54
|
+
successToast(t('transferSuccess'));
|
|
55
|
+
// Same leave-the-project flow as Delete: the moved project must stop
|
|
56
|
+
// being the remembered landing target, the global overlay must close
|
|
57
|
+
// before the navigation lands, and Back must not return to a project
|
|
58
|
+
// the viewer may no longer see.
|
|
59
|
+
forgetLastProjectId(viewerId, projectId);
|
|
60
|
+
useSettingsPanelStore.getState().close();
|
|
61
|
+
// qk.projects.scope(): lists across every account plus the accountless
|
|
62
|
+
// slot — the project just changed accounts, so every list form is
|
|
63
|
+
// stale at once. The moved project's own caches are unreachable after
|
|
64
|
+
// the replace below (the old id's entries gcTime out).
|
|
65
|
+
queryClient.invalidateQueries({ queryKey: qk.projects.scope() });
|
|
66
|
+
onOpenChange(false);
|
|
67
|
+
router.replace(PROJECT_LANDING_PATH);
|
|
68
|
+
},
|
|
69
|
+
onError: (error) => errorToast(error.message || t('transferFailed')),
|
|
70
|
+
});
|
|
71
|
+
const targetName = targetOptions.find((account) => account.account_id === targetId)?.name;
|
|
72
|
+
const changeOpen = (next) => {
|
|
73
|
+
if (transferMutation.isPending)
|
|
74
|
+
return;
|
|
75
|
+
if (!next) {
|
|
76
|
+
setTargetId('');
|
|
77
|
+
transferMutation.reset();
|
|
78
|
+
}
|
|
79
|
+
onOpenChange(next);
|
|
80
|
+
};
|
|
81
|
+
return (_jsx(ConfirmDialog, { open: open, onOpenChange: changeOpen, title: t('transferTitle'), description: _jsxs("div", { className: "space-y-4", children: [_jsx("p", { children: t('transferDialog') }), accountsQuery.isLoading ? (_jsx("p", { children: t('transferLoadingTargets') })) : accountsQuery.isError ? (_jsx(Button, { variant: "outline", onClick: () => accountsQuery.refetch(), children: t('retry') })) : targetOptions.length === 0 ? (_jsx("p", { children: t('transferNoTargets') })) : (_jsxs(Select, { value: targetId, onValueChange: setTargetId, children: [_jsx(SelectTrigger, { className: "w-full", "aria-label": t('transferTargetLabel'), children: _jsx(SelectValue, { placeholder: t('transferTargetPlaceholder') }) }), _jsx(SelectContent, { children: targetOptions.map((account) => (_jsx(SelectItem, { value: account.account_id, children: account.name }, account.account_id))) })] }))] }), cancelLabel: t('keepWorkspace'), confirmLabel: targetName ? t('transferMoveTo', { name: targetName }) : t('transferMove'), confirmVariant: "destructive", confirmDisabled: !targetName || accountsQuery.isError, isPending: transferMutation.isPending, onConfirm: () => transferMutation.mutate() }));
|
|
82
|
+
}
|
|
@@ -30,7 +30,10 @@ export function RichRowBody({ icon: Glyph, title, description, }) {
|
|
|
30
30
|
* A tab with one common case that needs no form leads with it (`quick`):
|
|
31
31
|
* Connectors → "MCP server" (KRTX-2185).
|
|
32
32
|
*/
|
|
33
|
-
export function NewEntityMenu({ label = 'New',
|
|
33
|
+
export function NewEntityMenu({ label = 'New',
|
|
34
|
+
// `default` is `h-9`, the height of the `size="sm"` search input every
|
|
35
|
+
// Customize header puts beside it. `sm` (`h-8`) left the pair 4px apart.
|
|
36
|
+
size = 'default', variant = 'secondary', caret = true, pending = false, onChat, manual, quick, }) {
|
|
34
37
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
35
38
|
if (!manual) {
|
|
36
39
|
return (_jsxs(Button, { variant: variant, size: size, className: "gap-1.5", disabled: pending, onClick: onChat, children: [pending ? _jsx(Loading, { className: "size-4 shrink-0" }) : _jsx(PlusIcon, { className: "size-4" }), label] }));
|
|
@@ -96,10 +96,9 @@ export function SkillsPage({ projectId }) {
|
|
|
96
96
|
// One control, two labels. The header has a title beside it and can be terse;
|
|
97
97
|
// the empty state is the whole screen and has to name what it creates. Both
|
|
98
98
|
// offer the same two ways in, so they cannot drift apart.
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
const createButton = (label) => canWrite ? (_jsx(NewEntityMenu, { label: label, pending: configure.pending, onChat: () => configure.start(newConfigPrompt('skill')), manual: {
|
|
99
|
+
// The header button is `h-9`, the height of the `size="sm"` search input
|
|
100
|
+
// beside it. The empty state keeps `sm` to match its `sm` docs link.
|
|
101
|
+
const createButton = (label, size) => canWrite ? (_jsx(NewEntityMenu, { label: label, size: size, pending: configure.pending, onChat: () => configure.start(newConfigPrompt('skill')), manual: {
|
|
103
102
|
label: tI18nComplete.raw('texta38668224f1a'),
|
|
104
103
|
description: tI18nComplete.raw('textedac6130dac7'),
|
|
105
104
|
onSelect: () => setFormOpen(true),
|
|
@@ -108,7 +107,7 @@ export function SkillsPage({ projectId }) {
|
|
|
108
107
|
// The copy invites an action, so the action is here — not only in
|
|
109
108
|
// the header. Docs stays as the secondary, for the reader who has
|
|
110
109
|
// no write permission and gets no primary at all.
|
|
111
|
-
action: createButton('Create a skill'), secondaryAction: _jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "gap-1.5", children: _jsx("a", { href: "
|
|
110
|
+
action: createButton('Create a skill', 'sm'), secondaryAction: _jsx(Button, { asChild: true, variant: "ghost", size: "sm", className: "gap-1.5", children: _jsx("a", { href: "/docs/project/agents#skills", target: "_blank", rel: "noopener noreferrer", children: tI18nComplete.raw('text7af023c43013') }) }) })), children: filtered.map((skill) => (_jsx(CatalogCard, { title: skill.name, description: skill.description, onClick: () => setSelectedPath(skill.path) }, skill.path))) }), _jsx(EntityDetailModal, { projectId: projectId, entity: detail.record, kind: "skill", removable: true, open: detail.open, isResolving: detail.isResolving, onOpenChange: (next) => {
|
|
112
111
|
if (!next)
|
|
113
112
|
setSelectedPath(null);
|
|
114
113
|
} }), _jsx(NewSkillModal, { projectId: projectId, open: formOpen, onOpenChange: setFormOpen })] }));
|
|
@@ -28,9 +28,5 @@ export function ThenFields({ agents, draft, patch, payloadSchema, error, }) {
|
|
|
28
28
|
el?.setSelectionRange(at + insert.length, at + insert.length);
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
// up with every other field. The selector's own button fills it, label left,
|
|
33
|
-
// caret right, like a Select trigger.
|
|
34
|
-
const panel = 'bg-popover border-border flex h-9 w-full items-center rounded-md border px-0.5 [&_button]:h-8 [&_button]:w-full [&_button]:justify-between';
|
|
35
|
-
return (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Textarea, { value: draft.instruction, ref: promptRef, onChange: (e) => patch({ instruction: e.target.value }), "aria-label": tI18nComplete.raw('text112f3ccb1b36'), "aria-invalid": error ? true : undefined, placeholder: tI18nComplete.raw('text2438ee64fbf9'), rows: 3, className: "leading-relaxed" }), _jsx(InlineError, { message: error }), draft.kind === 'event' && draft.eventType ? (_jsx(PromptVariableHints, { payloadSchema: payloadSchema, onInsert: insertVariable })) : (_jsx("p", { className: "text-muted-foreground text-xs leading-relaxed text-pretty", children: tI18nComplete.raw('text03956d4b33dc') }))] }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { className: "text-xs", children: tI18nComplete.raw('text11b39c93777e') }), _jsx("div", { className: panel, children: _jsx(AgentSelector, { agents: agents, selectedAgent: draft.agent, triggerLabelClassName: "max-w-none", onSelect: (agent) => patch({ agent }) }) })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { className: "text-xs", children: tI18nComplete.raw('text5e2c614c23f0') }), _jsx("div", { className: panel, children: _jsx(ModelSelector, { models: models, providers: providers, selectedModel: draft.model, unsetLabel: tI18nComplete.raw('text57069bbd0d2e'), triggerLabelClassName: "max-w-none", onSelect: (model) => patch({ model }) }) })] })] })] }));
|
|
31
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Textarea, { value: draft.instruction, ref: promptRef, onChange: (e) => patch({ instruction: e.target.value }), "aria-label": tI18nComplete.raw('text112f3ccb1b36'), "aria-invalid": error ? true : undefined, placeholder: tI18nComplete.raw('text2438ee64fbf9'), rows: 3, className: "leading-relaxed" }), _jsx(InlineError, { message: error }), draft.kind === 'event' && draft.eventType ? (_jsx(PromptVariableHints, { payloadSchema: payloadSchema, onInsert: insertVariable })) : (_jsx("p", { className: "text-muted-foreground text-xs leading-relaxed text-pretty", children: tI18nComplete.raw('text03956d4b33dc') }))] }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-2", children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { className: "text-xs", children: tI18nComplete.raw('text11b39c93777e') }), _jsx(AgentSelector, { agents: agents, selectedAgent: draft.agent, appearance: "field", onSelect: (agent) => patch({ agent }) })] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Label, { className: "text-xs", children: tI18nComplete.raw('text5e2c614c23f0') }), _jsx(ModelSelector, { models: models, providers: providers, selectedModel: draft.model, unsetLabel: tI18nComplete.raw('text57069bbd0d2e'), appearance: "field", onSelect: (model) => patch({ model }) })] })] })] }));
|
|
36
32
|
}
|