@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
|
@@ -675,7 +675,7 @@ export function SqliteRenderer({ filePath, fileName, className, readOnly = false
|
|
|
675
675
|
// ── Main layout ───────────────────────────────────────────────────────
|
|
676
676
|
return (_jsxs("div", { className: cn('bg-background relative flex h-full w-full flex-col', className), children: [_jsxs("div", { className: "flex h-10 shrink-0 items-center gap-2 border-b px-3 py-1.5", children: [_jsxs("span", { className: "text-muted-foreground/60 text-xs tabular-nums", children: [tables.filter((t) => t.type === 'table').length, ' ', tHardcodedUi.raw('i18nComplete.text0d4fc4a78d37'), tables.filter((t) => t.type === 'table').length !== 1 ? 's' : '', tables.some((t) => t.type === 'view') && (_jsxs(_Fragment, { children: [' ', "\u00B7 ", tables.filter((t) => t.type === 'view').length, ' ', tHardcodedUi.raw('i18nComplete.text2bcb43cbc8f6'), tables.filter((t) => t.type === 'view').length !== 1 ? 's' : ''] })), _jsxs(_Fragment, { children: [' ', "\u00B7 ", tables.reduce((sum, t) => sum + t.rowCount, 0).toLocaleString(), ' ', tHardcodedUi.raw('i18nComplete.textbc51e9e65d79')] })] }), hasUnsavedChanges && (_jsx("span", { className: "bg-kortix-yellow h-1.5 w-1.5 shrink-0 rounded-full", title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line795JsxAttrTitleUnsavedChanges') })), _jsxs("div", { className: "ml-auto flex items-center gap-1", children: [hasUnsavedChanges && (_jsxs(_Fragment, { children: [_jsxs(Button, { variant: "muted", size: "toolbar", onClick: handleDiscard, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line806JsxAttrTitleDiscardChanges'), children: [_jsx(Undo2, { className: "h-3 w-3" }), tHardcodedUi.raw('i18nComplete.texteb1a70e39274')] }), _jsxs(Button, { variant: "default", size: "toolbar", onClick: handleSave, disabled: isSaving, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line816JsxAttrTitleSaveToFileS'), children: [isSaving ? _jsx(Loading, { className: "h-3 w-3" }) : _jsx(Save, { className: "h-3 w-3" }), tHardcodedUi.raw('i18nComplete.text1509f561f241')] })] })), _jsx("div", { className: "bg-muted/60 ml-1 flex items-center rounded-md p-0.5", children: ['data', 'schema', 'query'].map((mode) => (_jsxs("button", { className: cn('inline-flex h-6 cursor-pointer items-center gap-1 rounded-sm px-2 text-xs transition-colors', viewMode === mode
|
|
677
677
|
? 'bg-background text-foreground shadow-sm'
|
|
678
|
-
: 'text-muted-foreground/60 hover:text-foreground'), onClick: () => setViewMode(mode), children: [mode === 'data' && _jsx(List, { className: "h-3 w-3" }), mode === 'schema' && _jsx(Code2, { className: "h-3 w-3" }), mode === 'query' && _jsx(Play, { className: "h-3 w-3" }), mode.charAt(0).toUpperCase() + mode.slice(1)] }, mode))) })] })] }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsxs("div", { className: "bg-muted/10 flex w-56 shrink-0 flex-col border-r", children: [_jsx("div", { className: "border-b p-2", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground/50 absolute top-1/2 left-2 h-3 w-3 -translate-y-1/2" }), _jsx(Input, { type: "text", placeholder: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line860JsxAttrPlaceholderFilterTables'), autoComplete: "off", value: tableSearch, onChange: (e) => setTableSearch(e.target.value), className: "h-7 pr-7 pl-7 text-xs" }), tableSearch && (_jsx("button", { onClick: () => setTableSearch(''), className: "text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer", children: _jsx(X, { className: "h-3 w-3" }) }))] }) }), _jsx("div", { className: "flex-1 overflow-y-auto py-1", children: filteredTables.map((table) => (_jsxs("button", { onClick: () => {
|
|
678
|
+
: 'text-muted-foreground/60 hover:text-foreground'), onClick: () => setViewMode(mode), children: [mode === 'data' && _jsx(List, { className: "h-3 w-3" }), mode === 'schema' && _jsx(Code2, { className: "h-3 w-3" }), mode === 'query' && _jsx(Play, { className: "h-3 w-3" }), mode.charAt(0).toUpperCase() + mode.slice(1)] }, mode))) })] })] }), _jsxs("div", { className: "flex flex-1 overflow-hidden", children: [_jsxs("div", { className: "bg-muted/10 flex w-56 shrink-0 flex-col border-r", children: [_jsx("div", { className: "border-b p-2", children: _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground/50 absolute top-1/2 left-2 h-3 w-3 -translate-y-1/2" }), _jsx(Input, { type: "text", placeholder: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line860JsxAttrPlaceholderFilterTables'), autoComplete: "off", value: tableSearch, onChange: (e) => setTableSearch(e.target.value), className: "h-7 pr-7 pl-7 text-xs" }), tableSearch && (_jsx("button", { onClick: () => setTableSearch(''), "aria-label": tHardcodedUi.raw('i18nComplete.text83b12c2216ef'), className: "text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer", children: _jsx(X, { className: "h-3 w-3" }) }))] }) }), _jsx("div", { className: "flex-1 overflow-y-auto py-1", children: filteredTables.map((table) => (_jsxs("button", { onClick: () => {
|
|
679
679
|
setSelectedTable(table.name);
|
|
680
680
|
setSearchTerm('');
|
|
681
681
|
if (viewMode === 'query') {
|
|
@@ -683,7 +683,7 @@ export function SqliteRenderer({ filePath, fileName, className, readOnly = false
|
|
|
683
683
|
}
|
|
684
684
|
}, className: cn('flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-left text-sm transition-colors', selectedTable === table.name
|
|
685
685
|
? 'bg-accent text-accent-foreground'
|
|
686
|
-
: 'text-muted-foreground hover:bg-muted/50 hover:text-foreground'), children: [table.type === 'view' ? (_jsx(Eye, { className: "text-kortix-purple h-3.5 w-3.5 shrink-0" })) : (_jsx(Table2, { className: "text-kortix-blue h-3.5 w-3.5 shrink-0" })), _jsx("span", { className: "flex-1 truncate text-xs font-medium", children: table.name }), _jsx("span", { className: "text-muted-foreground/50 shrink-0 text-xs tabular-nums", children: table.rowCount.toLocaleString() })] }, table.name))) }), _jsxs("div", { className: "text-muted-foreground/30 border-t px-3 py-1.5 text-xs tabular-nums", children: [filteredTables.length, "/", tables.length, ' ', tHardcodedUi.raw('i18nComplete.textbaaf53622a51')] })] }), _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [viewMode === 'data' && selectedTableInfo && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex h-9 shrink-0 items-center gap-2 border-b px-3 py-1.5", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [selectedTableInfo.type === 'view' ? (_jsx(Eye, { className: "text-kortix-purple h-3.5 w-3.5 shrink-0" })) : (_jsx(Table2, { className: "text-kortix-blue h-3.5 w-3.5 shrink-0" })), _jsx("span", { className: "text-foreground truncate text-xs font-medium", children: selectedTableInfo.name }), _jsxs("span", { className: "text-muted-foreground/40 shrink-0 text-xs tabular-nums", children: [selectedTableInfo.rowCount.toLocaleString(), " \u00D7", ' ', selectedTableInfo.columns.length] })] }), _jsxs("div", { className: "ml-auto flex items-center gap-1", children: [isEditable && (_jsxs(_Fragment, { children: [_jsx("button", { className: "text-muted-foreground/50 hover:text-foreground hover:bg-muted inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors", onClick: handleAddRow, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line941JsxAttrTitleInsertRow'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }), _jsx("button", { className: "text-muted-foreground/50 hover:bg-destructive/10 hover:text-destructive inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors", onClick: handleDeleteSelected, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line948JsxAttrTitleDeleteSelectedRows'), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }), _jsx("div", { className: "bg-border mx-0.5 h-4 w-px" })] })), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground/40 absolute top-1/2 left-2 h-3 w-3 -translate-y-1/2" }), _jsx(Input, { type: "text", placeholder: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line961JsxAttrPlaceholderFilter'), autoComplete: "off", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "h-7 w-40 pr-7 pl-7 text-xs" }), searchTerm && (_jsx("button", { onClick: () => setSearchTerm(''), className: "text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer", children: _jsx(X, { className: "h-3 w-3" }) }))] }), _jsx("button", { className: "text-muted-foreground/50 hover:text-foreground hover:bg-muted inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors", onClick: handleExportCsv, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line979JsxAttrTitleExportAsCsv'), children: _jsx(Download, { className: "h-3.5 w-3.5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-hidden", children: tableData.rows.length > 0 ? (_jsx("div", { className: "h-full w-full", children: _jsx(AgGridReact, { ref: gridApiRef, theme: agTheme, rowData: tableData.rows, columnDefs: columnDefs, defaultColDef: {
|
|
686
|
+
: 'text-muted-foreground hover:bg-muted/50 hover:text-foreground'), children: [table.type === 'view' ? (_jsx(Eye, { className: "text-kortix-purple h-3.5 w-3.5 shrink-0" })) : (_jsx(Table2, { className: "text-kortix-blue h-3.5 w-3.5 shrink-0" })), _jsx("span", { className: "flex-1 truncate text-xs font-medium", children: table.name }), _jsx("span", { className: "text-muted-foreground/50 shrink-0 text-xs tabular-nums", children: table.rowCount.toLocaleString() })] }, table.name))) }), _jsxs("div", { className: "text-muted-foreground/30 border-t px-3 py-1.5 text-xs tabular-nums", children: [filteredTables.length, "/", tables.length, ' ', tHardcodedUi.raw('i18nComplete.textbaaf53622a51')] })] }), _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [viewMode === 'data' && selectedTableInfo && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex h-9 shrink-0 items-center gap-2 border-b px-3 py-1.5", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [selectedTableInfo.type === 'view' ? (_jsx(Eye, { className: "text-kortix-purple h-3.5 w-3.5 shrink-0" })) : (_jsx(Table2, { className: "text-kortix-blue h-3.5 w-3.5 shrink-0" })), _jsx("span", { className: "text-foreground truncate text-xs font-medium", children: selectedTableInfo.name }), _jsxs("span", { className: "text-muted-foreground/40 shrink-0 text-xs tabular-nums", children: [selectedTableInfo.rowCount.toLocaleString(), " \u00D7", ' ', selectedTableInfo.columns.length] })] }), _jsxs("div", { className: "ml-auto flex items-center gap-1", children: [isEditable && (_jsxs(_Fragment, { children: [_jsx("button", { className: "text-muted-foreground/50 hover:text-foreground hover:bg-muted inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors", onClick: handleAddRow, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line941JsxAttrTitleInsertRow'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }), _jsx("button", { className: "text-muted-foreground/50 hover:bg-destructive/10 hover:text-destructive inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors", onClick: handleDeleteSelected, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line948JsxAttrTitleDeleteSelectedRows'), children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }), _jsx("div", { className: "bg-border mx-0.5 h-4 w-px" })] })), _jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground/40 absolute top-1/2 left-2 h-3 w-3 -translate-y-1/2" }), _jsx(Input, { type: "text", placeholder: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line961JsxAttrPlaceholderFilter'), autoComplete: "off", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "h-7 w-40 pr-7 pl-7 text-xs" }), searchTerm && (_jsx("button", { onClick: () => setSearchTerm(''), "aria-label": tHardcodedUi.raw('i18nComplete.text83b12c2216ef'), className: "text-muted-foreground hover:text-foreground absolute top-1/2 right-2 -translate-y-1/2 cursor-pointer", children: _jsx(X, { className: "h-3 w-3" }) }))] }), _jsx("button", { className: "text-muted-foreground/50 hover:text-foreground hover:bg-muted inline-flex h-7 w-7 cursor-pointer items-center justify-center rounded-md transition-colors", onClick: handleExportCsv, title: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line979JsxAttrTitleExportAsCsv'), children: _jsx(Download, { className: "h-3.5 w-3.5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-hidden", children: tableData.rows.length > 0 ? (_jsx("div", { className: "h-full w-full", children: _jsx(AgGridReact, { ref: gridApiRef, theme: agTheme, rowData: tableData.rows, columnDefs: columnDefs, defaultColDef: {
|
|
687
687
|
sortable: true,
|
|
688
688
|
filter: true,
|
|
689
689
|
resizable: true,
|
|
@@ -723,5 +723,10 @@ export function SqliteRenderer({ filePath, fileName, className, readOnly = false
|
|
|
723
723
|
? '⌘'
|
|
724
724
|
: 'Ctrl', tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line1169JsxTextEnter')] }), _jsxs("button", { className: cn('inline-flex h-7 cursor-pointer items-center gap-1 rounded-md px-2.5 text-xs transition-colors', sqlQuery.trim()
|
|
725
725
|
? 'bg-primary text-primary-foreground hover:bg-primary/90'
|
|
726
|
-
: 'bg-muted text-muted-foreground cursor-not-allowed'), onClick: runQuery, disabled: isQueryRunning || !sqlQuery.trim(), children: [isQueryRunning ? (_jsx(Loading, { className: "h-3 w-3" })) : (_jsx(Play, { className: "h-3 w-3" })), tHardcodedUi.raw('i18nComplete.text00d60e31a4e6')] })] })] }), _jsx("textarea", { value: sqlQuery, onChange: (e) => setSqlQuery(e.target.value), onKeyDown: handleQueryKeyDown, placeholder: `SELECT * FROM "${selectedTable || 'table_name'}" LIMIT 100`, className: cn('bg-muted/30 h-24 w-full cursor-text rounded-md border px-3 py-2 font-mono text-xs', 'focus:ring-ring resize-none focus:ring-1 focus:outline-none', 'placeholder:text-muted-foreground/30'), spellCheck: false })] }), _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [queryResult?.error && (_jsxs("div", { className: "border-destructive/20 bg-destructive/5 text-destructive shrink-0 border-b px-4 py-2 font-mono text-xs select-text", children: [tHardcodedUi.raw('i18nComplete.text617062906764'), " ", queryResult.error] })), queryResult && !queryResult.error && (_jsxs("div", { className: "text-muted-foreground flex shrink-0 items-center gap-2 border-b px-3 py-1.5 text-xs", children: [_jsxs("span", { children: [queryResult.rowCount.toLocaleString(), ' ', tHardcodedUi.raw('i18nComplete.text634768dae147'), queryResult.rowCount !== 1 ? 's' : ''] }), _jsx("span", { className: "text-muted-foreground/30", children: "\u00B7" }), _jsxs("span", { children: [queryResult.time.toFixed(1), tHardcodedUi.raw('i18nComplete.textf785c3ce1d58')] })] })), queryResult && queryResult.rows.length > 0 && (_jsx("div", { className: "flex-1 overflow-hidden", children: _jsx(Suspense, { fallback: _jsx(GridFallback, {}), children: _jsx(DataGrid, { rowData: queryResult.rows, className: "h-full" }, `query-${queryResult.time}`) }) })), !queryResult && (_jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsxs("div", { className: "space-y-2 text-center", children: [_jsx(Play, { className: "text-muted-foreground/20 mx-auto h-8 w-8" }), _jsx("p", { className: "text-muted-foreground/40 text-sm", children: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line1237JsxTextWriteAQueryAndPressRun') })] }) })), queryResult && queryResult.rows.length === 0 && !queryResult.error && (_jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsxs("p", { className: "text-muted-foreground/40 text-sm", children: [tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line1246JsxTextQueryReturnedNoRows'), queryResult.time.toFixed(1), tHardcodedUi.raw('i18nComplete.text9e7d85a50dc3')] }) }))] })] }))] })] }), expandedCell && (_jsx("div", { className: "absolute inset-0 z-50 flex items-center justify-center bg-black/40 p-6 backdrop-blur-[2px]", onClick: (
|
|
726
|
+
: 'bg-muted text-muted-foreground cursor-not-allowed'), onClick: runQuery, disabled: isQueryRunning || !sqlQuery.trim(), children: [isQueryRunning ? (_jsx(Loading, { className: "h-3 w-3" })) : (_jsx(Play, { className: "h-3 w-3" })), tHardcodedUi.raw('i18nComplete.text00d60e31a4e6')] })] })] }), _jsx("textarea", { value: sqlQuery, onChange: (e) => setSqlQuery(e.target.value), onKeyDown: handleQueryKeyDown, placeholder: `SELECT * FROM "${selectedTable || 'table_name'}" LIMIT 100`, className: cn('bg-muted/30 h-24 w-full cursor-text rounded-md border px-3 py-2 font-mono text-xs', 'focus:ring-ring resize-none focus:ring-1 focus:outline-none', 'placeholder:text-muted-foreground/30'), spellCheck: false })] }), _jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [queryResult?.error && (_jsxs("div", { className: "border-destructive/20 bg-destructive/5 text-destructive shrink-0 border-b px-4 py-2 font-mono text-xs select-text", children: [tHardcodedUi.raw('i18nComplete.text617062906764'), " ", queryResult.error] })), queryResult && !queryResult.error && (_jsxs("div", { className: "text-muted-foreground flex shrink-0 items-center gap-2 border-b px-3 py-1.5 text-xs", children: [_jsxs("span", { children: [queryResult.rowCount.toLocaleString(), ' ', tHardcodedUi.raw('i18nComplete.text634768dae147'), queryResult.rowCount !== 1 ? 's' : ''] }), _jsx("span", { className: "text-muted-foreground/30", children: "\u00B7" }), _jsxs("span", { children: [queryResult.time.toFixed(1), tHardcodedUi.raw('i18nComplete.textf785c3ce1d58')] })] })), queryResult && queryResult.rows.length > 0 && (_jsx("div", { className: "flex-1 overflow-hidden", children: _jsx(Suspense, { fallback: _jsx(GridFallback, {}), children: _jsx(DataGrid, { rowData: queryResult.rows, className: "h-full" }, `query-${queryResult.time}`) }) })), !queryResult && (_jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsxs("div", { className: "space-y-2 text-center", children: [_jsx(Play, { className: "text-muted-foreground/20 mx-auto h-8 w-8" }), _jsx("p", { className: "text-muted-foreground/40 text-sm", children: tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line1237JsxTextWriteAQueryAndPressRun') })] }) })), queryResult && queryResult.rows.length === 0 && !queryResult.error && (_jsx("div", { className: "flex flex-1 items-center justify-center", children: _jsxs("p", { className: "text-muted-foreground/40 text-sm", children: [tHardcodedUi.raw('componentsFileRenderersSqliteRenderer.line1246JsxTextQueryReturnedNoRows'), queryResult.time.toFixed(1), tHardcodedUi.raw('i18nComplete.text9e7d85a50dc3')] }) }))] })] }))] })] }), expandedCell && (_jsx("div", { role: "presentation", className: "absolute inset-0 z-50 flex items-center justify-center bg-black/40 p-6 backdrop-blur-[2px]", onClick: (e) => {
|
|
727
|
+
if (e.target === e.currentTarget)
|
|
728
|
+
setExpandedCell(null);
|
|
729
|
+
else
|
|
730
|
+
e.stopPropagation();
|
|
731
|
+
}, children: _jsxs("div", { className: "bg-background border-border/60 flex max-h-[70vh] w-full max-w-xl flex-col overflow-hidden rounded-md border shadow-xl", children: [_jsxs("div", { className: "flex items-center justify-between border-b px-4 py-2.5", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("span", { className: "text-muted-foreground truncate font-mono text-xs", children: expandedCell.column }), _jsxs("span", { className: "text-muted-foreground/30 shrink-0 text-xs tabular-nums", children: [tHardcodedUi.raw('i18nComplete.text634768dae147'), " ", expandedCell.rowIndex + 1] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [isEditable && expandedEditValue !== expandedCell.value && (_jsxs(Button, { variant: "default", size: "toolbar", onClick: handleExpandedSave, children: [_jsx(Check, { className: "h-3 w-3" }), tHardcodedUi.raw('i18nComplete.text31e392d1c037')] })), _jsx(Button, { onClick: () => setExpandedCell(null), variant: "ghost", size: "icon-sm", children: _jsx(X, { className: "h-3.5 w-3.5" }) })] })] }), _jsx("div", { className: "flex-1 overflow-auto", children: isEditable ? (_jsx("textarea", { value: expandedEditValue, onChange: (e) => setExpandedEditValue(e.target.value), className: cn('h-full min-h-[180px] w-full cursor-text bg-transparent p-4 font-mono text-sm', 'resize-none focus:outline-none', 'placeholder:text-muted-foreground/20'), placeholder: "NULL", "aria-label": `${expandedCell.column} value`, spellCheck: false, autoFocus: true })) : (_jsx("pre", { className: "text-muted-foreground min-h-[180px] p-4 font-mono text-sm break-all whitespace-pre-wrap select-text", children: expandedCell.value || (_jsx("span", { className: "text-muted-foreground/30 italic", children: "NULL" })) })) }), _jsxs("div", { className: "text-muted-foreground/30 border-t px-4 py-1.5 text-xs tabular-nums", children: [expandedEditValue.length.toLocaleString(), ' ', tHardcodedUi.raw('i18nComplete.text1ce93dacbcf4')] })] }) }))] }));
|
|
727
732
|
}
|
|
@@ -508,22 +508,21 @@ const WorkbookSheetTabsInner = React.memo(function WorkbookSheetTabsInner({ acti
|
|
|
508
508
|
setThumbnailUrls({});
|
|
509
509
|
}, [clearCloseTimeout, clearOpenTimeout, workbookIdentity]);
|
|
510
510
|
React.useEffect(() => {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
}, [thumbnails]);
|
|
511
|
+
const painted = {};
|
|
512
|
+
for (const thumbnail of thumbnails) {
|
|
513
|
+
if (thumbnailUrls[thumbnail.sheetIndex])
|
|
514
|
+
continue;
|
|
515
|
+
const canvas = document.createElement('canvas');
|
|
516
|
+
canvas.width = thumbnail.width;
|
|
517
|
+
canvas.height = thumbnail.height;
|
|
518
|
+
if (thumbnail.paint(canvas))
|
|
519
|
+
painted[thumbnail.sheetIndex] = canvas.toDataURL('image/png');
|
|
520
|
+
}
|
|
521
|
+
if (Object.keys(painted).length === 0)
|
|
522
|
+
return;
|
|
523
|
+
// Existing entries win, as before: a sheet is painted once per workbook.
|
|
524
|
+
setThumbnailUrls((current) => ({ ...painted, ...current }));
|
|
525
|
+
}, [thumbnails, thumbnailUrls]);
|
|
527
526
|
React.useEffect(() => {
|
|
528
527
|
if (visiblePreviewIndex === null)
|
|
529
528
|
return;
|
|
@@ -141,7 +141,7 @@ export function FileTreeItem({ node, onClick, onDownload, onRename, onDelete, on
|
|
|
141
141
|
return;
|
|
142
142
|
onDropMove(sourcePath, node.path);
|
|
143
143
|
}, [isDropTarget, node.path, onDropMove]);
|
|
144
|
-
const content = isRenaming ? (_jsxs("div", { className: cn('flex w-full items-center gap-2 rounded-lg px-3 py-1.5 text-sm', node.ignored && 'opacity-50'), children: [getNodeIcon(node), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx("input", { type: "text", ref: renameInputRef, value: renameName, onChange: (e) => setRenameName(e.target.value), onKeyDown: (e) => {
|
|
144
|
+
const content = isRenaming ? (_jsxs("div", { className: cn('flex w-full items-center gap-2 rounded-lg px-3 py-1.5 text-sm', node.ignored && 'opacity-50'), children: [getNodeIcon(node), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx("input", { type: "text", ref: renameInputRef, "aria-label": tHardcodedUi.raw('i18nComplete.text3064d79a295c'), value: renameName, onChange: (e) => setRenameName(e.target.value), onKeyDown: (e) => {
|
|
145
145
|
if (e.nativeEvent.isComposing)
|
|
146
146
|
return;
|
|
147
147
|
if (e.key === 'Enter' && !nameConflict)
|
|
@@ -9,7 +9,7 @@ import { cn } from '../../lib/utils.js';
|
|
|
9
9
|
import { WarningIcon as AlertTriangle, BracketsCurlyIcon as Braces, CheckIcon as Check, WarningCircleIcon as CircleAlert, CodeIcon as Code, EyeIcon as Eye, GlobeIcon as Globe, ArrowCounterClockwiseIcon as RotateCcw, FloppyDiskIcon as Save } from '@phosphor-icons/react';
|
|
10
10
|
import { Download } from '../../internal/icons/download.js';
|
|
11
11
|
export function FileHeader({ showHeader, Breadcrumbs, filePath, readOnly, hasUnsavedChanges, saveFlash, fileDiagErrorCount, fileDiagWarningCount, fileContent, isSaving, handleSave, latestContentRef, discardLabel, handleDiscard, isHtmlFile, isHtmlPreview, setIsHtmlPreview, isJsonFile, isJsonTreeView, setIsJsonTreeView, hasPreviewToggle, isMarkdownPreview, setIsMarkdownPreview, headerActions, handleDownload, blobUrl, rawBlob, tI18nHardcoded, tHardcodedUi }) {
|
|
12
|
-
return (_jsx(_Fragment, { children: showHeader && (_jsxs("div", { className: "border-border/50 flex h-10 shrink-0 items-center gap-2 border-b px-3 py-1.5", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1", children: [Breadcrumbs && _jsx(Breadcrumbs, { filePath: filePath }), !readOnly && hasUnsavedChanges && (_jsxs(Badge, { variant: "warning", size: "sm", className: "shrink-0", children: [_jsx(StatusDot, { tone: "warning", pulse: true }), tI18nHardcoded.raw('i18nComplete.text7117f0807129')] })), !readOnly && saveFlash && !hasUnsavedChanges && (_jsxs(Badge, { variant: "success", size: "sm", className: "shrink-0", children: [_jsx(Check, { className: "h-3 w-3" }), tI18nHardcoded.raw('i18nComplete.textb5c120b316c2')] })), readOnly && (_jsx(Badge, { variant: "muted", size: "sm", className: "shrink-0 tracking-wider uppercase", children: tHardcodedUi.raw('featuresFilesComponentsFileContentRenderer.line554JsxTextViewOnly') })), (fileDiagErrorCount > 0 || fileDiagWarningCount > 0) && (_jsxs("span", { className: "inline-flex shrink-0 items-center gap-1.5", children: [fileDiagErrorCount > 0 && (_jsxs("span", { className: "text-destructive inline-flex items-center gap-0.5 text-xs font-medium tabular-nums", children: [_jsx(CircleAlert, { className: "h-3 w-3" }), fileDiagErrorCount] })), fileDiagWarningCount > 0 && (_jsxs("span", { className: "text-kortix-orange inline-flex items-center gap-0.5 text-xs font-medium tabular-nums", children: [_jsx(AlertTriangle, { className: "h-3 w-3" }), fileDiagWarningCount] }))] }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [!readOnly && hasUnsavedChanges && fileContent?.type === 'text' && (_jsxs(_Fragment, { children: [_jsxs(Button, { variant: "default", size: "sm", className: "h-7 gap-1.5 px-3 text-xs font-medium", onClick: () => handleSave(latestContentRef.current), disabled: isSaving, title: tHardcodedUi.raw('featuresFilesComponentsFileContentRenderer.line586JsxAttrTitleSaveS'), children: [isSaving ? (_jsx(Loading, { className: "h-3.5 w-3.5" })) : (_jsx(Save, { className: "h-3.5 w-3.5" })), tI18nHardcoded.raw('i18nComplete.text1509f561f241')] }), _jsx(Hint, { label: discardLabel, side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": discardLabel, className: "text-muted-foreground hover:text-foreground h-7 w-7 active:scale-[0.96]", onClick: handleDiscard, children: _jsx(RotateCcw, { className: "h-3.5 w-3.5" }) }) })] })), isHtmlFile && (_jsx(Hint, { label: isHtmlPreview ? tI18nHardcoded.raw('i18nComplete.text6ee818aa2de3') : 'Preview', side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": isHtmlPreview ? tI18nHardcoded.raw('i18nComplete.text6ee818aa2de3') : 'Preview', "aria-pressed": isHtmlPreview, className: cn('h-7 w-7 active:scale-[0.96]', isHtmlPreview && 'text-primary'), onClick: () => setIsHtmlPreview((v) => !v), children: isHtmlPreview ? _jsx(Code, { className: "h-4 w-4" }) : _jsx(Globe, { className: "h-4 w-4" }) }) })), isJsonFile && fileContent?.type === 'text' && (_jsx(Hint, { label: isJsonTreeView
|
|
12
|
+
return (_jsx(_Fragment, { children: showHeader && (_jsxs("div", { className: "border-border/50 flex h-10 shrink-0 items-center gap-2 border-b px-3 py-1.5", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1", children: [Breadcrumbs && _jsx(Breadcrumbs, { filePath: filePath }), !readOnly && hasUnsavedChanges && (_jsxs(Badge, { variant: "warning", size: "sm", className: "shrink-0", children: [_jsx(StatusDot, { tone: "warning", pulse: true }), tI18nHardcoded.raw('i18nComplete.text7117f0807129')] })), !readOnly && saveFlash && !hasUnsavedChanges && (_jsxs(Badge, { variant: "success", size: "sm", className: "shrink-0", children: [_jsx(Check, { className: "h-3 w-3" }), tI18nHardcoded.raw('i18nComplete.textb5c120b316c2')] })), readOnly && (_jsx(Badge, { variant: "muted", size: "sm", className: "shrink-0 tracking-wider uppercase", children: tHardcodedUi.raw('featuresFilesComponentsFileContentRenderer.line554JsxTextViewOnly') })), (fileDiagErrorCount > 0 || fileDiagWarningCount > 0) && (_jsxs("span", { className: "inline-flex shrink-0 items-center gap-1.5", children: [fileDiagErrorCount > 0 && (_jsxs("span", { className: "text-destructive inline-flex items-center gap-0.5 text-xs font-medium tabular-nums", children: [_jsx(CircleAlert, { className: "h-3 w-3" }), fileDiagErrorCount] })), fileDiagWarningCount > 0 && (_jsxs("span", { className: "text-kortix-orange inline-flex items-center gap-0.5 text-xs font-medium tabular-nums", children: [_jsx(AlertTriangle, { className: "h-3 w-3" }), fileDiagWarningCount] }))] }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [!readOnly && hasUnsavedChanges && fileContent?.type === 'text' && (_jsxs(_Fragment, { children: [_jsxs(Button, { variant: "default", size: "sm", className: "h-7 gap-1.5 px-3 text-xs font-medium", onClick: () => { void handleSave(latestContentRef.current).catch(() => undefined); }, disabled: isSaving, title: tHardcodedUi.raw('featuresFilesComponentsFileContentRenderer.line586JsxAttrTitleSaveS'), children: [isSaving ? (_jsx(Loading, { className: "h-3.5 w-3.5" })) : (_jsx(Save, { className: "h-3.5 w-3.5" })), tI18nHardcoded.raw('i18nComplete.text1509f561f241')] }), _jsx(Hint, { label: discardLabel, side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": discardLabel, className: "text-muted-foreground hover:text-foreground h-7 w-7 active:scale-[0.96]", onClick: handleDiscard, children: _jsx(RotateCcw, { className: "h-3.5 w-3.5" }) }) })] })), isHtmlFile && (_jsx(Hint, { label: isHtmlPreview ? tI18nHardcoded.raw('i18nComplete.text6ee818aa2de3') : 'Preview', side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": isHtmlPreview ? tI18nHardcoded.raw('i18nComplete.text6ee818aa2de3') : 'Preview', "aria-pressed": isHtmlPreview, className: cn('h-7 w-7 active:scale-[0.96]', isHtmlPreview && 'text-primary'), onClick: () => setIsHtmlPreview((v) => !v), children: isHtmlPreview ? _jsx(Code, { className: "h-4 w-4" }) : _jsx(Globe, { className: "h-4 w-4" }) }) })), isJsonFile && fileContent?.type === 'text' && (_jsx(Hint, { label: isJsonTreeView
|
|
13
13
|
? tI18nHardcoded.raw('i18nComplete.text6ee818aa2de3')
|
|
14
14
|
: tI18nHardcoded.raw('i18nComplete.text4f50bda41e87'), side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": isJsonTreeView
|
|
15
15
|
? tI18nHardcoded.raw('i18nComplete.text6ee818aa2de3')
|
|
@@ -60,4 +60,4 @@ export interface FilePreviewModalProps extends FilePreviewState {
|
|
|
60
60
|
* hit that path, which is why only the mouse appeared broken.)
|
|
61
61
|
* Z-index is dialog-depth aware so it always stacks above its host overlay.
|
|
62
62
|
*/
|
|
63
|
-
export declare function FilePreviewModal({ selectedFilePath, panelMode, filePathList, currentFileIndex, onClose, onNext, onPrev, source, HistoryContent, statusSlot, extraActions, shareContext, historyLabel, embedded, targetLine, }: FilePreviewModalProps): import("react").JSX.Element | null;
|
|
63
|
+
export declare function FilePreviewModal({ selectedFilePath, panelMode, filePathList, currentFileIndex, onClose: closePreview, onNext: nextPreview, onPrev: prevPreview, source, HistoryContent, statusSlot, extraActions, shareContext, historyLabel, embedded, targetLine, }: FilePreviewModalProps): import("react").JSX.Element | null;
|
|
@@ -54,9 +54,19 @@ const NO_REFRESH = {
|
|
|
54
54
|
* hit that path, which is why only the mouse appeared broken.)
|
|
55
55
|
* Z-index is dialog-depth aware so it always stacks above its host overlay.
|
|
56
56
|
*/
|
|
57
|
-
export function FilePreviewModal({ selectedFilePath, panelMode, filePathList, currentFileIndex, onClose, onNext, onPrev, source, HistoryContent, statusSlot, extraActions, shareContext, historyLabel = "History", embedded = false, targetLine = null, }) {
|
|
57
|
+
export function FilePreviewModal({ selectedFilePath, panelMode, filePathList, currentFileIndex, onClose: closePreview, onNext: nextPreview, onPrev: prevPreview, source, HistoryContent, statusSlot, extraActions, shareContext, historyLabel = "History", embedded = false, targetLine = null, }) {
|
|
58
58
|
const tI18nHardcoded = useTranslations("hardcodedUi");
|
|
59
59
|
const isOpen = panelMode === "viewer" && !!selectedFilePath;
|
|
60
|
+
const [dirty, setDirty] = useState(false);
|
|
61
|
+
const leave = (action) => {
|
|
62
|
+
if (dirty && !window.confirm('Discard unsaved changes?'))
|
|
63
|
+
return;
|
|
64
|
+
setDirty(false);
|
|
65
|
+
action();
|
|
66
|
+
};
|
|
67
|
+
const onClose = () => leave(closePreview);
|
|
68
|
+
const onNext = () => leave(nextPreview);
|
|
69
|
+
const onPrev = () => leave(prevPreview);
|
|
60
70
|
// Embedded viewers start inline (in the side panel); "Expand" pops them to
|
|
61
71
|
// the full-screen overlay. Non-embedded viewers are always full-screen.
|
|
62
72
|
const [expanded, setExpanded] = useState(false);
|
|
@@ -264,7 +274,7 @@ export function FilePreviewModal({ selectedFilePath, panelMode, filePathList, cu
|
|
|
264
274
|
: "Expand", side: "bottom", children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": expanded
|
|
265
275
|
? tI18nHardcoded.raw("i18nComplete.textde12e3c7c7a8")
|
|
266
276
|
: "Expand", "aria-pressed": expanded, className: "text-muted-foreground hover:text-foreground h-8 w-8 active:scale-[0.96]", onClick: () => setExpanded((v) => !v), children: expanded ? (_jsx(Minimize2, { className: "h-4 w-4" })) : (_jsx(Maximize2, { className: "h-4 w-4" })) }) })), _jsx(ButtonGroup, { className: "ml-1.5", children: _jsx(Hint, { label: tI18nHardcoded.raw("autoFeaturesFileViewerFilePreviewModalJsxAttrTitleClosea40d0510"), side: "bottom", children: _jsx(Button, { variant: "secondary", size: "icon-base", "aria-label": tI18nHardcoded.raw("autoFeaturesFileViewerFilePreviewModalJsxAttrTitleClosea40d0510"), className: "active:scale-[0.96]", onClick: onClose, children: _jsx(X, { className: "h-4 w-4" }) }) }) })] })] }));
|
|
267
|
-
const body = (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-full w-full overflow-hidden px-3 pt-3 pb-2", children: _jsx(FileSourceProvider, { value: source, children: _jsx(FileContentRenderer, { filePath: selectedFilePath, reloadKey: reloadKey, showHeader:
|
|
277
|
+
const body = (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-full w-full overflow-hidden px-3 pt-3 pb-2", children: _jsx(FileSourceProvider, { value: source, children: _jsx(FileContentRenderer, { filePath: selectedFilePath, reloadKey: reloadKey, onUnsavedChange: setDirty, showHeader: !!source.editablePreview, readOnly: !source.editablePreview, targetLine: targetLine, markdownPreview: markdownPreview, onMarkdownPreviewChange: setMarkdownPreview }) }) }), historyPath && (_jsx("div", { className: "bg-popover border-border/60 animate-in slide-in-from-bottom-4 fade-in-0 absolute right-4 bottom-4 z-30 overflow-hidden rounded-md border shadow-md duration-normal", children: _jsx(HistoryContent, { filePath: historyPath, onClose: () => setHistoryPath(null) }) }))] }));
|
|
268
278
|
const panelInner = (_jsxs(_Fragment, { children: [_jsx("div", { ref: toolbarRef, className: "border-border/40 bg-background/95 flex h-12 shrink-0 items-center gap-2 border-b px-3 backdrop-blur-sm", children: toolbar }), _jsx("div", { ref: contentRef, className: "relative min-h-0 flex-1 overflow-hidden", children: body })] }));
|
|
269
279
|
// Inline (embedded, not expanded): fill the relative parent — the side panel —
|
|
270
280
|
// instead of portaling to a full-screen overlay. No backdrop, no body lock.
|
|
@@ -273,7 +283,7 @@ export function FilePreviewModal({ selectedFilePath, panelMode, filePathList, cu
|
|
|
273
283
|
value0: fileName ? `: ${fileName}` : "",
|
|
274
284
|
}), tabIndex: -1, className: "bg-background animate-in fade-in-0 absolute inset-0 z-20 flex flex-col overflow-hidden duration-normal outline-none", children: panelInner }));
|
|
275
285
|
}
|
|
276
|
-
const node = (_jsxs(DialogDepthProvider, { depth: dialogDepth, children: [_jsx("div", { "data-file-preview-overlay": "", className: "animate-in fade-in-0 pointer-events-auto fixed inset-0 bg-black/50 backdrop-blur-sm duration-normal", style: { zIndex: dialogOverlayZ(dialogDepth) }, onClick: embedded ? () => setExpanded(false) : onClose }), _jsx("div", { ref: surfaceRef, "data-file-preview-overlay": "", role: "dialog", "aria-modal": "true", "aria-label": tI18nHardcoded("i18nComplete.text4a7346d46cf6", {
|
|
286
|
+
const node = (_jsxs(DialogDepthProvider, { depth: dialogDepth, children: [_jsx("div", { "data-file-preview-overlay": "", className: "animate-in fade-in-0 pointer-events-auto fixed inset-0 bg-black/50 backdrop-blur-sm duration-normal", style: { zIndex: dialogOverlayZ(dialogDepth) }, "aria-hidden": "true", onClick: embedded ? () => setExpanded(false) : onClose }), _jsx("div", { ref: surfaceRef, "data-file-preview-overlay": "", role: "dialog", "aria-modal": "true", "aria-label": tI18nHardcoded("i18nComplete.text4a7346d46cf6", {
|
|
277
287
|
value0: fileName ? `: ${fileName}` : "",
|
|
278
288
|
}), tabIndex: -1, className: "kx-fullscreen-modal border-border/60 bg-background animate-in fade-in-0 zoom-in-[0.98] pointer-events-auto fixed inset-3 flex flex-col overflow-hidden rounded-xl border shadow-lg duration-normal outline-none sm:inset-4", style: { zIndex: dialogContentZ(dialogDepth) }, children: panelInner })] }));
|
|
279
289
|
return createPortal(node, document.body);
|
|
@@ -5,6 +5,7 @@ import { type ComponentType, type ReactNode } from 'react';
|
|
|
5
5
|
* their own typed hooks without conversion.
|
|
6
6
|
*/
|
|
7
7
|
export interface FileContent {
|
|
8
|
+
revision?: string;
|
|
8
9
|
type: 'text' | 'binary';
|
|
9
10
|
content: string;
|
|
10
11
|
patch?: FilePatch;
|
|
@@ -79,7 +80,8 @@ export interface FileSource {
|
|
|
79
80
|
* instead of `upload`, so a source can refuse a save over a file someone
|
|
80
81
|
* changed since it was read (a conditional write) rather than clobber it.
|
|
81
82
|
*/
|
|
82
|
-
|
|
83
|
+
editablePreview?: boolean;
|
|
84
|
+
save?: (filePath: string, file: File, revision?: string) => Promise<unknown>;
|
|
83
85
|
/**
|
|
84
86
|
* Every byte the viewer shows comes from this source, which owns the
|
|
85
87
|
* authorization. Previewers that otherwise read a sandbox path themselves
|
|
@@ -61,6 +61,13 @@ export function useFileContentState({ filePath, onUnsavedChange, onSaved, readOn
|
|
|
61
61
|
const contentRevision = useContentRevision(fileContent);
|
|
62
62
|
const fetchRevision = useContentRevision(dataUpdatedAt || undefined);
|
|
63
63
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
|
64
|
+
// A refetch may replace server content while CodeEditor retains a dirty draft.
|
|
65
|
+
// CAS must compare against the revision that draft started from.
|
|
66
|
+
const draftRevisionRef = useRef(fileContent?.revision);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!hasUnsavedChanges)
|
|
69
|
+
draftRevisionRef.current = fileContent?.revision;
|
|
70
|
+
}, [hasUnsavedChanges, fileContent?.revision]);
|
|
64
71
|
const [isSaving, setIsSaving] = useState(false);
|
|
65
72
|
const [saveFlash, setSaveFlash] = useState(false);
|
|
66
73
|
// Tracks the latest editor content so we can save from the header button.
|
|
@@ -120,12 +127,12 @@ export function useFileContentState({ filePath, onUnsavedChange, onSaved, readOn
|
|
|
120
127
|
// HEIC conversion — converts the raw HEIC blob to a renderable JPEG URL
|
|
121
128
|
const { url: heicImageUrl, isConverting: heicConverting } = useHeicBlob(isHeicImage ? rawBlob : null, fileName);
|
|
122
129
|
const displayContent = fileContent?.content ?? '';
|
|
123
|
-
//
|
|
130
|
+
// Refresh clean content only; header Save must keep the visible dirty draft.
|
|
124
131
|
useEffect(() => {
|
|
125
|
-
if (
|
|
126
|
-
latestContentRef.current = fileContent
|
|
132
|
+
if (!hasUnsavedChanges) {
|
|
133
|
+
latestContentRef.current = fileContent?.content ?? '';
|
|
127
134
|
}
|
|
128
|
-
}, [fileContent?.content]);
|
|
135
|
+
}, [fileContent?.content, hasUnsavedChanges]);
|
|
129
136
|
// Reset state when the FILE changes — markdown defaults to rendered preview.
|
|
130
137
|
//
|
|
131
138
|
// `setIsMarkdownPreview` MUST NOT be a dependency here, and this effect must
|
|
@@ -167,15 +174,17 @@ export function useFileContentState({ filePath, onUnsavedChange, onSaved, readOn
|
|
|
167
174
|
// Save handler — called by CodeEditor (Cmd+S) and by the header Save button.
|
|
168
175
|
// When called from the header button we pass latestContentRef.current.
|
|
169
176
|
// When called from CodeEditor's Cmd+S, CodeEditor passes its own localContent.
|
|
177
|
+
const draftGeneration = useRef(0);
|
|
170
178
|
const handleSave = useCallback(async (content) => {
|
|
171
179
|
if (readOnly)
|
|
172
180
|
return;
|
|
181
|
+
const generation = draftGeneration.current;
|
|
173
182
|
setIsSaving(true);
|
|
174
183
|
try {
|
|
175
184
|
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
|
|
176
185
|
const file = new File([blob], fileName, { type: 'text/plain' });
|
|
177
186
|
if (source.save) {
|
|
178
|
-
await source.save(filePath, file);
|
|
187
|
+
await source.save(filePath, file, draftRevisionRef.current);
|
|
179
188
|
}
|
|
180
189
|
else {
|
|
181
190
|
const parentPath = filePath.substring(0, filePath.lastIndexOf('/'));
|
|
@@ -184,7 +193,15 @@ export function useFileContentState({ filePath, onUnsavedChange, onSaved, readOn
|
|
|
184
193
|
// Refetch so fileContent.content (= originalContent for CodeEditor) updates.
|
|
185
194
|
// CodeEditor's originalContent effect will then sync savedContent.current
|
|
186
195
|
// to match localContent, clearing its internal hasChanges flag.
|
|
187
|
-
await refetch();
|
|
196
|
+
const refreshed = await refetch();
|
|
197
|
+
if (refreshed && typeof refreshed === 'object' && 'data' in refreshed) {
|
|
198
|
+
const data = refreshed.data;
|
|
199
|
+
if (data && typeof data === 'object' && 'revision' in data && typeof data.revision === 'string') {
|
|
200
|
+
draftRevisionRef.current = data.revision;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (draftGeneration.current !== generation)
|
|
204
|
+
return;
|
|
188
205
|
setHasUnsavedChanges(false);
|
|
189
206
|
setSaveFlash(true);
|
|
190
207
|
if (saveFlashTimerRef.current)
|
|
@@ -199,11 +216,12 @@ export function useFileContentState({ filePath, onUnsavedChange, onSaved, readOn
|
|
|
199
216
|
? err.message
|
|
200
217
|
: tI18nHardcoded.raw('i18nComplete.text27c2ccd962c2'),
|
|
201
218
|
}));
|
|
219
|
+
throw err;
|
|
202
220
|
}
|
|
203
221
|
finally {
|
|
204
222
|
setIsSaving(false);
|
|
205
223
|
}
|
|
206
|
-
}, [filePath, fileName, refetch, onSaved, readOnly, source]);
|
|
224
|
+
}, [filePath, fileName, refetch, onSaved, readOnly, source, tHardcodedUi, tI18nHardcoded]);
|
|
207
225
|
// Discard handler — force-remounts CodeEditor so it re-initialises from fileContent.content.
|
|
208
226
|
const handleDiscard = useCallback(() => {
|
|
209
227
|
if (readOnly)
|
|
@@ -216,6 +234,7 @@ export function useFileContentState({ filePath, onUnsavedChange, onSaved, readOn
|
|
|
216
234
|
const handleEditorChange = useCallback((content) => {
|
|
217
235
|
if (readOnly)
|
|
218
236
|
return;
|
|
237
|
+
draftGeneration.current++;
|
|
219
238
|
latestContentRef.current = content;
|
|
220
239
|
}, [readOnly]);
|
|
221
240
|
// Cmd+S handler for when CodeEditor is not mounted (e.g. markdown preview)
|
|
@@ -226,7 +245,7 @@ export function useFileContentState({ filePath, onUnsavedChange, onSaved, readOn
|
|
|
226
245
|
if ((e.metaKey || e.ctrlKey) && e.key === 's') {
|
|
227
246
|
e.preventDefault();
|
|
228
247
|
if (hasUnsavedChanges && latestContentRef.current) {
|
|
229
|
-
handleSave(latestContentRef.current);
|
|
248
|
+
void handleSave(latestContentRef.current).catch(() => undefined);
|
|
230
249
|
}
|
|
231
250
|
}
|
|
232
251
|
};
|
|
@@ -148,8 +148,8 @@ function expiryLabel(expiresAt) {
|
|
|
148
148
|
/**
|
|
149
149
|
* `Copy link` and everything about the link behind it, in one popover.
|
|
150
150
|
*
|
|
151
|
-
* A file or app mint always makes a NEW public token
|
|
152
|
-
*
|
|
151
|
+
* A file or app mint always makes a NEW public token, so the popover reads
|
|
152
|
+
* the session's live shares first:
|
|
153
153
|
*
|
|
154
154
|
* - a live link for this exact file or port → show it, copy it, see when it
|
|
155
155
|
* expires, revoke it;
|