@kortix/ui 0.14.9 → 0.14.10
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 +55 -2
- package/dist/_vendor/shared/artifact-comments.d.ts +235 -0
- package/dist/_vendor/shared/channel-descriptors.d.ts +96 -0
- package/dist/_vendor/shared/channel-message.d.ts +13 -2
- package/dist/_vendor/shared/index.d.ts +1 -0
- package/dist/apps/app-preview-pool.js +19 -2
- package/dist/artifacts/artifact-frame.js +7 -3
- package/dist/customize/sections/component/channel-access-panel.js +4 -4
- package/dist/customize/sections/component/telegram-channel-row.js +7 -5
- package/dist/customize/sections/view/agent-editor-catalog.js +5 -0
- package/dist/customize/sections/view/channels-view.d.ts +2 -1
- package/dist/customize/sections/view/channels-view.js +12 -7
- package/dist/customize/settings/rail.js +9 -0
- package/dist/customize/settings/settings-tabs.d.ts +1 -1
- package/dist/customize/settings/settings-tabs.js +1 -0
- package/dist/customize/settings/tabs/chrome-connections-tab.d.ts +6 -0
- package/dist/customize/settings/tabs/chrome-connections-tab.js +99 -0
- package/dist/customize/shared/catalog/catalog-empty-state.d.ts +3 -3
- package/dist/customize/shared/catalog/catalog-empty-state.js +6 -4
- package/dist/files/renderers/image-frame.d.ts +3 -1
- package/dist/files/renderers/image-frame.js +2 -2
- package/dist/i18n/en.d.ts +189 -0
- package/dist/i18n/en.js +190 -1
- package/dist/internal/apps-and-extensions/apps-modal.d.ts +9 -0
- package/dist/internal/apps-and-extensions/apps-modal.js +107 -0
- package/dist/internal/chrome/browser-icon.d.ts +24 -0
- package/dist/internal/chrome/browser-icon.js +58 -0
- package/dist/internal/chrome/chrome-card-state.d.ts +16 -0
- package/dist/internal/chrome/chrome-card-state.js +9 -0
- package/dist/internal/chrome/chrome-connect.d.ts +69 -0
- package/dist/internal/chrome/chrome-connect.js +178 -0
- package/dist/internal/chrome/chrome-mock.d.ts +4 -0
- package/dist/internal/chrome/chrome-mock.js +15 -0
- package/dist/internal/chrome/chrome-names.d.ts +15 -0
- package/dist/internal/chrome/chrome-names.js +35 -0
- package/dist/internal/chrome/extension.d.ts +47 -0
- package/dist/internal/chrome/extension.js +91 -0
- package/dist/internal/chrome/use-chrome-offered.d.ts +11 -0
- package/dist/internal/chrome/use-chrome-offered.js +22 -0
- package/dist/internal/connector-logo/connector-logo-source.d.ts +2 -1
- package/dist/internal/connector-logo/connector-logo-source.js +7 -6
- package/dist/internal/icons/edge.d.ts +5 -0
- package/dist/internal/icons/edge.js +10 -0
- package/dist/internal/lib/browser-noise/rules/extensions.js +17 -3
- package/dist/internal/lib/detect-os.d.ts +43 -0
- package/dist/internal/lib/detect-os.js +70 -0
- package/dist/internal/lib/use-project-feature-flags.js +5 -1
- package/dist/internal/stores/apps-modal-store.d.ts +8 -0
- package/dist/internal/stores/apps-modal-store.js +6 -0
- package/dist/internal/stores/composer-prefill-store.d.ts +12 -5
- package/dist/markdown/setup-links/approval-decision.js +3 -1
- package/dist/primitives/empty-state.d.ts +2 -2
- package/dist/primitives/empty-state.js +6 -5
- package/dist/primitives/mermaid-renderer.js +1 -1
- package/dist/session/panel/session-audit-shared.js +3 -1
- package/dist/session/participants/session-participants.d.ts +3 -1
- package/dist/session/participants/session-participants.js +2 -2
- package/dist/session/prompts/approval-request.js +2 -0
- package/dist/session/thread/session-thread.d.ts +13 -1
- package/dist/session/thread/session-thread.js +15 -5
- package/dist/session/thread/session-transcript-class.d.ts +5 -1
- package/dist/session/thread/session-transcript-class.js +5 -1
- package/dist/session/tool/tools/image-gen-tool.js +4 -3
- package/dist/session/turn/user-message.d.ts +7 -5
- package/dist/session/turn/user-message.js +14 -8
- package/dist/styles.css +1 -1
- package/dist/workspace/sessions/session-label-badges.js +2 -1
- package/dist/workspace/sidebar/footer/project-chrome-nav.d.ts +10 -0
- package/dist/workspace/sidebar/footer/project-chrome-nav.js +56 -0
- package/dist/workspace/sidebar/project-sidebar.js +5 -1
- package/package.json +43 -3
- package/skills/kortix-ui/references/modules.md +1 -1
|
@@ -108,6 +108,7 @@ import { useEffect, useMemo, useState } from 'react';
|
|
|
108
108
|
import { useTunnelConnections } from '@kortix/sdk/react';
|
|
109
109
|
import { ComputerHero } from '../../connectors/detail/computer-app-page.js';
|
|
110
110
|
import { FeatureGateScreen } from '../../shared/feature-gate-screen.js';
|
|
111
|
+
import { CHANNEL_PLATFORM_IDS, CHANNELS, isChannelPlatform, } from '../../../_vendor/kortix-shared.js';
|
|
111
112
|
export function ChannelsSection({ projectId, platform }) {
|
|
112
113
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
113
114
|
useTeamsInstallReturnToast();
|
|
@@ -137,7 +138,7 @@ export function ChannelsSection({ projectId, platform }) {
|
|
|
137
138
|
// platform, the Channels tab every platform, one under the other.
|
|
138
139
|
const platforms = platform
|
|
139
140
|
? [platform]
|
|
140
|
-
:
|
|
141
|
+
: CHANNEL_PLATFORM_IDS.filter((pf) => pf !== 'email' || emailEnabled);
|
|
141
142
|
// The Kortix tab also holds the computer, where this deployment can pair one
|
|
142
143
|
// (the machine list answers 503 where computers are off).
|
|
143
144
|
const computersEnabled = useTunnelConnections({ refetchInterval: false }).isSuccess;
|
|
@@ -153,6 +154,11 @@ export function ChannelsSection({ projectId, platform }) {
|
|
|
153
154
|
return _jsx(EmailHero, { projectId: projectId, canWrite: canWrite });
|
|
154
155
|
case 'telegram':
|
|
155
156
|
return _jsx(TelegramChannelRow, { projectId: projectId, canWrite: canWrite });
|
|
157
|
+
default: {
|
|
158
|
+
// A new channel id fails here until it has a hero.
|
|
159
|
+
const _exhaustive = pf;
|
|
160
|
+
return _exhaustive;
|
|
161
|
+
}
|
|
156
162
|
}
|
|
157
163
|
};
|
|
158
164
|
// The Email page with the flag off: the standard flag-off screen, with its enable action.
|
|
@@ -190,14 +196,15 @@ function ChannelsButton({ count, onOpen }) {
|
|
|
190
196
|
}
|
|
191
197
|
/**
|
|
192
198
|
* What follows a connected Slack before its first channel: the one-time "now
|
|
193
|
-
* do this in Slack" nudge. It retires itself as soon as
|
|
194
|
-
*
|
|
199
|
+
* do this in Slack" nudge. It retires itself as soon as a Slack channel is
|
|
200
|
+
* bound: that is proof the user already invited the bot and mentioned it,
|
|
195
201
|
* and from then on the Slack row's "N channels" opens the bindings dialog.
|
|
202
|
+
* Another platform's row (a Telegram chat's `/model`) proves nothing about Slack.
|
|
196
203
|
*/
|
|
197
204
|
function SlackFollowUp({ projectId }) {
|
|
198
205
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
199
206
|
const bindingsQuery = useChannelBindings(projectId);
|
|
200
|
-
const bindings = bindingsQuery.data?.bindings ?? [];
|
|
207
|
+
const bindings = (bindingsQuery.data?.bindings ?? []).filter((b) => b.platform === 'slack');
|
|
201
208
|
return bindings.length === 0 && !bindingsQuery.isLoading ? (_jsxs(InfoBanner, { tone: "neutral", icon: AtIcon, title: tI18nComplete.raw('textd63af8edd3d6'), children: [tI18nComplete.raw('text1fd9ae1607aa'), ' ', _jsx("span", { className: "text-foreground font-medium", children: tI18nComplete.raw('text476b90bdc143') }), ' ', tI18nComplete.raw('textb81b729b4538')] })) : null;
|
|
202
209
|
}
|
|
203
210
|
/**
|
|
@@ -249,7 +256,7 @@ function ChannelBindingsDialog({ projectId, canWrite, platform, open, onOpenChan
|
|
|
249
256
|
return (_jsx(Modal, { open: open, onOpenChange: onOpenChange, children: selected ? (_jsx(ChannelSettingsModalContent, { projectId: projectId, binding: selected.binding, name: selected.name, scope: selected.scope, projectDefaultAgent: projectDefaultAgent, canWrite: canWrite, onBack: back })) : (_jsxs(ModalContent, { className: "lg:max-w-lg", children: [_jsxs(ModalHeader, { children: [_jsx(ModalTitle, { children: tI18nComplete.raw('text5f61b63c2c4a') }), _jsx(ModalDescription, { children: tI18nComplete.raw('text1f2550ed44dc') })] }), _jsxs(ModalBody, { className: "space-y-3 pt-4", children: [tabs.length > 1 ? (_jsx(Tabs, { value: active, onValueChange: (value) => {
|
|
250
257
|
setTab(value);
|
|
251
258
|
setQuery('');
|
|
252
|
-
}, children: _jsx(TabsListCompact, { children: tabs.map((t) => (_jsxs(TabsTriggerCompact, { value: t.platform, className: "gap-1.5", children: [
|
|
259
|
+
}, children: _jsx(TabsListCompact, { children: tabs.map((t) => (_jsxs(TabsTriggerCompact, { value: t.platform, className: "gap-1.5", children: [isChannelPlatform(t.platform) ? CHANNELS[t.platform].label : t.platform, _jsx("span", { className: "text-muted-foreground tabular-nums", children: t.count })] }, t.platform))) }) })) : null, inTab.length >= BINDING_SEARCH_MIN ? (_jsxs(InputGroupSearch, { children: [_jsx(InputGroupSearchIcon, { children: _jsx(MagnifyingGlassIcon, {}) }), _jsx(InputGroupSearchInput, { placeholder: tI18nComplete.raw('text49c266baaaa7'), value: query, onChange: (e) => setQuery(e.target.value), size: "sm" }), _jsx(InputGroupSearchClear, { onClick: () => setQuery('') })] })) : null, bindingsQuery.isLoading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-12 rounded-md" }), _jsx(Skeleton, { className: "h-12 rounded-md" })] })) : visible.length === 0 ? (_jsx("p", { className: "text-muted-foreground px-3 py-6 text-center text-xs", children: tI18nComplete.raw('texte8dd87902b91') })) : (
|
|
253
260
|
// The list scrolls; the tabs and search above it stay put. Capped at
|
|
254
261
|
// the viewport less ~21rem of header, tabs, search and footer, so
|
|
255
262
|
// the footer stays on screen at the 720 × 480 desktop minimum,
|
|
@@ -262,8 +269,6 @@ function ChannelBindingsDialog({ projectId, canWrite, platform, open, onOpenChan
|
|
|
262
269
|
_jsx(BindingOverrides, { binding: binding, policies: conversationPolicies }, "overrides"),
|
|
263
270
|
], onClick: () => setSelectedId(binding.bindingId) }, binding.bindingId))) }))] }), _jsx(ModalFooter, { className: "pt-2 pb-5", children: _jsx(Button, { type: "button", variant: "outline-ghost", onClick: () => onOpenChange(false), children: tI18nComplete.raw('text11a6767d5674') }) })] })) }));
|
|
264
271
|
}
|
|
265
|
-
/** Brand names, as the platform rows spell them. */
|
|
266
|
-
const PLATFORM_NAMES = { slack: 'Slack', teams: 'Microsoft Teams' };
|
|
267
272
|
/** A row's settings at a glance: only what overrides the project, else "Project default". */
|
|
268
273
|
function BindingOverrides({ binding, policies, }) {
|
|
269
274
|
const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ArrowCircleUpIcon as ArrowUpCircle, ChatCircleIcon as ChatCircle, CoinsIcon as Coins, ShippingContainerIcon as Container, CreditCardIcon as CreditCard, FlaskIcon as Flask, KeyIcon as Key, LaptopIcon as Laptop, LinkIcon as Link, PaletteIcon as Palette, ShieldCheckIcon as ShieldCheck, SlidersHorizontalIcon as SlidersHorizontal, SquaresFourIcon as SquaresFour, UserIcon as User, } from '@phosphor-icons/react';
|
|
2
2
|
import { Mcp } from '../../internal/icons/mcp.js';
|
|
3
|
+
import { ChromeRailIcon } from '../../internal/chrome/browser-icon.js';
|
|
3
4
|
/**
|
|
4
5
|
* Whether a rail item is the active one for the current settings tab.
|
|
5
6
|
*
|
|
@@ -64,6 +65,14 @@ const STATIC_GROUPS = [
|
|
|
64
65
|
description: 'Language and keyboard shortcuts.',
|
|
65
66
|
icon: SlidersHorizontal,
|
|
66
67
|
},
|
|
68
|
+
{
|
|
69
|
+
tab: 'chrome',
|
|
70
|
+
label: 'Kortix in Chrome',
|
|
71
|
+
description: 'Your sessions use Chrome with your logins. You see every step.',
|
|
72
|
+
docsHref: '/docs/connect/chrome',
|
|
73
|
+
// Monochrome like its neighbours; `ChromeRailIcon` takes only `className`.
|
|
74
|
+
icon: ChromeRailIcon,
|
|
75
|
+
},
|
|
67
76
|
// Labelled "API keys", routed at `/settings/tokens`. The id has to be
|
|
68
77
|
// `tokens` — it is the URL segment, and the account page already spends
|
|
69
78
|
// `api-keys` on a legacy redirect (`RENAMED` in `settings-tabs.ts`) —
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SettingsTab = 'profile' | 'security' | 'appearance' | 'sessions' | 'preferences' | 'connected' | 'tokens' | 'plan' | 'credits' | 'workspace' | 'sandbox' | 'feature-flags' | 'upgrades' | 'mcp' | 'computer';
|
|
1
|
+
export type SettingsTab = 'profile' | 'security' | 'appearance' | 'sessions' | 'preferences' | 'connected' | 'chrome' | 'tokens' | 'plan' | 'credits' | 'workspace' | 'sandbox' | 'feature-flags' | 'upgrades' | 'mcp' | 'computer';
|
|
2
2
|
/**
|
|
3
3
|
* The default must be a tab that survives every gate, or the overlay opens on
|
|
4
4
|
* nothing. It was `general` until project configuration moved to
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings → Kortix in Chrome: the browsers this person connected with the
|
|
3
|
+
* Kortix extension. With none, the three connect steps stand inline and the
|
|
4
|
+
* connect action sits in the page header.
|
|
5
|
+
*/
|
|
6
|
+
export declare function ChromeConnectionsTab(): import("react").JSX.Element;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useChromeConnections, useDeleteChromeConnection, useUpdateChromeConnection } from '@kortix/sdk/react';
|
|
4
|
+
import { PencilSimpleIcon } from '@phosphor-icons/react';
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
import { Button } from '../../../primitives/button.js';
|
|
7
|
+
import { ConfirmDialog } from '../../../primitives/confirm-dialog.js';
|
|
8
|
+
import { InlineMeta } from '../../../primitives/inline-meta.js';
|
|
9
|
+
import { Input } from '../../../primitives/input.js';
|
|
10
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '../../../primitives/select.js';
|
|
11
|
+
import { SettingsRow, SettingsRowGroup } from '../../../primitives/settings-row.js';
|
|
12
|
+
import { SettingsSubsectionHeader } from '../../../primitives/settings-subsection-header.js';
|
|
13
|
+
import { Skeleton } from '../../../primitives/skeleton.js';
|
|
14
|
+
import { errorToast, successToast } from '../../../primitives/toast.js';
|
|
15
|
+
import { ErrorState } from '../../../primitives/error-state.js';
|
|
16
|
+
import { SettingsTabHeader } from '../settings-tab-header.js';
|
|
17
|
+
import { useLocale, useTranslations } from '../../../i18n/index.js';
|
|
18
|
+
import { relativeTime } from '../../../internal/lib/relative-time.js';
|
|
19
|
+
import { ChromeButtonMark, ChromeConnectModal, ChromeConnectSteps, ChromeCopyLink, ChromeInstallActions, ChromeOnlineDot, useChromeConnect, } from '../../../internal/chrome/chrome-connect.js';
|
|
20
|
+
import { BrowserLogoTile } from '../../../internal/chrome/browser-icon.js';
|
|
21
|
+
import { chromeDisplayNames, offlineLongerThan } from '../../../internal/chrome/chrome-names.js';
|
|
22
|
+
import { ChromeMock } from '../../../internal/chrome/chrome-mock.js';
|
|
23
|
+
const ACCESS_MODES = ['always', 'ask', 'off'];
|
|
24
|
+
// `all` first: it is the recommended default.
|
|
25
|
+
const TAB_SCOPES = ['all', 'own'];
|
|
26
|
+
/** Offline longer than this shows when the browser was last seen. Shorter is just "Offline". */
|
|
27
|
+
const LAST_SEEN_AFTER_MS = 10 * 60_000;
|
|
28
|
+
/**
|
|
29
|
+
* Settings → Kortix in Chrome: the browsers this person connected with the
|
|
30
|
+
* Kortix extension. With none, the three connect steps stand inline and the
|
|
31
|
+
* connect action sits in the page header.
|
|
32
|
+
*/
|
|
33
|
+
export function ChromeConnectionsTab() {
|
|
34
|
+
const t = useTranslations('chrome');
|
|
35
|
+
const connections = useChromeConnections();
|
|
36
|
+
const [connectOpen, setConnectOpen] = useState(false);
|
|
37
|
+
const list = connections.data ?? [];
|
|
38
|
+
if (connections.isSuccess && list.length === 0)
|
|
39
|
+
return _jsx(ChromeEmptyTab, {});
|
|
40
|
+
const names = chromeDisplayNames(list);
|
|
41
|
+
return (
|
|
42
|
+
// `max-w-2xl`: the form tier every person-scoped pane in this dialog uses.
|
|
43
|
+
_jsxs("div", { className: "mx-auto w-full max-w-2xl space-y-5", children: [_jsx(SettingsTabHeader, { tab: "chrome", action: list.length > 0 ? (_jsxs(Button, { size: "sm", variant: "secondary", className: "gap-1.5", onClick: () => setConnectOpen(true), children: [_jsx(ChromeButtonMark, {}), t('connectAnother')] })) : undefined }), connections.isPending ? (_jsx("div", { className: "space-y-2", children: _jsx(Skeleton, { className: "h-24 rounded-md" }) })) : connections.isError ? (_jsx(ErrorState, { size: "sm", title: t('loadFailed'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => connections.refetch(), children: t('retry') }) })) : (_jsxs(_Fragment, { children: [_jsxs("section", { className: "space-y-3", children: [_jsx(SettingsSubsectionHeader, { title: t('listTitle') }), _jsx("ul", { className: "space-y-3", children: list.map((chrome) => (_jsx(ChromeRow, { chrome: chrome, displayName: names.get(chrome.id) ?? chrome.name }, chrome.id))) })] }), _jsxs("section", { className: "space-y-2", children: [_jsx(SettingsSubsectionHeader, { title: t('how.title') }), _jsxs("ul", { className: "text-muted-foreground list-disc space-y-1 pl-5 text-sm text-pretty", children: [_jsx("li", { children: t('how.group') }), _jsx("li", { children: t('how.control') }), _jsx("li", { children: t('how.own') })] })] })] })), _jsx(ChromeConnectModal, { open: connectOpen, onOpenChange: setConnectOpen, fresh: true })] }));
|
|
44
|
+
}
|
|
45
|
+
/** No browser yet: the steps stand inline, the one action is in the header. */
|
|
46
|
+
function ChromeEmptyTab() {
|
|
47
|
+
const state = useChromeConnect();
|
|
48
|
+
return (_jsxs("div", { className: "mx-auto w-full max-w-2xl space-y-5", children: [_jsx(SettingsTabHeader, { tab: "chrome", action: state.environment === 'unsupported' ? (_jsx(ChromeCopyLink, {})) : (_jsx(ChromeInstallActions, { state: state, showGuide: false })) }), _jsxs("div", { className: "space-y-4", children: [_jsx(ChromeMock, { className: "mx-auto max-w-md" }), _jsx("div", { className: "bg-popover flex flex-col gap-5 rounded-md border px-4 py-5", children: _jsx(ChromeConnectSteps, { state: state, showActions: false }) })] })] }));
|
|
49
|
+
}
|
|
50
|
+
/** "Chromium on macOS · Work · v1.0.0": what tells two browsers apart. The name is not repeated. */
|
|
51
|
+
function chromeMeta(chrome, displayName) {
|
|
52
|
+
// The profile label already sits in the display name of a duplicate: say it once.
|
|
53
|
+
const profile = chrome.profileLabel && !displayName.includes(chrome.profileLabel) ? chrome.profileLabel : null;
|
|
54
|
+
return [profile, chrome.extensionVersion ? `v${chrome.extensionVersion}` : null].filter((part) => Boolean(part));
|
|
55
|
+
}
|
|
56
|
+
function ChromeRow({ chrome, displayName }) {
|
|
57
|
+
const t = useTranslations('chrome');
|
|
58
|
+
const locale = useLocale();
|
|
59
|
+
const update = useUpdateChromeConnection();
|
|
60
|
+
const remove = useDeleteChromeConnection();
|
|
61
|
+
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
62
|
+
const [draft, setDraft] = useState(null);
|
|
63
|
+
const save = (change) => update.mutate({ id: chrome.id, ...change }, { onError: () => errorToast(t('updateFailed')) });
|
|
64
|
+
const commitName = () => {
|
|
65
|
+
const name = draft?.trim();
|
|
66
|
+
// An empty name is not a name: keep the field open and flag it. Blur reverts.
|
|
67
|
+
if (!name)
|
|
68
|
+
return false;
|
|
69
|
+
setDraft(null);
|
|
70
|
+
if (name !== chrome.name)
|
|
71
|
+
save({ name });
|
|
72
|
+
return true;
|
|
73
|
+
};
|
|
74
|
+
const sessions = chrome.activeSessions.length;
|
|
75
|
+
// "Last seen just now" beside "Offline" contradicts itself: say it only once it is a while ago.
|
|
76
|
+
const longOffline = !chrome.online && offlineLongerThan(chrome.lastSeenAt, LAST_SEEN_AFTER_MS);
|
|
77
|
+
const status = chrome.online
|
|
78
|
+
? t('online')
|
|
79
|
+
: longOffline
|
|
80
|
+
? t('lastSeen', { time: relativeTime(chrome.lastSeenAt, locale) })
|
|
81
|
+
: t('offline');
|
|
82
|
+
const meta = [...chromeMeta(chrome, displayName), status];
|
|
83
|
+
return (_jsxs("li", { children: [_jsxs(SettingsRowGroup, { children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-3", children: [_jsx(BrowserLogoTile, { brand: chrome.brand }), _jsxs("div", { className: "min-w-0 flex-1 space-y-0.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ChromeOnlineDot, { online: chrome.online }), draft === null ? (_jsxs("button", { type: "button", "aria-label": t('rename', { name: displayName }), title: displayName, className: "focus-visible:ring-ring/50 -mx-1 flex min-w-0 items-center gap-1.5 rounded-sm px-1 text-left outline-none focus-visible:ring-3", onClick: () => setDraft(chrome.name), children: [_jsx("span", { className: "truncate text-sm font-medium", children: displayName }), _jsx(PencilSimpleIcon, { className: "text-muted-foreground size-3.5 shrink-0" })] })) : (_jsx(Input, { autoFocus: true, value: draft, maxLength: 255, "aria-label": t('renameLabel'), className: "h-6 py-0", "aria-invalid": draft.trim() === '' ? true : undefined, onChange: (event) => setDraft(event.target.value), onBlur: () => {
|
|
84
|
+
if (!commitName())
|
|
85
|
+
setDraft(null);
|
|
86
|
+
}, onKeyDown: (event) => {
|
|
87
|
+
if (event.key === 'Enter')
|
|
88
|
+
commitName();
|
|
89
|
+
// Closes the field only. The settings dialog ignores Escape from a text field.
|
|
90
|
+
if (event.key === 'Escape')
|
|
91
|
+
setDraft(null);
|
|
92
|
+
} }))] }), _jsxs(InlineMeta, { children: [meta, sessions > 0 ? t('usedBy', { count: sessions }) : ''] })] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setConfirmOpen(true), children: t('disconnect') })] }), _jsx(SettingsRow, { label: t('access.label'), description: t('access.description'), children: _jsxs(Select, { value: chrome.accessMode, disabled: update.isPending, onValueChange: (value) => save({ accessMode: value }), children: [_jsx(SelectTrigger, { size: "sm", className: "w-44", "aria-label": t('access.label'), children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: ACCESS_MODES.map((mode) => (_jsx(SelectItem, { value: mode, children: t(`access.${mode}`) }, mode))) })] }) }), _jsx(SettingsRow, { label: t('scope.label'), description: t('scope.description'), children: _jsxs(Select, { value: chrome.tabScope, disabled: update.isPending, onValueChange: (value) => save({ tabScope: value }), children: [_jsx(SelectTrigger, { size: "sm", className: "w-44", "aria-label": t('scope.label'), children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: TAB_SCOPES.map((scope) => (_jsx(SelectItem, { value: scope, children: t(`scope.${scope}`) }, scope))) })] }) })] }), _jsx(ConfirmDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, title: t('disconnectTitle', { name: displayName }), description: _jsxs(_Fragment, { children: [_jsx("span", { className: "text-muted-foreground mb-2 block text-xs", children: meta.join(' · ') }), t('disconnectDescription')] }), confirmLabel: t('disconnect'), confirmVariant: "destructive", isPending: remove.isPending, onConfirm: () => remove.mutate(chrome.id, {
|
|
93
|
+
onSuccess: () => {
|
|
94
|
+
setConfirmOpen(false);
|
|
95
|
+
successToast(t('disconnected'));
|
|
96
|
+
},
|
|
97
|
+
onError: () => errorToast(t('disconnectFailed')),
|
|
98
|
+
}) })] }));
|
|
99
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
/**
|
|
3
|
-
* The "nothing here"
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* The "nothing here" state every catalog uses: the shared `EmptyState`, so a
|
|
4
|
+
* catalog's empty slot looks like every other empty view. `CatalogGrid` owns
|
|
5
|
+
* loading/error/empty; this is what callers put IN the empty slot when the
|
|
6
6
|
* cause is the search box rather than an empty project.
|
|
7
7
|
*/
|
|
8
8
|
export declare function CatalogEmptyNote({ children }: {
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { MagnifyingGlassIcon } from '@phosphor-icons/react';
|
|
2
3
|
import { useTranslations } from '../../../i18n/index.js';
|
|
4
|
+
import { EmptyState } from '../../../primitives/empty-state.js';
|
|
3
5
|
/**
|
|
4
|
-
* The "nothing here"
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* The "nothing here" state every catalog uses: the shared `EmptyState`, so a
|
|
7
|
+
* catalog's empty slot looks like every other empty view. `CatalogGrid` owns
|
|
8
|
+
* loading/error/empty; this is what callers put IN the empty slot when the
|
|
7
9
|
* cause is the search box rather than an empty project.
|
|
8
10
|
*/
|
|
9
11
|
export function CatalogEmptyNote({ children }) {
|
|
10
|
-
return _jsx(
|
|
12
|
+
return _jsx(EmptyState, { size: "sm", icon: MagnifyingGlassIcon, title: children });
|
|
11
13
|
}
|
|
12
14
|
/**
|
|
13
15
|
* "No matches for `<query>`."
|
|
@@ -27,6 +27,8 @@ export interface ImageFrameProps {
|
|
|
27
27
|
naturalRatio?: string | null;
|
|
28
28
|
/** Reports the image's natural size once it decoded. */
|
|
29
29
|
onNaturalSize?: (width: number, height: number) => void;
|
|
30
|
+
/** Drawn over the frame's own box (an overlay on the image's corner), which narrows with `maxHeight`. */
|
|
31
|
+
children?: ReactNode;
|
|
30
32
|
}
|
|
31
33
|
/**
|
|
32
34
|
* The box an image takes before, while and after it exists: a flat `bg-muted`
|
|
@@ -35,7 +37,7 @@ export interface ImageFrameProps {
|
|
|
35
37
|
* The frame itself never moves: the busy signal is the label (one waiting
|
|
36
38
|
* channel, kortix-brand `layout.md` States).
|
|
37
39
|
*/
|
|
38
|
-
export declare function ImageFrame({ aspectRatio, src, alt, pending, label, onOpen, className, fill, maxHeight, openLabel, naturalRatio, onNaturalSize, }: ImageFrameProps): import("react").JSX.Element;
|
|
40
|
+
export declare function ImageFrame({ aspectRatio, src, alt, pending, label, onOpen, className, fill, maxHeight, openLabel, naturalRatio, onNaturalSize, children, }: ImageFrameProps): import("react").JSX.Element;
|
|
39
41
|
/**
|
|
40
42
|
* An image whose file could not be read: "Image unavailable" and Try again,
|
|
41
43
|
* centered in the frame. Never the read's own error text (R38): that is
|
|
@@ -16,7 +16,7 @@ function ratioValue(ratio) {
|
|
|
16
16
|
* The frame itself never moves: the busy signal is the label (one waiting
|
|
17
17
|
* channel, kortix-brand `layout.md` States).
|
|
18
18
|
*/
|
|
19
|
-
export function ImageFrame({ aspectRatio, src, alt, pending, label, onOpen, className, fill = false, maxHeight, openLabel, naturalRatio = null, onNaturalSize, }) {
|
|
19
|
+
export function ImageFrame({ aspectRatio, src, alt, pending, label, onOpen, className, fill = false, maxHeight, openLabel, naturalRatio = null, onNaturalSize, children, }) {
|
|
20
20
|
const img = useRef(null);
|
|
21
21
|
const [loaded, setLoaded] = useState(false);
|
|
22
22
|
const [natural, setNatural] = useState(naturalRatio);
|
|
@@ -46,7 +46,7 @@ export function ImageFrame({ aspectRatio, src, alt, pending, label, onOpen, clas
|
|
|
46
46
|
: {
|
|
47
47
|
aspectRatio: natural ?? aspectRatio,
|
|
48
48
|
...(maxHeight && { width: `min(100%, calc(${maxHeight} * ${ratioValue(natural ?? aspectRatio)}))` }),
|
|
49
|
-
}, children: [image && onOpen ? (_jsx("button", { type: "button", onClick: onOpen, "aria-label": openLabel ?? alt, className: "focus-visible:ring-kortix-base block size-full cursor-zoom-in rounded-md focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset", children: image })) : (image), label ? (_jsx("div", { className: "absolute inset-0 flex items-center justify-center p-4 text-center", children: label })) : null] }));
|
|
49
|
+
}, children: [image && onOpen ? (_jsx("button", { type: "button", onClick: onOpen, "aria-label": openLabel ?? alt, className: "focus-visible:ring-kortix-base block size-full cursor-zoom-in rounded-md focus-visible:ring-2 focus-visible:outline-none focus-visible:ring-inset", children: image })) : (image), label ? (_jsx("div", { className: "absolute inset-0 flex items-center justify-center p-4 text-center", children: label })) : null, children] }));
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* An image whose file could not be read: "Image unavailable" and Try again,
|
package/dist/i18n/en.d.ts
CHANGED
|
@@ -371,6 +371,10 @@ declare const catalog: {
|
|
|
371
371
|
connected: {
|
|
372
372
|
label: string;
|
|
373
373
|
};
|
|
374
|
+
chrome: {
|
|
375
|
+
label: string;
|
|
376
|
+
description: string;
|
|
377
|
+
};
|
|
374
378
|
tokens: {
|
|
375
379
|
label: string;
|
|
376
380
|
description: string;
|
|
@@ -835,6 +839,14 @@ declare const catalog: {
|
|
|
835
839
|
name: string;
|
|
836
840
|
description: string;
|
|
837
841
|
};
|
|
842
|
+
artifact_comments: {
|
|
843
|
+
name: string;
|
|
844
|
+
description: string;
|
|
845
|
+
};
|
|
846
|
+
chrome: {
|
|
847
|
+
name: string;
|
|
848
|
+
description: string;
|
|
849
|
+
};
|
|
838
850
|
};
|
|
839
851
|
channelsSwitch: {
|
|
840
852
|
onTitle: string;
|
|
@@ -1161,6 +1173,7 @@ declare const catalog: {
|
|
|
1161
1173
|
loadError: string;
|
|
1162
1174
|
createIn: string;
|
|
1163
1175
|
localComputer: string;
|
|
1176
|
+
appsAndExtensions: string;
|
|
1164
1177
|
};
|
|
1165
1178
|
manifestUpgrade: {
|
|
1166
1179
|
title: string;
|
|
@@ -1772,6 +1785,13 @@ declare const catalog: {
|
|
|
1772
1785
|
unexpected: string;
|
|
1773
1786
|
};
|
|
1774
1787
|
};
|
|
1788
|
+
panel: {
|
|
1789
|
+
waitingTitle: string;
|
|
1790
|
+
waitingBody: string;
|
|
1791
|
+
errorTitle: string;
|
|
1792
|
+
errorBody: string;
|
|
1793
|
+
signIn: string;
|
|
1794
|
+
};
|
|
1775
1795
|
};
|
|
1776
1796
|
tools: {
|
|
1777
1797
|
executeCommand: string;
|
|
@@ -6777,6 +6797,127 @@ declare const catalog: {
|
|
|
6777
6797
|
calendarEstimatedSr: string;
|
|
6778
6798
|
calendarUpcomingSr: string;
|
|
6779
6799
|
};
|
|
6800
|
+
chrome: {
|
|
6801
|
+
pill: string;
|
|
6802
|
+
connectTitle: string;
|
|
6803
|
+
connectDescription: string;
|
|
6804
|
+
promoLabel: string;
|
|
6805
|
+
dismissPromo: string;
|
|
6806
|
+
steps: {
|
|
6807
|
+
install: {
|
|
6808
|
+
title: string;
|
|
6809
|
+
description: string;
|
|
6810
|
+
done: string;
|
|
6811
|
+
descriptionUnlisted: string;
|
|
6812
|
+
};
|
|
6813
|
+
connect: {
|
|
6814
|
+
title: string;
|
|
6815
|
+
description: string;
|
|
6816
|
+
done: string;
|
|
6817
|
+
};
|
|
6818
|
+
done: {
|
|
6819
|
+
title: string;
|
|
6820
|
+
description: string;
|
|
6821
|
+
};
|
|
6822
|
+
};
|
|
6823
|
+
addToChrome: string;
|
|
6824
|
+
finishInChrome: string;
|
|
6825
|
+
connect: string;
|
|
6826
|
+
connecting: string;
|
|
6827
|
+
done: string;
|
|
6828
|
+
unsupported: string;
|
|
6829
|
+
connectFailed: string;
|
|
6830
|
+
online: string;
|
|
6831
|
+
offline: string;
|
|
6832
|
+
lastSeen: string;
|
|
6833
|
+
usedBy: string;
|
|
6834
|
+
connectAnother: string;
|
|
6835
|
+
listTitle: string;
|
|
6836
|
+
rename: string;
|
|
6837
|
+
renameLabel: string;
|
|
6838
|
+
disconnect: string;
|
|
6839
|
+
disconnectTitle: string;
|
|
6840
|
+
disconnectDescription: string;
|
|
6841
|
+
disconnected: string;
|
|
6842
|
+
disconnectFailed: string;
|
|
6843
|
+
updateFailed: string;
|
|
6844
|
+
loadFailed: string;
|
|
6845
|
+
retry: string;
|
|
6846
|
+
access: {
|
|
6847
|
+
label: string;
|
|
6848
|
+
always: string;
|
|
6849
|
+
ask: string;
|
|
6850
|
+
off: string;
|
|
6851
|
+
description: string;
|
|
6852
|
+
};
|
|
6853
|
+
scope: {
|
|
6854
|
+
label: string;
|
|
6855
|
+
own: string;
|
|
6856
|
+
all: string;
|
|
6857
|
+
description: string;
|
|
6858
|
+
};
|
|
6859
|
+
how: {
|
|
6860
|
+
title: string;
|
|
6861
|
+
group: string;
|
|
6862
|
+
control: string;
|
|
6863
|
+
own: string;
|
|
6864
|
+
};
|
|
6865
|
+
howToInstall: string;
|
|
6866
|
+
copyLink: string;
|
|
6867
|
+
linkCopied: string;
|
|
6868
|
+
copyFailed: string;
|
|
6869
|
+
extensionMissing: string;
|
|
6870
|
+
another: {
|
|
6871
|
+
title: string;
|
|
6872
|
+
waiting: string;
|
|
6873
|
+
description: string;
|
|
6874
|
+
};
|
|
6875
|
+
panel: {
|
|
6876
|
+
project: string;
|
|
6877
|
+
title: string;
|
|
6878
|
+
body: string;
|
|
6879
|
+
selectionTitle: string;
|
|
6880
|
+
selectionBody: string;
|
|
6881
|
+
actions: {
|
|
6882
|
+
summarize: string;
|
|
6883
|
+
tables: string;
|
|
6884
|
+
compare: string;
|
|
6885
|
+
email: string;
|
|
6886
|
+
};
|
|
6887
|
+
prompts: {
|
|
6888
|
+
summarize: string;
|
|
6889
|
+
tables: string;
|
|
6890
|
+
compare: string;
|
|
6891
|
+
email: string;
|
|
6892
|
+
};
|
|
6893
|
+
recent: string;
|
|
6894
|
+
noProjects: string;
|
|
6895
|
+
createProject: string;
|
|
6896
|
+
addTab: string;
|
|
6897
|
+
addTabsTitle: string;
|
|
6898
|
+
addTabsHint: string;
|
|
6899
|
+
addTabs: string;
|
|
6900
|
+
noTabs: string;
|
|
6901
|
+
tabsFailed: string;
|
|
6902
|
+
cancel: string;
|
|
6903
|
+
removeTab: string;
|
|
6904
|
+
removeQuote: string;
|
|
6905
|
+
wholePage: string;
|
|
6906
|
+
unreadable: string;
|
|
6907
|
+
message: string;
|
|
6908
|
+
placeholder: string;
|
|
6909
|
+
placeholderNoTab: string;
|
|
6910
|
+
modeLabel: string;
|
|
6911
|
+
read: string;
|
|
6912
|
+
act: string;
|
|
6913
|
+
readHint: string;
|
|
6914
|
+
actHint: string;
|
|
6915
|
+
send: string;
|
|
6916
|
+
readFailed: string;
|
|
6917
|
+
screenshot: string;
|
|
6918
|
+
captureFailed: string;
|
|
6919
|
+
};
|
|
6920
|
+
};
|
|
6780
6921
|
computers: {
|
|
6781
6922
|
connectYourComputer: string;
|
|
6782
6923
|
connectThisComputer: string;
|
|
@@ -8087,5 +8228,53 @@ declare const catalog: {
|
|
|
8087
8228
|
tryAgain: string;
|
|
8088
8229
|
details: string;
|
|
8089
8230
|
};
|
|
8231
|
+
appsModal: {
|
|
8232
|
+
title: string;
|
|
8233
|
+
subtitle: string;
|
|
8234
|
+
mock: {
|
|
8235
|
+
group: string;
|
|
8236
|
+
button: string;
|
|
8237
|
+
working: string;
|
|
8238
|
+
takeOver: string;
|
|
8239
|
+
stop: string;
|
|
8240
|
+
};
|
|
8241
|
+
chrome: {
|
|
8242
|
+
name: string;
|
|
8243
|
+
description: string;
|
|
8244
|
+
connect: string;
|
|
8245
|
+
connecting: string;
|
|
8246
|
+
manage: string;
|
|
8247
|
+
unsupported: string;
|
|
8248
|
+
group: string;
|
|
8249
|
+
manageLabel: string;
|
|
8250
|
+
summary: string;
|
|
8251
|
+
};
|
|
8252
|
+
computer: {
|
|
8253
|
+
title: string;
|
|
8254
|
+
thisComputer: string;
|
|
8255
|
+
thisComputerDescription: string;
|
|
8256
|
+
connected: string;
|
|
8257
|
+
connect: string;
|
|
8258
|
+
manage: string;
|
|
8259
|
+
desktop: string;
|
|
8260
|
+
desktopDescription: string;
|
|
8261
|
+
desktopRunning: string;
|
|
8262
|
+
download: string;
|
|
8263
|
+
manageLabel: string;
|
|
8264
|
+
connectLabel: string;
|
|
8265
|
+
};
|
|
8266
|
+
developers: {
|
|
8267
|
+
title: string;
|
|
8268
|
+
cli: string;
|
|
8269
|
+
cliDescription: string;
|
|
8270
|
+
copy: string;
|
|
8271
|
+
copied: string;
|
|
8272
|
+
mcp: string;
|
|
8273
|
+
mcpDescription: string;
|
|
8274
|
+
connect: string;
|
|
8275
|
+
connectLabel: string;
|
|
8276
|
+
copyFailed: string;
|
|
8277
|
+
};
|
|
8278
|
+
};
|
|
8090
8279
|
};
|
|
8091
8280
|
export default catalog;
|