@kortix/ui 0.14.5 → 0.14.7
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 +489 -381
- package/dist/access/access/access-dialog.js +8 -5
- package/dist/access/access/copy-row.js +2 -2
- package/dist/access/sharing-picker.js +2 -1
- package/dist/browser/app-in-browser.js +5 -3
- package/dist/browser/browser-panel.js +6 -6
- package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
- package/dist/browser/sandbox-browser-chrome.js +4 -3
- package/dist/customize/agents/agent-access.d.ts +20 -0
- package/dist/customize/agents/agent-access.js +17 -0
- package/dist/customize/agents/agent-authority-card.js +1 -2
- 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 +73 -76
- package/dist/customize/agents/agent-nav.prototype.d.ts +35 -0
- package/dist/customize/agents/agent-nav.prototype.js +95 -0
- package/dist/customize/agents/agent-page.js +59 -23
- 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 +18 -1
- package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
- 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/connector-routes.d.ts +3 -1
- package/dist/customize/connectors/connector-routes.js +18 -0
- package/dist/customize/connectors/connectors-page.js +23 -4
- package/dist/customize/connectors/detail/app-page.js +19 -5
- package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
- 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/providers/provider-accordion.js +2 -1
- package/dist/customize/providers/provider-connect.js +2 -1
- package/dist/customize/sections/component/telegram-channel-row.js +1 -1
- package/dist/customize/sections/connector-connection-modal.js +11 -9
- package/dist/customize/sections/connectors-view.js +11 -13
- 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/gateway/gateway-routing.js +18 -21
- 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/rail-copy-context.js +5 -3
- 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/sandbox-template-form.js +9 -12
- 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/capability-tabs.js +2 -1
- package/dist/customize/skills/skills-page.js +3 -5
- package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
- package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
- package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
- package/dist/customize/triggers/schedule/when-event.js +1 -1
- package/dist/diff/diff-view.js +9 -10
- package/dist/files/editor/code-editor.js +2 -3
- package/dist/files/project/api/runtime-files.js +3 -2
- package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
- package/dist/files/project/components/change-request-detail-dialog.js +3 -5
- package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
- package/dist/files/project/components/change-request-status-badge.js +27 -0
- package/dist/files/project/components/change-requests-panel.js +1 -1
- package/dist/files/project/components/drive-explorer.js +2 -1
- package/dist/files/project/components/drive-grid-view.js +11 -7
- package/dist/files/project/components/drive-list-view.js +4 -4
- package/dist/files/project/components/file-breadcrumbs.js +1 -1
- package/dist/files/project/components/file-explorer-page.js +1 -1
- package/dist/files/project/components/file-history-popover.js +1 -6
- package/dist/files/project/components/file-search.js +6 -1
- package/dist/files/project/components/open-change-request-dialog.js +2 -1
- package/dist/files/project/components/version-selector-logic.d.ts +11 -0
- package/dist/files/project/components/version-selector-logic.js +26 -0
- package/dist/files/project/components/version-selector.js +11 -20
- package/dist/files/project/file-source.js +18 -1
- package/dist/files/project/hooks/use-file-content.js +2 -0
- package/dist/files/project/hooks/use-server-health.js +17 -15
- package/dist/files/renderers/docx/docx-viewer.js +0 -5
- package/dist/files/renderers/image-renderer.js +6 -24
- package/dist/files/renderers/pdf/pdf-viewer.js +1 -1
- package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
- package/dist/files/renderers/show-content-renderer.js +1 -1
- package/dist/files/renderers/sqlite-renderer.js +8 -3
- package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
- package/dist/files/tree/components/file-tree-item.js +1 -1
- 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 +13 -3
- package/dist/files/viewer/file-source.d.ts +3 -1
- package/dist/files/viewer/use-file-content-state.js +27 -8
- package/dist/files/viewer/viewer-actions.js +2 -2
- package/dist/i18n/en.d.ts +355 -12
- package/dist/i18n/en.js +360 -17
- package/dist/internal/desktop/desktop-back-button.js +5 -3
- 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/hooks/use-auto-scroll.js +5 -3
- package/dist/internal/lib/query-client-singleton.d.ts +9 -3
- package/dist/internal/lib/query-client-singleton.js +18 -12
- package/dist/internal/notifications/notification-rows.js +2 -1
- package/dist/internal/outcomes/outcome-types.d.ts +5 -0
- 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/code/inline-code.js +8 -0
- package/dist/markdown/code/output-paths-context.d.ts +18 -0
- package/dist/markdown/code/output-paths-context.js +35 -0
- package/dist/markdown/genui/components/charts.js +6 -5
- package/dist/primitives/map.js +2 -1
- package/dist/primitives/preview-image.js +4 -2
- package/dist/primitives/settings-section-header.d.ts +1 -1
- package/dist/primitives/textarea.js +1 -1
- package/dist/primitives/typed-title.js +12 -14
- package/dist/primitives/typing-animation.js +4 -2
- package/dist/session/composer/agent-selector.js +6 -1
- 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-chat-input.js +5 -3
- 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/composer-logic.js +8 -7
- 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 +3 -6
- package/dist/session/composer/context-usage.js +3 -6
- package/dist/session/composer/draft/composer-draft.js +4 -4
- 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/pasted-text.js +3 -2
- 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/stores/queued-draft-store.js +3 -2
- package/dist/session/composer/token-progress.d.ts +1 -1
- package/dist/session/composer/token-progress.js +2 -2
- package/dist/session/header/reminder-parts.d.ts +11 -2
- package/dist/session/header/reminder-parts.js +9 -4
- 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/media/sandbox-url-detector.js +0 -7
- package/dist/session/outcomes/change-request-outcomes.js +24 -3
- package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
- package/dist/session/panel/advanced/advanced-panel.js +3 -7
- package/dist/session/panel/easy/app-preview.js +12 -2
- package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
- package/dist/session/panel/easy/easy-panel-logic.js +1 -1
- package/dist/session/panel/easy/outputs-card.js +2 -1
- package/dist/session/panel/easy/panel-card.js +5 -3
- package/dist/session/panel/easy/preview-load.d.ts +14 -0
- package/dist/session/panel/easy/preview-load.js +15 -0
- package/dist/session/panel/easy/step-detail-body.js +2 -7
- 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/panel/session-panel-provider.js +6 -2
- package/dist/session/panel/shared/use-panel-derivations.js +6 -4
- package/dist/session/panel/use-session-panel-layout.js +7 -5
- package/dist/session/print/session-print-header.js +9 -8
- 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/session-chat.js +15 -19
- package/dist/session/thread/session-history-scroll.d.ts +2 -1
- package/dist/session/thread/session-history.js +3 -1
- package/dist/session/thread/session-thread.js +1 -1
- package/dist/session/thread/transcript.js +13 -7
- package/dist/session/tool/shared/file-list.js +19 -2
- package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
- package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
- package/dist/session/tool/shared/infrastructure-output.js +9 -5
- package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
- package/dist/session/tool/shared/infrastructure-rows.js +7 -5
- package/dist/session/tool/tools/bash-tool.js +10 -6
- package/dist/session/tool/tools/web-search-tool.js +25 -3
- package/dist/session/turn/recovered-failures.d.ts +8 -0
- package/dist/session/turn/recovered-failures.js +32 -0
- package/dist/session/turn/streaming-cadence.js +5 -8
- package/dist/styles.css +1 -1
- package/dist/terminal/pty-connection.d.ts +5 -4
- package/dist/terminal/session-terminal-panel.js +3 -5
- package/dist/theme/theme.js +2 -1
- package/dist/workspace/index.d.ts +1 -0
- package/dist/workspace/index.js +1 -0
- package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
- package/dist/workspace/review/review-center.js +13 -10
- 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 +9 -14
- package/dist/workspace/sessions/deleted-session-row.js +5 -2
- package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
- 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/footer/project-mcp-nav.js +6 -2
- package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
- 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 +5 -8
- package/package.json +4 -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
|
@@ -66,7 +66,7 @@ import { errorToast, successToast } from '../../primitives/toast.js';
|
|
|
66
66
|
import { EmptyState } from '../../primitives/empty-state.js';
|
|
67
67
|
import { ErrorState } from '../../primitives/error-state.js';
|
|
68
68
|
import { configEntitySourcePath } from '../sections/component/config-entity-source-path.js';
|
|
69
|
-
import { AgentConfigSections, agentConfigSectionKeys, agentEditorOptionQueries, DEFAULT_AGENT_CONFIG_SECTION, isAgentConfigSectionKey, registryGrantOptions, useAgentDraft, useAgentEditorOptions, useLocalizedAgentConfigCatalog, } from '../sections/view/agent-editor.js';
|
|
69
|
+
import { AgentConfigSections, agentConfigSectionKeys, agentEditorOptionQueries, DEFAULT_AGENT_CONFIG_SECTION, grantSummary, isAgentConfigSectionKey, registryGrantOptions, useAgentDraft, useAgentEditorOptions, useLocalizedAgentConfigCatalog, } from '../sections/view/agent-editor.js';
|
|
70
70
|
import { formatMode, toArray } from '../shared/utils.js';
|
|
71
71
|
import { editConfigPrompt, useConfigureThread, } from '../use-configure-thread.js';
|
|
72
72
|
import { agentConfigNeedsUpgrade, useAgentConfig, useUpdateAgentConfig, } from '../../internal/hooks/projects/use-agent-config.js';
|
|
@@ -86,11 +86,13 @@ import { FadedScrollArea } from '../../primitives/faded-scroll-area.js';
|
|
|
86
86
|
import { SETTINGS_SIDEBAR_WIDTH_PX } from '../../internal/account-hub/account-settings-shell.js';
|
|
87
87
|
import { capabilityTabHref } from '../../internal/lib/capability-tab-routes.js';
|
|
88
88
|
import { useIsMobile } from '../../internal/hooks/index.js';
|
|
89
|
-
import { EditorSectionStyleProvider } from '../sections/view/agent-editor-primitives.js';
|
|
89
|
+
import { EditorSection, EditorSectionStyleProvider } from '../sections/view/agent-editor-primitives.js';
|
|
90
|
+
import { SettingsSectionHeader } from '../../primitives/settings-section-header.js';
|
|
90
91
|
import { AgentDrivesSection } from './agent-drives-section.js';
|
|
91
92
|
import { AgentAuthorityCard } from './agent-authority-card.js';
|
|
92
93
|
import { AgentModel, AgentScope } from './agent-detail-aside.js';
|
|
93
94
|
import { AppsGrantPage, ConnectorsGrantPage, SecretsGrantPage, SkillsGrantPage, } from './agent-grant-pages.js';
|
|
95
|
+
import { GroupedUnderlineTabs, GroupSwitchTabs, InlineVerticalTabs, PrototypeSwitcher, useNavVariant, } from './agent-nav.prototype.js';
|
|
94
96
|
import { AgentPeopleSection } from './agent-people-section.js';
|
|
95
97
|
import { AgentShareControl } from './agent-share-control.js';
|
|
96
98
|
import { AgentTriggersSection } from './agent-triggers-section.js';
|
|
@@ -162,11 +164,12 @@ export function AgentPage({ projectId, agentName }) {
|
|
|
162
164
|
* the one scroller; the rail is the Settings rail
|
|
163
165
|
* (`project-settings-page.tsx`), row for row.
|
|
164
166
|
*/
|
|
165
|
-
function AgentPageFrame({ header, section, sections, sectionHref, pane, footer, }) {
|
|
167
|
+
function AgentPageFrame({ header, section, sections, sectionHref, pane, footer, summaries, }) {
|
|
166
168
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
167
169
|
const isMobile = useIsMobile();
|
|
168
170
|
const localizedConfig = useLocalizedAgentConfigCatalog();
|
|
169
|
-
const
|
|
171
|
+
const sectionKeys = new Set(sections);
|
|
172
|
+
const items = localizedConfig.sections.filter((s) => sectionKeys.has(s.key));
|
|
170
173
|
// The Preferences rail's rule: a heading over a lone group labels nothing.
|
|
171
174
|
const groups = localizedConfig.groups
|
|
172
175
|
.map((group) => ({
|
|
@@ -183,7 +186,18 @@ function AgentPageFrame({ header, section, sections, sectionHref, pane, footer,
|
|
|
183
186
|
// The Settings rail's row dialect (`project-settings-page.tsx`).
|
|
184
187
|
'gap-2 px-2.5 py-1 font-normal transition-none has-[>svg]:px-2.5', 'text-foreground data-[state=inactive]:text-foreground hover:bg-hover hover:text-foreground', 'data-[state=active]:bg-active data-[state=active]:font-medium', '[&_svg]:text-muted-foreground data-[state=active]:[&_svg]:text-foreground'), children: _jsxs(Link, { href: sectionHref(item.key), prefetch: true, children: [_jsx(SectionIcon, { className: "size-4 shrink-0" }), _jsx("span", { className: cn(!horizontal && 'truncate'), children: item.label })] }) }, item.key));
|
|
185
188
|
};
|
|
186
|
-
|
|
189
|
+
// PROTOTYPE: `?variant=` swaps the rail for one of the candidate navs.
|
|
190
|
+
const variant = useNavVariant();
|
|
191
|
+
const navProps = {
|
|
192
|
+
groups,
|
|
193
|
+
section,
|
|
194
|
+
href: (key) => sectionHref(key),
|
|
195
|
+
summaries,
|
|
196
|
+
};
|
|
197
|
+
if (!isMobile && variant !== 'rail') {
|
|
198
|
+
return (_jsxs("div", { className: "relative flex h-full min-h-0 flex-1 flex-col", children: [_jsx("div", { className: cn('shrink-0 px-5 py-3', variant === 'inline' && 'border-border/60 border-b'), children: header }), variant === 'tabs' ? _jsx(GroupedUnderlineTabs, { ...navProps }) : null, variant === 'groups' ? _jsx(GroupSwitchTabs, { ...navProps }) : null, _jsx("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto", children: variant === 'inline' ? (_jsx(InlineVerticalTabs, { ...navProps, children: pane })) : (_jsx("div", { className: "mx-auto w-full max-w-2xl px-4 py-10 pb-32 lg:py-14 lg:pb-32", children: pane })) }), footer, _jsx(PrototypeSwitcher, {})] }));
|
|
199
|
+
}
|
|
200
|
+
return (_jsxs("div", { className: "relative flex h-full min-h-0 flex-1 flex-col", children: [_jsx("div", { className: "border-border/60 shrink-0 border-b px-5 py-3", children: header }), _jsxs("div", { className: cn('min-h-0 flex-1', isMobile ? 'flex flex-col overflow-hidden' : 'grid overflow-hidden'), style: isMobile ? undefined : { gridTemplateColumns: `${SETTINGS_SIDEBAR_WIDTH_PX}px 1fr` }, children: [isMobile ? (_jsx("nav", { "aria-label": tI18nComplete.raw('text7be318295927'), className: "border-border/60 flex h-auto shrink-0 items-center border-b", children: _jsx(FadedScrollArea, { orientation: "horizontal", fadeColor: "from-background", className: "min-w-0 flex-1 py-2", children: _jsx(Tabs, { value: section, className: "w-fit", children: _jsx(TabsList, { orientation: "horizontal", className: "w-fit", children: items.map((item) => trigger(item, true)) }) }) }) })) : (_jsx("aside", { className: "flex min-h-0 flex-col border-r bg-inherit", children: _jsx("nav", { "aria-label": tI18nComplete.raw('text7be318295927'), className: "flex min-h-0 flex-1 [scrollbar-width:none] flex-col gap-4 overflow-y-auto px-2 pt-3 pb-2 [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden", children: _jsx(Tabs, { value: section, orientation: "vertical", className: "space-y-3", children: groups.map((g) => (_jsxs("div", { children: [showGroupLabels ? (_jsx("div", { className: "text-muted-foreground flex h-7 items-center px-2.5 text-xs font-medium", children: g.group })) : null, _jsx(TabsList, { orientation: "vertical", className: "w-full", children: g.items.map((item) => trigger(item, false)) })] }, g.group))) }) }) })), _jsx("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-y-auto", children: _jsx("div", { className: "mx-auto w-full max-w-2xl px-4 py-10 pb-32 lg:py-14 lg:pb-32", children: pane }) })] }), footer, _jsx(PrototypeSwitcher, {})] }));
|
|
187
201
|
}
|
|
188
202
|
function CenteredState({ children }) {
|
|
189
203
|
return (_jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx("div", { className: "mx-auto w-full max-w-3xl px-6 py-16", children: children }) }));
|
|
@@ -236,7 +250,7 @@ function AgentActions({ projectId, agent, config, canWrite, }) {
|
|
|
236
250
|
: null;
|
|
237
251
|
const makeDefault = useDefaultAgent(projectId);
|
|
238
252
|
const pathname = useUiPathname();
|
|
239
|
-
return (_jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(AgentShareControl, { projectId: projectId, agentName: agent.name, peopleHref: `${pathname}?section=people` }), startBlocked ? (_jsx(Hint, { label: startBlocked, children: _jsx("span", { className: "inline-flex", children: _jsxs(Button, { size: "sm", disabled: true, children: [_jsx(PlayIcon, { weight: "fill", className: "size-3.5 shrink-0" }), tI18nComplete.raw('textb1c52ee3677d')] }) }) })) : (_jsxs(Button, { size: "sm", onClick: () => startSession({ create: { agent_name: agent.name } }), children: [_jsx(PlayIcon, { weight: "fill", className: "size-3.5 shrink-0" }), tI18nComplete.raw('textb1c52ee3677d')] })), canWrite ? (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "
|
|
253
|
+
return (_jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(AgentShareControl, { projectId: projectId, agentName: agent.name, peopleHref: `${pathname}?section=people` }), startBlocked ? (_jsx(Hint, { label: startBlocked, children: _jsx("span", { className: "inline-flex", children: _jsxs(Button, { size: "sm", disabled: true, children: [_jsx(PlayIcon, { weight: "fill", className: "size-3.5 shrink-0" }), tI18nComplete.raw('textb1c52ee3677d')] }) }) })) : (_jsxs(Button, { size: "sm", onClick: () => startSession({ create: { agent_name: agent.name } }), children: [_jsx(PlayIcon, { weight: "fill", className: "size-3.5 shrink-0" }), tI18nComplete.raw('textb1c52ee3677d')] })), canWrite ? (_jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "secondary", size: "icon-sm", "aria-label": tI18nComplete.raw('textf8d46c2570e7'), children: _jsx(DotsThreeIcon, { className: "size-4" }) }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { disabled: isDefault || agent.enabled === false || makeDefault.isPending, onSelect: () => makeDefault.mutate(agent.name), children: [_jsx(StarIcon, { className: "size-4" }), isDefault
|
|
240
254
|
? tI18nComplete.raw('texte8cb80e5c5cb')
|
|
241
255
|
: tI18nComplete.raw('texte8f43f910a4e')] }), _jsx(DropdownMenuSeparator, {}), _jsx(DropdownMenuItem, { disabled: configure.pending, onSelect: () => setConfirmEditSource(true), children: tI18nComplete.raw('text4930821dd07b') })] })] })) : null, _jsx(ConfirmDialog, { open: confirmEditSource, onOpenChange: setConfirmEditSource, title: tI18nComplete.raw('text24ba36a8ec86'), description: tI18nComplete('text13324ae62b23', { value0: agent.name }), confirmLabel: tI18nComplete.raw('text0bce1a892dec'), cancelLabel: tI18nComplete.raw('text19766ed6ccb2'), onConfirm: () => {
|
|
242
256
|
setConfirmEditSource(false);
|
|
@@ -247,7 +261,7 @@ function AgentActions({ projectId, agent, config, canWrite, }) {
|
|
|
247
261
|
function AgentChips({ agent, config, size, }) {
|
|
248
262
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
249
263
|
const { showMode, isDefault, disabled } = agentStatus(agent, config);
|
|
250
|
-
return (_jsxs("span", { className: "flex items-center gap-1.5", children: [showMode ? (_jsx(Badge, { variant: "
|
|
264
|
+
return (_jsxs("span", { className: "flex items-center gap-1.5", children: [showMode ? (_jsx(Badge, { variant: "secondary", size: size, children: formatMode(agent.mode ?? '') })) : null, isDefault ? (_jsx(Badge, { variant: "secondary", size: size, children: tI18nComplete.raw('text21b111cbfe6e') })) : null, disabled ? (_jsx(Badge, { variant: "muted", size: size, children: tI18nComplete.raw('text75081b593d15') })) : null] }));
|
|
251
265
|
}
|
|
252
266
|
/**
|
|
253
267
|
* Breadcrumb, avatar, name, chips, actions — the full header at the top of
|
|
@@ -256,7 +270,7 @@ function AgentChips({ agent, config, size, }) {
|
|
|
256
270
|
*/
|
|
257
271
|
function AgentHeader({ projectId, agent, config, canWrite, children, }) {
|
|
258
272
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
259
|
-
return (_jsxs("header", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("nav", { "aria-label": tI18nComplete.raw('text2bd873d6c734'), className: "flex min-w-0 items-center gap-1.5 text-sm", children: [_jsx(Link, { href: capabilityTabHref(projectId, 'agent'), prefetch: true, className: "text-muted-foreground hover:text-foreground shrink-0 transition-colors", children: tI18nComplete.raw('text279b44d2ab4b') }), _jsx(CaretRightIcon, { "aria-hidden": true, className: "text-muted-foreground
|
|
273
|
+
return (_jsxs("header", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("nav", { "aria-label": tI18nComplete.raw('text2bd873d6c734'), className: "flex min-w-0 items-center gap-1.5 text-sm", children: [_jsx(Link, { href: capabilityTabHref(projectId, 'agent'), prefetch: true, className: "text-muted-foreground hover:text-foreground shrink-0 transition-colors", children: tI18nComplete.raw('text279b44d2ab4b') }), _jsx(CaretRightIcon, { "aria-hidden": true, className: "text-muted-foreground size-3.5 shrink-0" }), _jsx("h1", { className: "text-foreground truncate text-sm font-semibold", children: isMetaAgentName(agent.name) ? META_AGENT_DISPLAY_NAME : capitalizeWords(agent.name) }), _jsx(AgentChips, { agent: agent, config: config, size: "xs" })] }), _jsx(AgentActions, { projectId: projectId, agent: agent, config: config, canWrite: canWrite })] }), children] }));
|
|
260
274
|
}
|
|
261
275
|
// ─── Editable body ─────────────────────────────────────────────────────────
|
|
262
276
|
/** What a v1 project, or a reader without write, can still see. */
|
|
@@ -288,6 +302,22 @@ function EditableAgentPage({ projectId, agent, config, initial, schemaVersion, }
|
|
|
288
302
|
const sections = useMemo(() => agentConfigSectionKeys(schemaVersion).filter((k) => drivesOn || k !== 'drives'), [schemaVersion, drivesOn]);
|
|
289
303
|
const registryOptions = useMemo(() => registryGrantOptions({ manifest_raw: config.manifest_raw, agents: toArray(config.agents) }, agent.name), [config.manifest_raw, config.agents, agent.name]);
|
|
290
304
|
const section = useAgentSection(sections);
|
|
305
|
+
// PROTOTYPE: the `inline` nav variant shows each topic's current value.
|
|
306
|
+
const summaries = useMemo(() => {
|
|
307
|
+
const d = editor.draft;
|
|
308
|
+
const grant = (v) => grantSummary(v, tI18nComplete).label;
|
|
309
|
+
return {
|
|
310
|
+
skills: grant(d.skills),
|
|
311
|
+
connectors: grant(d.connectors),
|
|
312
|
+
secrets: grant(d.secrets),
|
|
313
|
+
apps: grant(d.apps),
|
|
314
|
+
actions: grant(d.kortix_permissions ?? d.kortix_cli),
|
|
315
|
+
subagents: grant(d.subagents),
|
|
316
|
+
commands: grant(d.commands),
|
|
317
|
+
extensions: grant(d.extensions),
|
|
318
|
+
model: editor.oc.model ? (editor.oc.model.split('/').pop() ?? editor.oc.model) : 'Default',
|
|
319
|
+
};
|
|
320
|
+
}, [editor.draft, editor.oc.model, tI18nComplete]);
|
|
291
321
|
const onSave = useCallback(async () => {
|
|
292
322
|
if (!editor.isDirty || update.isPending)
|
|
293
323
|
return;
|
|
@@ -305,7 +335,7 @@ function EditableAgentPage({ projectId, agent, config, initial, schemaVersion, }
|
|
|
305
335
|
// shared across topics and nothing is lost.
|
|
306
336
|
const leaveGuard = useUnsavedChangesGuard(editor.isDirty, pathname);
|
|
307
337
|
useSaveShortcut(onSave);
|
|
308
|
-
return (_jsx(AgentPageFrame, { header: _jsx(AgentHeader, { projectId: projectId, agent: agent, config: config, canWrite: true }), section: section, sections: sections, sectionHref: sectionHrefFor(pathname), pane: _jsx(AgentConfigSections, { section: section, editor: editor, options: options, skillsOptions: skillsOptions, registryOptions: registryOptions, skills: _jsx(SkillsGrantPage, { projectId: projectId, config: config, editor: editor }), connectors: _jsx(ConnectorsGrantPage, { projectId: projectId, editor: editor }), secrets: _jsx(SecretsGrantPage, { projectId: projectId, editor: editor }), apps: _jsx(AppsGrantPage, { projectId: projectId, editor: editor }), drives: _jsx(AgentDrivesSection, { projectId: projectId, agentName: agent.name }), overview: _jsx(OverviewPane, { description: editor.oc.description ?? '', onDescriptionChange: (next) => editor.setOc('description', next), descriptionHelp: editor.oc.mode === 'subagent'
|
|
338
|
+
return (_jsx(AgentPageFrame, { header: _jsx(AgentHeader, { projectId: projectId, agent: agent, config: config, canWrite: true }), section: section, sections: sections, sectionHref: sectionHrefFor(pathname), summaries: summaries, pane: _jsx(AgentConfigSections, { section: section, editor: editor, options: options, skillsOptions: skillsOptions, registryOptions: registryOptions, skills: _jsx(SkillsGrantPage, { projectId: projectId, config: config, editor: editor }), connectors: _jsx(ConnectorsGrantPage, { projectId: projectId, editor: editor }), secrets: _jsx(SecretsGrantPage, { projectId: projectId, editor: editor }), apps: _jsx(AppsGrantPage, { projectId: projectId, editor: editor }), drives: _jsx(AgentDrivesSection, { projectId: projectId, agentName: agent.name }), overview: _jsx(OverviewPane, { description: editor.oc.description ?? '', onDescriptionChange: (next) => editor.setOc('description', next), descriptionHelp: editor.oc.mode === 'subagent'
|
|
309
339
|
? 'Required. This is how other agents decide to call it.'
|
|
310
340
|
: 'One line on what this agent is for. Other agents read it when picking a subagent.', prompt: editor.oc.prompt ?? '', onPromptChange: (next) => editor.setOc('prompt', next) }), triggers: _jsx(AgentTriggersSection, { projectId: projectId, agentName: agent.name, defaultAgent: config.default_agent ?? config.open_code_default_agent }), people: _jsx(AgentPeopleSection, { projectId: projectId, agentName: agent.name }), authority: _jsx(AgentAuthorityCard, { projectId: projectId, agentName: agent.name, grant: editor.draft.kortix_permissions ?? editor.draft.kortix_cli }) }), footer: _jsxs(_Fragment, { children: [_jsx(SaveBar, { dirty: editor.isDirty, pending: update.isPending, onDiscard: () => setConfirmDiscard(true), onSave: onSave }), _jsx(ConfirmDialog, { open: confirmDiscard, onOpenChange: setConfirmDiscard, title: tI18nComplete.raw('text3b13192b9d88'), description: tI18nComplete('text8a36cce34f68', { value0: capitalizeWords(agent.name) }), confirmLabel: tI18nComplete.raw('texteb1a70e39274'), cancelLabel: tI18nComplete.raw('texte76fd2add010'), confirmVariant: "destructive", onConfirm: () => {
|
|
311
341
|
setConfirmDiscard(false);
|
|
@@ -317,34 +347,40 @@ function EditableAgentPage({ projectId, agent, config, initial, schemaVersion, }
|
|
|
317
347
|
}
|
|
318
348
|
/**
|
|
319
349
|
* The Overview topic — what the agent IS: one line of description and the
|
|
320
|
-
* instructions
|
|
350
|
+
* instructions. Laid out like a Settings pane: the pane title, then each
|
|
351
|
+
* field under its own section heading. A field is its own surface; no box
|
|
352
|
+
* wraps a heading and a field together.
|
|
321
353
|
*/
|
|
322
354
|
function OverviewPane({ description, onDescriptionChange, descriptionHelp, prompt, onPromptChange, }) {
|
|
323
355
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
324
|
-
|
|
356
|
+
const tEditor = useI18nTranslations('agentEditor');
|
|
357
|
+
return (_jsxs(_Fragment, { children: [_jsx(SettingsSectionHeader, { title: tEditor('overviewTitle'), className: "pb-1" }), _jsx(EditorSection, { title: tI18nComplete.raw('text526e0087cc3f'), description: descriptionHelp, bare: true, children: _jsx(Textarea, { "aria-label": tI18nComplete.raw('text526e0087cc3f'), value: description, placeholder: tI18nComplete.raw('text446f4eabf99f'), minHeight: 44, className: "text-sm", onChange: (e) => onDescriptionChange(e.target.value) }) }), _jsx(InstructionsSection, { value: prompt, onChange: onPromptChange })] }));
|
|
325
358
|
}
|
|
326
359
|
/**
|
|
327
360
|
* The instructions — the agent's system prompt, and the thing that most IS
|
|
328
361
|
* the agent. Two views of one field: Edit is the textarea, Preview renders
|
|
329
362
|
* the markdown the way the agent's source file reads. It opens on Preview
|
|
330
363
|
* when there is something to read and on Edit when there is not; the toggle
|
|
331
|
-
* is
|
|
332
|
-
* pages use for their filters.
|
|
364
|
+
* is the segmented `TabsList` at the section heading's right edge.
|
|
333
365
|
*/
|
|
334
|
-
function
|
|
366
|
+
function InstructionsSection({ value, onChange, }) {
|
|
335
367
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
336
368
|
const [view, setView] = useState(value.trim() ? 'preview' : 'edit');
|
|
337
|
-
return (
|
|
369
|
+
return (_jsx(EditorSection, { title: tI18nComplete.raw('text934652dce41d'), description: tI18nComplete.raw('text5fe8921b712c'), trailing: _jsx(Tabs, { value: view, onValueChange: (next) => setView(next), children: _jsxs(TabsList, { "aria-label": tI18nComplete.raw('texte75bb2d0d554'), children: [_jsx(TabsTrigger, { value: "edit", children: tI18nComplete.raw('text464c4ffd019e') }), _jsx(TabsTrigger, { value: "preview", children: tI18nComplete.raw('text324b134f57c7') })] }) }), bare: true, children: view === 'edit' ? (_jsx(Textarea, { "aria-label": tI18nComplete.raw('text934652dce41d'), value: value, placeholder: tI18nComplete.raw('text1436469ad07f'), minHeight: 420, autoFocus: value.trim().length > 0, className: "font-mono text-xs leading-relaxed", onChange: (e) => onChange(e.target.value) })) : (_jsx("div", { className: "bg-popover min-h-[420px] rounded-md border px-5 py-4", children: _jsx(MarkdownWithFrontmatter, { content: value }) })) }));
|
|
338
370
|
}
|
|
339
371
|
/**
|
|
340
372
|
* The save bar. Exists only while there is something to save — an always-on
|
|
341
|
-
* disabled pair of buttons is chrome that never earns its row. It
|
|
342
|
-
* the
|
|
343
|
-
*
|
|
373
|
+
* disabled pair of buttons is chrome that never earns its row. It floats at
|
|
374
|
+
* the bottom centre of the page in the Drive selection bar's shape
|
|
375
|
+
* (`project-files/components/drive-selection-bar.tsx`): a `bg-popover` card
|
|
376
|
+
* as wide as its content — the state as a title over one muted line, then
|
|
377
|
+
* Discard and Save as a spaced pair (a confirm is never glued to its cancel).
|
|
378
|
+
* It sits outside both scrollers, so it is reachable
|
|
379
|
+
* from any point in a long instruction set.
|
|
344
380
|
*/
|
|
345
381
|
function SaveBar({ dirty, pending, onDiscard, onSave, }) {
|
|
346
382
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
347
|
-
return (_jsx(AnimatePresence, { initial: false, children: dirty ? (_jsx(m.div, { initial: { opacity: 0, y: 8 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 8 }, transition: { type: 'spring', duration: 0.3, bounce: 0 }, className: "
|
|
383
|
+
return (_jsx(AnimatePresence, { initial: false, children: dirty ? (_jsx(m.div, { initial: { opacity: 0, y: 8 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: 8 }, transition: { type: 'spring', duration: 0.3, bounce: 0 }, className: "pointer-events-none absolute inset-x-0 bottom-4 z-30 flex justify-center px-4", children: _jsxs("div", { className: "bg-popover text-popover-foreground border-border pointer-events-auto flex max-w-full items-center gap-3 rounded-lg border p-2 pl-3.5 shadow-md", children: [_jsxs("div", { className: "min-w-0", "aria-live": "polite", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: tI18nComplete.raw('textefa5855ff509') }), _jsx("p", { className: "text-muted-foreground truncate text-xs", children: tI18nComplete.raw('textc8134fda3694') })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsx(Button, { variant: "secondary", size: "sm", onClick: onDiscard, disabled: pending, children: tI18nComplete.raw('texteb1a70e39274') }), _jsxs(Button, { variant: "secondary", size: "sm", className: "gap-1.5", onClick: onSave, disabled: pending, children: [pending ? _jsx(Loading, { className: "size-3.5 shrink-0" }) : null, tI18nComplete.raw('text1509f561f241'), _jsx(Kbd, { children: tI18nComplete.raw('text8cd003e6301b') })] })] })] }) }, "save-bar")) : null }));
|
|
348
384
|
}
|
|
349
385
|
/**
|
|
350
386
|
* Mod+S saves. The page is a document you edit, and every editor a person
|
|
@@ -444,10 +480,10 @@ function ReadOnlyAgentPage({ projectId, agent, config, canWrite, showUpgradeHint
|
|
|
444
480
|
});
|
|
445
481
|
const pathname = useUiPathname();
|
|
446
482
|
const section = useAgentSection(isPlatform ? PLATFORM_SECTIONS : READ_ONLY_SECTIONS);
|
|
447
|
-
const source = (
|
|
483
|
+
const source = (_jsx(EditorSection, { title: tI18nComplete.raw('text934652dce41d'), description: _jsx("span", { className: "font-mono", children: sourcePath }), lead: true, bare: true, children: _jsx("div", { className: "bg-popover overflow-hidden rounded-md border", children: _jsx(EntityFilePane, { path: sourcePath, content: fileQuery.data?.content, isLoading: fileQuery.isLoading, isError: fileQuery.isError, error: fileQuery.error, onRetry: () => {
|
|
448
484
|
void fileQuery.refetch();
|
|
449
|
-
}, skeletonRows: 4, errorTitle: tI18nComplete.raw('text2f2f540650bf') })
|
|
450
|
-
return (_jsx(AgentPageFrame, { header: _jsx(AgentHeader, { projectId: projectId, agent: agent, config: config, canWrite: canWrite && !isPlatform, children: agent.description ? (_jsx("p", { className: "text-muted-foreground max-w-2xl text-sm text-pretty", children: agent.description })) : null }), section: section, sections: isPlatform ? PLATFORM_SECTIONS : READ_ONLY_SECTIONS, sectionHref: sectionHrefFor(pathname), pane: _jsx(EditorSectionStyleProvider, { value: "panel", children: _jsxs("div", { className: "space-y-
|
|
485
|
+
}, skeletonRows: 4, errorTitle: tI18nComplete.raw('text2f2f540650bf') }) }) }));
|
|
486
|
+
return (_jsx(AgentPageFrame, { header: _jsx(AgentHeader, { projectId: projectId, agent: agent, config: config, canWrite: canWrite && !isPlatform, children: agent.description ? (_jsx("p", { className: "text-muted-foreground max-w-2xl text-sm text-pretty", children: agent.description })) : null }), section: section, sections: isPlatform ? PLATFORM_SECTIONS : READ_ONLY_SECTIONS, sectionHref: sectionHrefFor(pathname), pane: _jsx(EditorSectionStyleProvider, { value: "panel", children: _jsxs("div", { className: "space-y-8", children: [isPlatform ? (_jsx(InfoBanner, { tone: "info", title: tI18nComplete.raw('text85b7a59cdbd5'), children: tI18nComplete.raw('textd9c0c74b514b') })) : showUpgradeHint ? (_jsx(InfoBanner, { tone: "info", title: tI18nComplete.raw('textdc7ab144ca89'), children: tUpgrades.rich('agentEditorHint', {
|
|
451
487
|
code: (chunks) => _jsx("span", { className: "font-mono", children: chunks }),
|
|
452
|
-
}) })) : null, isPlatform ? null : section === 'overview' ? (_jsxs(_Fragment, { children: [source, _jsx(AgentScope, { projectId: projectId, agentName: agent.name, scope: agent.scope })] })) : section === 'people' ? (_jsx(AgentPeopleSection, { projectId: projectId, agentName: agent.name })) : section === 'triggers' ? (_jsx(AgentTriggersSection, { projectId: projectId, agentName: agent.name, defaultAgent: config.default_agent ?? config.open_code_default_agent })) : section === 'actions' ? (_jsx(AgentAuthorityCard, { projectId: projectId, agentName: agent.name, grant: agent.scope?.kortix_permissions ?? agent.scope?.kortix_cli })) : (_jsxs("div", { className: "space-y-
|
|
488
|
+
}) })) : null, isPlatform ? null : section === 'overview' ? (_jsxs(_Fragment, { children: [source, _jsx(AgentScope, { projectId: projectId, agentName: agent.name, scope: agent.scope })] })) : section === 'people' ? (_jsx(AgentPeopleSection, { projectId: projectId, agentName: agent.name })) : section === 'triggers' ? (_jsx(AgentTriggersSection, { projectId: projectId, agentName: agent.name, defaultAgent: config.default_agent ?? config.open_code_default_agent })) : section === 'actions' ? (_jsx(AgentAuthorityCard, { projectId: projectId, agentName: agent.name, grant: agent.scope?.kortix_permissions ?? agent.scope?.kortix_cli })) : (_jsxs("div", { className: "space-y-3", children: [_jsx(AgentModel, { projectId: projectId, agentName: agent.name }), _jsx("p", { className: "text-muted-foreground text-xs text-pretty", children: tI18nComplete.raw('text9dee2a1acfd9') })] }))] }) }) }));
|
|
453
489
|
}
|
|
@@ -37,7 +37,8 @@ import { EntityAvatar } from '../../primitives/entity-avatar.js';
|
|
|
37
37
|
import { Skeleton } from '../../primitives/skeleton.js';
|
|
38
38
|
import { errorToast, successToast } from '../../primitives/toast.js';
|
|
39
39
|
import { UserAvatar } from '../../primitives/user-avatar.js';
|
|
40
|
-
import {
|
|
40
|
+
import { EmptyState } from '../../primitives/empty-state.js';
|
|
41
|
+
import { EditorList, EditorSection } from '../sections/view/agent-editor-primitives.js';
|
|
41
42
|
import { AccessDialog, } from '../../access/access/access-dialog.js';
|
|
42
43
|
import { builtinRole, customRole, ROLE_NONE } from '../../access/access/role-select.js';
|
|
43
44
|
import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
|
|
@@ -133,20 +134,20 @@ export function AgentPeopleSection({ projectId, agentName, }) {
|
|
|
133
134
|
});
|
|
134
135
|
setEditOpen(true);
|
|
135
136
|
};
|
|
136
|
-
return (_jsxs(EditorSection, { title: tI18nComplete.raw('text82d9af69e1a1'), description: tI18nComplete.raw('text96feb5be077d'),
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
137
|
+
return (_jsxs(EditorSection, { title: tI18nComplete.raw('text82d9af69e1a1'), description: tI18nComplete.raw('text96feb5be077d'), trailing: accountId ? (_jsxs(Button, { variant: "secondary", size: "sm", className: "gap-1.5", onClick: () => setGrantOpen(true), children: [_jsx(PlusIcon, { className: "size-4" }), tI18nComplete.raw('text8693768c7e08')] })) : undefined, lead: true, bare: true, children: [_jsx("div", { children: grantsQuery.isLoading ? (_jsx(EditorList, { children: [0, 1].map((i) => (_jsxs("li", { className: "flex items-center gap-3 px-4 py-2.5", children: [_jsx(Skeleton, { className: "size-8 rounded-md" }), _jsx(Skeleton, { className: "h-4 w-40 rounded-sm" })] }, i))) })) : assigned.length === 0 ? (_jsx(EmptyState, { size: "sm", title: tI18nComplete.raw('text011c4e48df01') })) : (_jsx(EditorList, { children: assigned.map((g) => {
|
|
138
|
+
const member = g.principal_type === 'member'
|
|
139
|
+
? accessQuery.data?.members.find((m) => m.user_id === g.principal_id)
|
|
140
|
+
: undefined;
|
|
141
|
+
return (_jsxs("li", { className: "flex items-center gap-3 px-4 py-2.5", children: [g.principal_type === 'group' ? (_jsx(EntityAvatar, { icon: UsersIcon, size: "md" })) : g.principal_type === 'project' ? (_jsx(EntityAvatar, { icon: UsersThreeIcon, size: "md" })) : (_jsx(UserAvatar, { email: member?.email ?? g.principal_label, size: "md" })), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "text-foreground block truncate text-sm font-medium", children: g.principal_type === 'project'
|
|
142
|
+
? tSharing('everyone', { project: g.principal_label })
|
|
143
|
+
: g.principal_label }), _jsxs("span", { className: "text-muted-foreground block truncate text-xs", children: [g.principal_type === 'project'
|
|
144
|
+
? tSharing('everyoneMeta')
|
|
145
|
+
: g.principal_type === 'group'
|
|
146
|
+
? tSharing('groupMeta')
|
|
147
|
+
: tSharing('memberMeta'), g.expires_at
|
|
148
|
+
? tI18nComplete('textdc40ace03968', {
|
|
149
|
+
value0: new Date(g.expires_at).toLocaleDateString(),
|
|
150
|
+
})
|
|
151
|
+
: '', g.orphaned ? tI18nComplete.raw('textc795f93da2e5') : ''] })] }), g.principal_type === 'project' ? (_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setStopSharing(g), children: tSharing('removeEveryone') })) : (_jsxs(Button, { variant: "ghost", size: "sm", className: "gap-1.5", onClick: () => openEdit(g), disabled: !accountId, children: [_jsx(PencilSimpleIcon, { className: "size-3.5 shrink-0" }), tI18nComplete.raw('text464c4ffd019e')] }))] }, g.grant_id));
|
|
152
|
+
}) })) }), accountId ? (_jsx(AccessDialog, { open: grantOpen, onOpenChange: setGrantOpen, accountId: accountId, scope: { kind: 'project', projectId, projectName }, mode: { kind: 'grant' }, initialAgentIds: [agentName] })) : null, accountId && editTarget ? (_jsx(AccessDialog, { open: editOpen, onOpenChange: setEditOpen, accountId: accountId, scope: { kind: 'project', projectId, projectName }, mode: { kind: 'edit', principal: editTarget.principal, current: editTarget.current }, inheritedFrom: editTarget.inheritedFrom }, `${editTarget.principal.type}:${editTarget.principal.id}`)) : null, _jsx(ConfirmDialog, { open: stopSharing !== null, onOpenChange: (open) => !open && setStopSharing(null), title: tSharing('removeEveryoneTitle', { agent: agentName }), description: tSharing('removeEveryoneDescription', { agent: agentName }), confirmLabel: tSharing('removeEveryone'), confirmVariant: "destructive", isPending: stopSharingMutation.isPending, onConfirm: () => stopSharing && stopSharingMutation.mutate(stopSharing.grant_id) })] }));
|
|
152
153
|
}
|
|
@@ -28,7 +28,8 @@ import { Badge } from '../../primitives/badge.js';
|
|
|
28
28
|
import { Button } from '../../primitives/button.js';
|
|
29
29
|
import { ConfirmDialog } from '../../primitives/confirm-dialog.js';
|
|
30
30
|
import { Skeleton } from '../../primitives/skeleton.js';
|
|
31
|
-
import {
|
|
31
|
+
import { EmptyState } from '../../primitives/empty-state.js';
|
|
32
|
+
import { EditorList, EditorSection } from '../sections/view/agent-editor-primitives.js';
|
|
32
33
|
import { useProjectFeatureFlags } from '../../internal/lib/use-project-feature-flags.js';
|
|
33
34
|
import { cn } from '../../internal/lib/utils.js';
|
|
34
35
|
import { listProjectTriggers } from '@kortix/sdk';
|
|
@@ -89,10 +90,10 @@ export function AgentTriggersSection({ projectId, agentName, defaultAgent, }) {
|
|
|
89
90
|
setSelectedSlug(null);
|
|
90
91
|
},
|
|
91
92
|
});
|
|
92
|
-
return (_jsxs(EditorSection, { title: tI18nComplete.raw('texte62f2148a64d'), description: tI18nComplete.raw('text1a1e4d549e85'),
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
return (_jsxs(EditorSection, { title: tI18nComplete.raw('texte62f2148a64d'), description: tI18nComplete.raw('text1a1e4d549e85'), trailing: canCreate ? (_jsxs(Button, { variant: "secondary", size: "sm", className: "gap-1.5", onClick: () => setCreateOpen(true), children: [_jsx(PlusIcon, { className: "size-4" }), tI18nComplete.raw('text58fd308928dd')] })) : undefined, lead: true, bare: true, children: [_jsx("div", { children: triggersQuery.isLoading ? (_jsx(EditorList, { children: [0, 1].map((i) => (_jsxs("li", { className: "flex items-center gap-3 px-4 py-2.5", children: [_jsx(Skeleton, { className: "size-8 rounded-sm" }), _jsx(Skeleton, { className: "h-4 w-40 rounded-sm" })] }, i))) })) : mine.length === 0 ? (_jsx(EmptyState, { size: "sm", title: tI18nComplete.raw('textb254c6e02e1a') })) : (_jsx(EditorList, { children: mine.map((trigger) => {
|
|
94
|
+
const KindIcon = KIND_ICON[trigger.type] ?? TimerIcon;
|
|
95
|
+
return (_jsx("li", { children: _jsxs("button", { type: "button", onClick: () => setSelectedSlug(trigger.slug), className: cn('hover:bg-hover flex w-full items-center gap-3 px-4 py-2.5 text-left transition-colors duration-fast', 'focus-visible:bg-hover focus-visible:outline-none'), children: [_jsx("span", { className: cn('flex size-8 shrink-0 items-center justify-center rounded-sm', trigger.enabled ? 'bg-kortix-green/15' : 'bg-muted'), children: _jsx(KindIcon, { weight: "fill", className: cn('size-4', trigger.enabled ? 'text-kortix-green' : 'text-muted-foreground') }) }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "text-foreground block truncate text-sm font-medium", children: triggerName(trigger) }), _jsx("span", { className: "text-muted-foreground block truncate text-xs", children: describeWhen(trigger) })] }), !trigger.enabled ? (_jsx(Badge, { variant: "muted", size: "xs", children: tI18nComplete.raw('texte159b06187d3') })) : null] }) }, trigger.slug));
|
|
96
|
+
}) })) }), canCreate ? (_jsx(TriggerComposer, { projectId: projectId, open: createOpen, onOpenChange: setCreateOpen, initialAgent: agentName, onCreated: (slug) => {
|
|
96
97
|
setCreateOpen(false);
|
|
97
98
|
void invalidate();
|
|
98
99
|
// The composer toasts the creation; straight into the new entry, as the Triggers tab does.
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { customizePath, uiRoutes } from '../../lib/routes.js';
|
|
4
4
|
import { NewEntityMenu } from '../shared/new-entity-menu.js';
|
|
5
5
|
import { useTranslations as useI18nTranslations } from '../../i18n/index.js';
|
|
6
|
+
import { agentAccess } from './agent-access.js';
|
|
6
7
|
import { useMemo, useRef, useState } from 'react';
|
|
7
8
|
import { Badge } from '../../primitives/badge.js';
|
|
8
9
|
import { Button } from '../../primitives/button.js';
|
|
@@ -163,10 +164,26 @@ function CardCaret() {
|
|
|
163
164
|
function AgentCardFacts({ agent, triggerCount, peopleCount, }) {
|
|
164
165
|
const tI18nComplete = useI18nTranslations('hardcodedUi.i18nComplete');
|
|
165
166
|
const model = agent.model ? agent.model.split('/').pop() : null;
|
|
167
|
+
const accessLabel = accessLabelOf(agentAccess(agent.scope), tI18nComplete);
|
|
166
168
|
const sep = (_jsx("span", { "aria-hidden": true, className: "text-muted-foreground", children: "\u00B7" }));
|
|
167
169
|
return (_jsxs(_Fragment, { children: [_jsx("span", { className: cn('truncate', model && 'font-mono'), children: model ?? tI18nComplete.raw('text3840d9d29421') }), sep, _jsxs("span", { className: "tabular-nums", children: [triggerCount, " ", triggerCount === 1 ? 'trigger' : 'triggers'] }), peopleCount !== null ? (_jsxs(_Fragment, { children: [sep, _jsx("span", { className: "tabular-nums", children: peopleCount === 0
|
|
168
170
|
? tI18nComplete.raw('textb6c70926c1aa')
|
|
169
|
-
: `${peopleCount} ${peopleCount === 1 ? 'grant' : 'grants'}` })] })) : null] }));
|
|
171
|
+
: `${peopleCount} ${peopleCount === 1 ? 'grant' : 'grants'}` })] })) : null, accessLabel ? _jsx("span", { className: "basis-full tabular-nums", children: accessLabel }) : null] }));
|
|
172
|
+
}
|
|
173
|
+
/** The access slot: what the configuration grants (KRTX-3025). */
|
|
174
|
+
function accessLabelOf(access, t) {
|
|
175
|
+
if (!access)
|
|
176
|
+
return null;
|
|
177
|
+
if (access.kind === 'full')
|
|
178
|
+
return t.raw('textf19611c61ca5');
|
|
179
|
+
const LABELS = {
|
|
180
|
+
connectors: { all: 'textd83250185d41', count: 'text15589a542412' },
|
|
181
|
+
secrets: { all: 'text0b38e3daeb93', count: 'texte96d99ad9896' },
|
|
182
|
+
actions: { all: 'text70b8d7e10749', count: 'text2d3f4433505a' },
|
|
183
|
+
};
|
|
184
|
+
return access.parts
|
|
185
|
+
.map(({ kind, value }) => value === 'all' ? t.raw(LABELS[kind].all) : t(LABELS[kind].count, { count: value }))
|
|
186
|
+
.join(', ');
|
|
170
187
|
}
|
|
171
188
|
/**
|
|
172
189
|
* Card badges — "also a subagent", the default-agent star, disabled.
|
|
@@ -25,8 +25,9 @@ export function mcpServerIdentity(rawUrl, takenSlugs) {
|
|
|
25
25
|
labels.pop();
|
|
26
26
|
const base = [...labels].reverse().find((label) => !GENERIC_LABELS.has(label)) ?? labels[labels.length - 1] ?? 'mcp';
|
|
27
27
|
const root = normalizeConnectorConnectionSlug(base) || 'mcp';
|
|
28
|
+
const taken = new Set(takenSlugs);
|
|
28
29
|
let slug = root;
|
|
29
|
-
for (let n = 2;
|
|
30
|
+
for (let n = 2; taken.has(slug); n++)
|
|
30
31
|
slug = `${root}-${n}`;
|
|
31
32
|
const name = root.charAt(0).toUpperCase() + root.slice(1);
|
|
32
33
|
return { slug, name };
|
|
@@ -37,8 +38,9 @@ export function mcpServerIdentity(rawUrl, takenSlugs) {
|
|
|
37
38
|
*/
|
|
38
39
|
export function mcpAppIdentity(appName, takenSlugs) {
|
|
39
40
|
const root = normalizeConnectorConnectionSlug(appName) || 'mcp';
|
|
41
|
+
const taken = new Set(takenSlugs);
|
|
40
42
|
let slug = root;
|
|
41
|
-
for (let n = 2;
|
|
43
|
+
for (let n = 2; taken.has(slug); n++)
|
|
42
44
|
slug = `${root}-${n}`;
|
|
43
45
|
return { slug, name: appName };
|
|
44
46
|
}
|
|
@@ -46,6 +46,20 @@ export type CatalogEntry = (CatalogEntryFields & {
|
|
|
46
46
|
});
|
|
47
47
|
/** Native platform provider. Each member's paired machine is one of its accounts. */
|
|
48
48
|
export declare function computersCatalogEntry(tI18nComplete: UiTranslator): CatalogEntry;
|
|
49
|
+
/**
|
|
50
|
+
* The icon URL a Discover record's card loads.
|
|
51
|
+
*
|
|
52
|
+
* A share of the catalogue's records carry a `domain` and no `icon` — the
|
|
53
|
+
* upstream feed only holds a logo for entries it could scrape one for. The
|
|
54
|
+
* card for such a record used to fall straight to a generic globe glyph, which
|
|
55
|
+
* is exactly the "inconsistent or missing imagery" a connector catalogue
|
|
56
|
+
* should not show when the app's own favicon is one well-known URL away. The
|
|
57
|
+
* same favicon service the marketing connectors page and `FaviconAvatar`
|
|
58
|
+
* already use resolves it; where the domain is a pseudo-host (`*.local`, the
|
|
59
|
+
* apis.guru feed's placeholders) it answers the generic globe image, which
|
|
60
|
+
* reads the same as the glyph it replaced.
|
|
61
|
+
*/
|
|
62
|
+
export declare function discoverEntryIcon(connector: Pick<DiscoverConnector, 'icon' | 'domain'>): string | null;
|
|
49
63
|
export declare function catalogEntryFromDiscover(connector: DiscoverConnector): CatalogEntry;
|
|
50
64
|
export declare function catalogEntryFromEasyConnect(app: PipedreamApp & {
|
|
51
65
|
provider?: 'composio' | 'pipedream';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { faviconUrlForHostname } from '../../../lib/favicon.js';
|
|
1
2
|
import { POPULAR_SECTION } from './connector-categories.js';
|
|
2
3
|
/** Native platform provider. Each member's paired machine is one of its accounts. */
|
|
3
4
|
export function computersCatalogEntry(tI18nComplete) {
|
|
@@ -12,6 +13,22 @@ export function computersCatalogEntry(tI18nComplete) {
|
|
|
12
13
|
popularity: null,
|
|
13
14
|
};
|
|
14
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* The icon URL a Discover record's card loads.
|
|
18
|
+
*
|
|
19
|
+
* A share of the catalogue's records carry a `domain` and no `icon` — the
|
|
20
|
+
* upstream feed only holds a logo for entries it could scrape one for. The
|
|
21
|
+
* card for such a record used to fall straight to a generic globe glyph, which
|
|
22
|
+
* is exactly the "inconsistent or missing imagery" a connector catalogue
|
|
23
|
+
* should not show when the app's own favicon is one well-known URL away. The
|
|
24
|
+
* same favicon service the marketing connectors page and `FaviconAvatar`
|
|
25
|
+
* already use resolves it; where the domain is a pseudo-host (`*.local`, the
|
|
26
|
+
* apis.guru feed's placeholders) it answers the generic globe image, which
|
|
27
|
+
* reads the same as the glyph it replaced.
|
|
28
|
+
*/
|
|
29
|
+
export function discoverEntryIcon(connector) {
|
|
30
|
+
return connector.icon ?? faviconUrlForHostname(connector.domain);
|
|
31
|
+
}
|
|
15
32
|
export function catalogEntryFromDiscover(connector) {
|
|
16
33
|
return {
|
|
17
34
|
source: 'discover',
|
|
@@ -20,7 +37,7 @@ export function catalogEntryFromDiscover(connector) {
|
|
|
20
37
|
slug: connector.slug,
|
|
21
38
|
name: connector.name,
|
|
22
39
|
description: connector.description,
|
|
23
|
-
icon: connector
|
|
40
|
+
icon: discoverEntryIcon(connector),
|
|
24
41
|
categories: connector.categories,
|
|
25
42
|
popularity: connector.popularity,
|
|
26
43
|
};
|
|
@@ -10,6 +10,34 @@ export interface CatalogInstall {
|
|
|
10
10
|
pendingKey: string | null;
|
|
11
11
|
onInstall: (entry: CatalogEntry) => void;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* A catalog favicon, or a neutral glyph tile when the record has none or its
|
|
15
|
+
* URL fails to load.
|
|
16
|
+
*
|
|
17
|
+
* A plain `<img>`, not `next/image`. These are third-party favicons on
|
|
18
|
+
* arbitrary hosts, so the loader was already bypassed with `unoptimized` — which
|
|
19
|
+
* left `fill` costing an absolutely-positioned child inside a `relative`
|
|
20
|
+
* wrapper, per card, for no optimisation in return. Native `loading="lazy"`
|
|
21
|
+
* defers every icon below the fold, which is most of them on a browse page.
|
|
22
|
+
*
|
|
23
|
+
* `width`/`height` are set so the box is reserved before the image arrives and
|
|
24
|
+
* the grid never reflows around a late favicon.
|
|
25
|
+
*
|
|
26
|
+
* The broken-image state is the fallback the null case already had: a logo
|
|
27
|
+
* URL that 404s used to render the browser's broken-image glyph inside the
|
|
28
|
+
* tile, which is worse than no imagery at all. `onError` swaps to the same
|
|
29
|
+
* glyph tile — the same fallback a record with no icon gets, so "missing" and
|
|
30
|
+
* "unavailable" look identical. Mirrors `ConnectorAppIcon`'s broken state.
|
|
31
|
+
*
|
|
32
|
+
* The latch is per URL (`failedUrl`, not a boolean): a URL that failed stays
|
|
33
|
+
* failed, while a swapped URL gets a fresh try without any call-site key —
|
|
34
|
+
* merge-search swaps a merged twin's icon to the managed logo as catalogue
|
|
35
|
+
* pages stream in.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ConnectorIcon({ icon, computer, }: {
|
|
38
|
+
icon: string | null;
|
|
39
|
+
computer?: boolean;
|
|
40
|
+
}): import("react").JSX.Element;
|
|
13
41
|
/**
|
|
14
42
|
* The catalogue body: one flat, paginated, searchable grid.
|
|
15
43
|
*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useTranslations } from '../../../i18n/index.js';
|
|
4
4
|
import { GlobeIcon, MonitorIcon } from '@phosphor-icons/react';
|
|
5
|
-
import { memo } from 'react';
|
|
5
|
+
import { memo, useState } from 'react';
|
|
6
6
|
import { Badge } from '../../../primitives/badge.js';
|
|
7
7
|
import { Button } from '../../../primitives/button.js';
|
|
8
8
|
import Loading from '../../../primitives/loading.js';
|
|
@@ -43,7 +43,8 @@ function CatalogAffordance({ entry, connected, install, }) {
|
|
|
43
43
|
disabled: !install.ready || install.pendingKey !== null, "data-testid": "catalog-add" }));
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* A catalog favicon, or a neutral glyph tile when the record has none
|
|
46
|
+
* A catalog favicon, or a neutral glyph tile when the record has none or its
|
|
47
|
+
* URL fails to load.
|
|
47
48
|
*
|
|
48
49
|
* A plain `<img>`, not `next/image`. These are third-party favicons on
|
|
49
50
|
* arbitrary hosts, so the loader was already bypassed with `unoptimized` — which
|
|
@@ -53,12 +54,24 @@ function CatalogAffordance({ entry, connected, install, }) {
|
|
|
53
54
|
*
|
|
54
55
|
* `width`/`height` are set so the box is reserved before the image arrives and
|
|
55
56
|
* the grid never reflows around a late favicon.
|
|
57
|
+
*
|
|
58
|
+
* The broken-image state is the fallback the null case already had: a logo
|
|
59
|
+
* URL that 404s used to render the browser's broken-image glyph inside the
|
|
60
|
+
* tile, which is worse than no imagery at all. `onError` swaps to the same
|
|
61
|
+
* glyph tile — the same fallback a record with no icon gets, so "missing" and
|
|
62
|
+
* "unavailable" look identical. Mirrors `ConnectorAppIcon`'s broken state.
|
|
63
|
+
*
|
|
64
|
+
* The latch is per URL (`failedUrl`, not a boolean): a URL that failed stays
|
|
65
|
+
* failed, while a swapped URL gets a fresh try without any call-site key —
|
|
66
|
+
* merge-search swaps a merged twin's icon to the managed logo as catalogue
|
|
67
|
+
* pages stream in.
|
|
56
68
|
*/
|
|
57
|
-
function ConnectorIcon({ icon, computer = false }) {
|
|
58
|
-
|
|
69
|
+
export function ConnectorIcon({ icon, computer = false, }) {
|
|
70
|
+
const [failedUrl, setFailedUrl] = useState(null);
|
|
71
|
+
if (!icon || failedUrl === icon) {
|
|
59
72
|
return (_jsx("span", { className: "bg-card flex size-9 shrink-0 items-center justify-center rounded-sm", children: computer ? _jsx(MonitorIcon, { className: "size-5" }) : _jsx(GlobeIcon, { className: "size-5" }) }));
|
|
60
73
|
}
|
|
61
|
-
return (_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-sm", children: _jsx("img", { src: icon, alt: "", width: 36, height: 36, loading: "lazy", decoding: "async", referrerPolicy: "no-referrer", className: "size-9 object-contain" }) }));
|
|
74
|
+
return (_jsx("span", { className: "flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-sm", children: _jsx("img", { src: icon, alt: "", width: 36, height: 36, loading: "lazy", decoding: "async", referrerPolicy: "no-referrer", className: "size-9 object-contain", onError: () => setFailedUrl(icon) }) }));
|
|
62
75
|
}
|
|
63
76
|
/**
|
|
64
77
|
* One catalogue card: icon and title on the bare page — no border, no
|
|
@@ -18,7 +18,9 @@ export type AppRef = {
|
|
|
18
18
|
slug: string;
|
|
19
19
|
};
|
|
20
20
|
export declare function connectorsHref(projectId: string, scope?: 'all' | 'connected' | 'channels'): string;
|
|
21
|
-
|
|
21
|
+
export declare function connectorSearchFromParams(search: Pick<URLSearchParams, 'get'> | null | undefined): string;
|
|
22
|
+
/** Sets `?q=` to the trimmed query, or removes it when the query is empty. */
|
|
23
|
+
export declare function withConnectorSearch(params: URLSearchParams, query: string): URLSearchParams;
|
|
22
24
|
export declare function appRefFromEntry(entry: CatalogEntry): AppRef | null;
|
|
23
25
|
export declare function appHref(projectId: string, app: AppRef): string;
|
|
24
26
|
export declare function appRefFromLocation(appSegment: string, search: URLSearchParams | null): AppRef | null;
|
|
@@ -23,6 +23,24 @@ export function connectorsHref(projectId, scope) {
|
|
|
23
23
|
return scope ? `${base(projectId)}?scope=${scope}` : base(projectId);
|
|
24
24
|
}
|
|
25
25
|
/** `null` for the computer entry: a computer has no app page. */
|
|
26
|
+
/**
|
|
27
|
+
* The catalogue search, held in `?q=`. Opening a connector is a route change
|
|
28
|
+
* that unmounts the catalogue; a search kept only in state was gone on browser
|
|
29
|
+
* Back (KRTX-3018).
|
|
30
|
+
*/
|
|
31
|
+
const SEARCH_PARAM = 'q';
|
|
32
|
+
export function connectorSearchFromParams(search) {
|
|
33
|
+
return search?.get(SEARCH_PARAM)?.trim() ?? '';
|
|
34
|
+
}
|
|
35
|
+
/** Sets `?q=` to the trimmed query, or removes it when the query is empty. */
|
|
36
|
+
export function withConnectorSearch(params, query) {
|
|
37
|
+
const trimmed = query.trim();
|
|
38
|
+
if (trimmed)
|
|
39
|
+
params.set(SEARCH_PARAM, trimmed);
|
|
40
|
+
else
|
|
41
|
+
params.delete(SEARCH_PARAM);
|
|
42
|
+
return params;
|
|
43
|
+
}
|
|
26
44
|
export function appRefFromEntry(entry) {
|
|
27
45
|
if (entry.source === 'discover') {
|
|
28
46
|
return { source: 'discover', slug: entry.slug, id: entry.connector.id };
|