@agent-native/dispatch 0.41.1-nightly-20261104110058 → 0.42.0
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/CHANGELOG.md +26 -55
- package/dist/actions/get-hosted-apps-settings.d.ts +5 -0
- package/dist/actions/get-hosted-apps-settings.d.ts.map +1 -0
- package/dist/actions/get-hosted-apps-settings.js +25 -0
- package/dist/actions/get-hosted-apps-settings.js.map +1 -0
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +4 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/list-connected-agents.d.ts +1 -0
- package/dist/actions/list-connected-agents.js +11 -10
- package/dist/actions/list-connected-agents.js.map +1 -1
- package/dist/actions/list_apps.js +3 -2
- package/dist/actions/list_apps.js.map +1 -1
- package/dist/actions/provider-api-register.d.ts +10 -10
- package/dist/actions/set-hosted-apps-settings.d.ts +7 -0
- package/dist/actions/set-hosted-apps-settings.d.ts.map +1 -0
- package/dist/actions/set-hosted-apps-settings.js +35 -0
- package/dist/actions/set-hosted-apps-settings.js.map +1 -0
- package/dist/components/app-card-tiers.d.ts +13 -0
- package/dist/components/app-card-tiers.d.ts.map +1 -0
- package/dist/components/app-card-tiers.js +22 -0
- package/dist/components/app-card-tiers.js.map +1 -0
- package/dist/components/app-list-row.d.ts +12 -4
- package/dist/components/app-list-row.d.ts.map +1 -1
- package/dist/components/app-list-row.js +19 -4
- package/dist/components/app-list-row.js.map +1 -1
- package/dist/components/app-open-actions.d.ts +4 -0
- package/dist/components/app-open-actions.d.ts.map +1 -1
- package/dist/components/app-open-actions.js +9 -0
- package/dist/components/app-open-actions.js.map +1 -1
- package/dist/components/app-pin-button.d.ts +9 -0
- package/dist/components/app-pin-button.d.ts.map +1 -0
- package/dist/components/app-pin-button.js +29 -0
- package/dist/components/app-pin-button.js.map +1 -0
- package/dist/components/app-tier-sections.d.ts +27 -0
- package/dist/components/app-tier-sections.d.ts.map +1 -0
- package/dist/components/app-tier-sections.js +44 -0
- package/dist/components/app-tier-sections.js.map +1 -0
- package/dist/components/chat-home-apps.d.ts.map +1 -1
- package/dist/components/chat-home-apps.js +19 -26
- package/dist/components/chat-home-apps.js.map +1 -1
- package/dist/components/connected-app-card.d.ts +3 -1
- package/dist/components/connected-app-card.d.ts.map +1 -1
- package/dist/components/connected-app-card.js +6 -3
- package/dist/components/connected-app-card.js.map +1 -1
- package/dist/components/create-app-popover.d.ts +4 -0
- package/dist/components/create-app-popover.d.ts.map +1 -1
- package/dist/components/create-app-popover.js +6 -0
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/dispatch-control-plane.d.ts.map +1 -1
- package/dist/components/dispatch-control-plane.js +25 -35
- package/dist/components/dispatch-control-plane.js.map +1 -1
- package/dist/components/hosted-apps-settings-group.d.ts +6 -0
- package/dist/components/hosted-apps-settings-group.d.ts.map +1 -0
- package/dist/components/hosted-apps-settings-group.js +76 -0
- package/dist/components/hosted-apps-settings-group.js.map +1 -0
- package/dist/components/layout/Layout.d.ts +6 -4
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +97 -80
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +9 -20
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-app-layout-notice.d.ts +9 -0
- package/dist/components/workspace-app-layout-notice.d.ts.map +1 -0
- package/dist/components/workspace-app-layout-notice.js +27 -0
- package/dist/components/workspace-app-layout-notice.js.map +1 -0
- package/dist/components/workspace-app-search.d.ts.map +1 -1
- package/dist/components/workspace-app-search.js +11 -5
- package/dist/components/workspace-app-search.js.map +1 -1
- package/dist/components/workspace-template-card.d.ts.map +1 -1
- package/dist/components/workspace-template-card.js +7 -2
- package/dist/components/workspace-template-card.js.map +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/lib/other-apps.d.ts +10 -1
- package/dist/lib/other-apps.d.ts.map +1 -1
- package/dist/lib/other-apps.js +7 -1
- package/dist/lib/other-apps.js.map +1 -1
- package/dist/lib/workspace-app-layout.d.ts +62 -6
- package/dist/lib/workspace-app-layout.d.ts.map +1 -1
- package/dist/lib/workspace-app-layout.js +196 -41
- package/dist/lib/workspace-app-layout.js.map +1 -1
- package/dist/lib/workspace-app-lists.d.ts +17 -0
- package/dist/lib/workspace-app-lists.d.ts.map +1 -0
- package/dist/lib/workspace-app-lists.js +21 -0
- package/dist/lib/workspace-app-lists.js.map +1 -0
- package/dist/lib/workspace-apps.d.ts +3 -1
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +5 -1
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +23 -35
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/settings-page.d.ts.map +1 -1
- package/dist/routes/pages/settings-page.js +24 -3
- package/dist/routes/pages/settings-page.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +13 -18
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/app-roles.d.ts +2 -0
- package/dist/server/lib/app-roles.d.ts.map +1 -1
- package/dist/server/lib/app-roles.js +26 -7
- package/dist/server/lib/app-roles.js.map +1 -1
- package/dist/server/lib/hosted-apps-settings-schema.d.ts +6 -0
- package/dist/server/lib/hosted-apps-settings-schema.d.ts.map +1 -0
- package/dist/server/lib/hosted-apps-settings-schema.js +6 -0
- package/dist/server/lib/hosted-apps-settings-schema.js.map +1 -0
- package/dist/server/lib/hosted-apps-settings.d.ts +27 -0
- package/dist/server/lib/hosted-apps-settings.d.ts.map +1 -0
- package/dist/server/lib/hosted-apps-settings.js +72 -0
- package/dist/server/lib/hosted-apps-settings.js.map +1 -0
- package/dist/server/plugins/agent-chat.js +6 -3
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/server/plugins/integrations.js +3 -3
- package/dist/server/plugins/integrations.js.map +1 -1
- package/dist/shared/hosted-apps-settings.d.ts +3 -0
- package/dist/shared/hosted-apps-settings.d.ts.map +1 -0
- package/dist/shared/hosted-apps-settings.js +3 -0
- package/dist/shared/hosted-apps-settings.js.map +1 -0
- package/package.json +4 -4
- package/src/actions/get-hosted-apps-settings.ts +29 -0
- package/src/actions/hosted-apps-settings.spec.ts +100 -0
- package/src/actions/index.ts +4 -0
- package/src/actions/list-connected-agents.spec.ts +67 -0
- package/src/actions/list-connected-agents.ts +14 -15
- package/src/actions/list_apps.spec.ts +16 -0
- package/src/actions/list_apps.ts +5 -2
- package/src/actions/set-hosted-apps-settings.ts +42 -0
- package/src/components/app-card-tiers.tsx +85 -0
- package/src/components/app-list-row.spec.tsx +54 -0
- package/src/components/app-list-row.tsx +50 -8
- package/src/components/app-open-actions.tsx +16 -0
- package/src/components/app-pin-button.spec.tsx +68 -0
- package/src/components/app-pin-button.tsx +66 -0
- package/src/components/app-tier-sections.spec.tsx +155 -0
- package/src/components/app-tier-sections.tsx +158 -0
- package/src/components/chat-home-apps.spec.tsx +135 -29
- package/src/components/chat-home-apps.tsx +115 -111
- package/src/components/connected-app-card.spec.tsx +18 -2
- package/src/components/connected-app-card.tsx +18 -1
- package/src/components/create-app-popover.tsx +22 -0
- package/src/components/dispatch-control-plane.spec.tsx +89 -20
- package/src/components/dispatch-control-plane.tsx +91 -125
- package/src/components/hosted-apps-settings-group.spec.tsx +218 -0
- package/src/components/hosted-apps-settings-group.tsx +189 -0
- package/src/components/layout/Layout.spec.tsx +356 -49
- package/src/components/layout/Layout.tsx +189 -142
- package/src/components/workspace-app-card.spec.tsx +33 -29
- package/src/components/workspace-app-card.tsx +13 -31
- package/src/components/workspace-app-layout-notice.spec.tsx +106 -0
- package/src/components/workspace-app-layout-notice.tsx +65 -0
- package/src/components/workspace-app-search.spec.tsx +53 -0
- package/src/components/workspace-app-search.tsx +39 -32
- package/src/components/workspace-template-card.spec.tsx +10 -0
- package/src/components/workspace-template-card.tsx +7 -2
- package/src/db/index.spec.ts +9 -0
- package/src/db/index.ts +1 -0
- package/src/lib/other-apps.spec.ts +25 -0
- package/src/lib/other-apps.ts +9 -0
- package/src/lib/workspace-app-layout.spec.ts +61 -3
- package/src/lib/workspace-app-layout.store.spec.tsx +261 -0
- package/src/lib/workspace-app-layout.ts +265 -48
- package/src/lib/workspace-app-lists.ts +32 -0
- package/src/lib/workspace-apps.ts +10 -2
- package/src/routes/pages/apps.spec.tsx +133 -5
- package/src/routes/pages/apps.tsx +79 -140
- package/src/routes/pages/chat.spec.tsx +66 -49
- package/src/routes/pages/settings-page.tsx +31 -3
- package/src/routes/pages/settings.spec.tsx +37 -0
- package/src/server/lib/app-creation-store.spec.ts +14 -0
- package/src/server/lib/app-creation-store.ts +16 -29
- package/src/server/lib/app-creation-store.write-observation.spec.ts +216 -0
- package/src/server/lib/app-roles.spec.ts +48 -1
- package/src/server/lib/app-roles.ts +44 -12
- package/src/server/lib/hosted-apps-settings-schema.ts +6 -0
- package/src/server/lib/hosted-apps-settings.spec.ts +154 -0
- package/src/server/lib/hosted-apps-settings.ts +108 -0
- package/src/server/plugins/agent-chat.spec.ts +16 -0
- package/src/server/plugins/agent-chat.ts +7 -2
- package/src/server/plugins/integrations.ts +3 -3
- package/src/shared/hosted-apps-settings.ts +3 -0
- package/src/styles/dispatch.css +40 -11
- package/dist/components/available-apps-section.d.ts +0 -9
- package/dist/components/available-apps-section.d.ts.map +0 -1
- package/dist/components/available-apps-section.js +0 -97
- package/dist/components/available-apps-section.js.map +0 -1
- package/dist/components/other-apps-section.d.ts +0 -35
- package/dist/components/other-apps-section.d.ts.map +0 -1
- package/dist/components/other-apps-section.js +0 -79
- package/dist/components/other-apps-section.js.map +0 -1
- package/src/components/available-apps-section.tsx +0 -239
- package/src/components/other-apps-section.spec.ts +0 -50
- package/src/components/other-apps-section.tsx +0 -254
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-template-card.js","sourceRoot":"","sources":["../../src/components/workspace-template-card.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionMutation } from \"@agent-native/core/client/hooks\";\nimport { normalizeWorkspaceAppId } from \"@agent-native/core/shared\";\nimport {\n IconArrowUpRight,\n IconCircleCheck,\n IconPlus,\n IconPlugConnected,\n} from \"@tabler/icons-react\";\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { toast } from \"sonner\";\n\nimport { cn } from \"../lib/utils\";\nimport { AppIcon } from \"./app-icon\";\nimport { AppListRow } from \"./app-list-row\";\nimport { AppOpenActions } from \"./app-open-actions\";\nimport { AppRowSettings } from \"./app-row-settings\";\nimport { useNotifyBuildInBuilder } from \"./build-in-builder\";\nimport { Button } from \"./ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"./ui/dialog\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { Spinner } from \"./ui/spinner\";\n\nexport interface CuratedWorkspaceTemplate {\n id?: string | null;\n templateId?: string | null;\n appId?: string | null;\n name: string;\n description?: string | null;\n source?: string | null;\n sourceDescription?: string | null;\n icon?: string | null;\n color?: string | null;\n integrationSetup?: string | null;\n setupNote?: string | null;\n installed?: boolean | null;\n installedAppId?: string | null;\n liveUrl?: string | null;\n productUrl?: string | null;\n}\n\nexport type CuratedWorkspaceTemplatesResult =\n | CuratedWorkspaceTemplate[]\n | {\n templates: CuratedWorkspaceTemplate[];\n };\n\nexport interface WorkspaceTemplateLabels {\n appId: string;\n appIdDescription: string;\n cancel: string;\n integrationSetup: string;\n installed: string;\n remix: string;\n remixing: string;\n remixSuccess: string;\n remixError: string;\n appIdRequired: string;\n source: string;\n openApp: string;\n viewLiveApp: string;\n}\n\nconst DEFAULT_LABELS: WorkspaceTemplateLabels = {\n appId: \"App ID\",\n appIdDescription: \"Choose the URL-safe id for the new workspace app.\",\n cancel: \"Cancel\",\n integrationSetup: \"Integration setup\",\n installed: \"Installed\",\n remix: \"Add app\",\n remixing: \"Creating app…\",\n remixSuccess: \"Template app creation started.\",\n remixError: \"Could not add this app\",\n appIdRequired: \"App ID is required.\",\n source: \"Source\",\n openApp: \"Open app\",\n viewLiveApp: \"View the live app\",\n};\n\nexport interface WorkspaceTemplateCardProps {\n template: CuratedWorkspaceTemplate;\n defaultAppId?: string;\n labels?: Partial<WorkspaceTemplateLabels>;\n className?: string;\n catalog?: boolean;\n onRemixSuccess?: (\n result: unknown,\n template: CuratedWorkspaceTemplate,\n ) => void;\n}\n\nfunction templateIdFor(template: CuratedWorkspaceTemplate): string {\n return template.templateId || template.id || template.appId || template.name;\n}\n\nfunction defaultAppIdFor(\n template: CuratedWorkspaceTemplate,\n defaultAppId?: string,\n): string {\n if (defaultAppId) return normalizeWorkspaceAppId(defaultAppId) || \"new-app\";\n const sourceId =\n normalizeWorkspaceAppId(template.appId || template.name) || \"new-app\";\n return `${sourceId}-app`;\n}\n\nfunction stringifyError(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === \"string\") return error;\n return \"Unknown error\";\n}\n\nfunction mergeLabels(\n labels?: Partial<WorkspaceTemplateLabels>,\n): WorkspaceTemplateLabels {\n return { ...DEFAULT_LABELS, ...labels };\n}\n\nexport function WorkspaceTemplateCard({\n template,\n defaultAppId,\n labels: labelOverrides,\n className,\n catalog = false,\n onRemixSuccess,\n}: WorkspaceTemplateCardProps) {\n const labels = useMemo(() => mergeLabels(labelOverrides), [labelOverrides]);\n const [open, setOpen] = useState(false);\n const [appId, setAppId] = useState(() =>\n defaultAppIdFor(template, defaultAppId),\n );\n const isInstalled = Boolean(template.installed || template.installedAppId);\n const liveUrl = template.liveUrl || template.productUrl;\n const setupNote = template.integrationSetup || template.setupNote;\n const notifyBuildInBuilder = useNotifyBuildInBuilder();\n const remix = useActionMutation(\"remix-workspace-template\", {\n onSuccess: (result) => {\n const mode = (result as { mode?: string } | null)?.mode;\n const message = (result as { message?: string } | null)?.message;\n const url = (result as { url?: string } | null)?.url;\n if (mode === \"builder-managed\" && url) {\n notifyBuildInBuilder(url);\n } else if (mode === \"builder\") {\n toast.success(labels.remixSuccess);\n } else if (mode === \"builder-unavailable\" || mode === \"app-id-taken\") {\n toast.error(message || labels.remixError);\n } else if (mode === \"coming-soon\") {\n toast.info(message || labels.remixSuccess);\n } else {\n toast.success(labels.remixSuccess);\n }\n setOpen(false);\n onRemixSuccess?.(result, template);\n },\n onError: (error) =>\n toast.error(`${labels.remixError}: ${stringifyError(error)}`),\n });\n\n useEffect(() => {\n if (open) {\n setAppId(defaultAppIdFor(template, defaultAppId));\n }\n }, [defaultAppId, open, template]);\n\n function submitRemix() {\n const normalizedAppId = normalizeWorkspaceAppId(appId);\n if (!normalizedAppId) {\n toast.error(labels.appIdRequired);\n return;\n }\n setAppId(normalizedAppId);\n\n remix.mutate({\n templateId: templateIdFor(template),\n appId: normalizedAppId,\n });\n }\n\n return (\n <AppListRow className={cn(\"items-center\", className)}>\n <AppIcon\n id={template.id || template.templateId || template.name}\n name={template.name}\n icon={template.icon || undefined}\n color={template.color || undefined}\n size=\"sm\"\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <h3 className=\"truncate text-sm font-semibold text-foreground\">\n {template.name}\n </h3>\n {isInstalled ? (\n <span className=\"inline-flex shrink-0 items-center gap-1 text-xs text-primary\">\n <IconCircleCheck size={13} />\n {labels.installed}\n </span>\n ) : null}\n </div>\n {template.description ? (\n <p className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {template.description}\n </p>\n ) : null}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {catalog ? (\n <>\n {liveUrl ? (\n <AppOpenActions\n name={template.name}\n href={liveUrl}\n rel=\"noreferrer\"\n labels={{ openApp: labels.openApp }}\n showNewTabOption\n />\n ) : null}\n <AppRowSettings\n name={template.name}\n addAppLabel={labels.remix}\n onAddApp={() => setOpen(true)}\n />\n </>\n ) : liveUrl ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"shrink-0\" asChild>\n <a href={liveUrl} target=\"_blank\" rel=\"noreferrer\">\n {labels.viewLiveApp}\n <IconArrowUpRight />\n </a>\n </Button>\n ) : null}\n\n <Dialog\n open={open}\n onOpenChange={(nextOpen) => {\n if (!remix.isPending) setOpen(nextOpen);\n }}\n >\n {!catalog ? (\n <DialogTrigger asChild>\n <Button type=\"button\" variant=\"outline\" size=\"sm\">\n <IconPlus />\n {labels.remix}\n </Button>\n </DialogTrigger>\n ) : null}\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>{template.name}</DialogTitle>\n <DialogDescription>{labels.appIdDescription}</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-4\"\n onSubmit={(event) => {\n event.preventDefault();\n submitRemix();\n }}\n >\n <div className=\"flex flex-col gap-2\">\n <Label\n htmlFor={`workspace-template-app-id-${templateIdFor(template)}`}\n >\n {labels.appId}\n </Label>\n <Input\n id={`workspace-template-app-id-${templateIdFor(template)}`}\n value={appId}\n autoComplete=\"off\"\n onChange={(event) => setAppId(event.target.value)}\n onBlur={() => setAppId(normalizeWorkspaceAppId(appId))}\n disabled={remix.isPending}\n />\n </div>\n {setupNote ? (\n <div className=\"flex items-start gap-2 rounded-lg bg-muted px-3 py-2 text-xs leading-5 text-muted-foreground\">\n <IconPlugConnected className=\"mt-0.5 shrink-0\" size={15} />\n <span>\n <span className=\"font-medium text-foreground\">\n {labels.integrationSetup}:\n </span>{\" \"}\n {setupNote}\n </span>\n </div>\n ) : null}\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={remix.isPending}\n >\n {labels.cancel}\n </Button>\n <Button type=\"submit\" disabled={remix.isPending}>\n {remix.isPending ? <Spinner /> : <IconArrowUpRight />}\n {remix.isPending ? labels.remixing : labels.remix}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n </div>\n </AppListRow>\n );\n}\n\nexport interface WorkspaceTemplatesSectionProps {\n templates: CuratedWorkspaceTemplatesResult;\n title?: ReactNode;\n defaultAppId?: string;\n labels?: Partial<WorkspaceTemplateLabels>;\n className?: string;\n cardClassName?: string;\n listClassName?: string;\n catalog?: boolean;\n onRemixSuccess?: (\n result: unknown,\n template: CuratedWorkspaceTemplate,\n ) => void;\n}\n\nfunction getTemplateItems(\n result: CuratedWorkspaceTemplatesResult,\n): CuratedWorkspaceTemplate[] {\n return Array.isArray(result) ? result : result.templates;\n}\n\nexport function WorkspaceTemplatesSection({\n templates: result,\n title,\n defaultAppId,\n labels,\n className,\n cardClassName,\n listClassName,\n catalog = false,\n onRemixSuccess,\n}: WorkspaceTemplatesSectionProps) {\n const templates = getTemplateItems(result);\n\n if (templates.length === 0) return null;\n\n return (\n <section className={cn(\"flex flex-col gap-3\", className)}>\n {title ? <div className=\"text-sm font-semibold\">{title}</div> : null}\n <div className={cn(\"overflow-hidden rounded-2xl bg-card\", listClassName)}>\n {templates.map((template) => (\n <WorkspaceTemplateCard\n key={templateIdFor(template)}\n template={template}\n defaultAppId={defaultAppId}\n labels={labels}\n catalog={catalog}\n className={cardClassName}\n onRemixSuccess={onRemixSuccess}\n />\n ))}\n </div>\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workspace-template-card.js","sourceRoot":"","sources":["../../src/components/workspace-template-card.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionMutation } from \"@agent-native/core/client/hooks\";\nimport { useT } from \"@agent-native/core/client/i18n\";\nimport { normalizeWorkspaceAppId } from \"@agent-native/core/shared\";\nimport {\n IconArrowUpRight,\n IconCircleCheck,\n IconPlus,\n IconPlugConnected,\n} from \"@tabler/icons-react\";\nimport { useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { toast } from \"sonner\";\n\nimport { cn } from \"../lib/utils\";\nimport { AppIcon } from \"./app-icon\";\nimport { AppListRow } from \"./app-list-row\";\nimport { AppOpenActions, appOpenActionLabels } from \"./app-open-actions\";\nimport { AppRowSettings } from \"./app-row-settings\";\nimport { useNotifyBuildInBuilder } from \"./build-in-builder\";\nimport { Button } from \"./ui/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"./ui/dialog\";\nimport { Input } from \"./ui/input\";\nimport { Label } from \"./ui/label\";\nimport { Spinner } from \"./ui/spinner\";\n\nexport interface CuratedWorkspaceTemplate {\n id?: string | null;\n templateId?: string | null;\n appId?: string | null;\n name: string;\n description?: string | null;\n source?: string | null;\n sourceDescription?: string | null;\n icon?: string | null;\n color?: string | null;\n integrationSetup?: string | null;\n setupNote?: string | null;\n installed?: boolean | null;\n installedAppId?: string | null;\n liveUrl?: string | null;\n productUrl?: string | null;\n}\n\nexport type CuratedWorkspaceTemplatesResult =\n | CuratedWorkspaceTemplate[]\n | {\n templates: CuratedWorkspaceTemplate[];\n };\n\nexport interface WorkspaceTemplateLabels {\n appId: string;\n appIdDescription: string;\n cancel: string;\n integrationSetup: string;\n installed: string;\n remix: string;\n remixing: string;\n remixSuccess: string;\n remixError: string;\n appIdRequired: string;\n source: string;\n openApp: string;\n viewLiveApp: string;\n}\n\nconst DEFAULT_LABELS: WorkspaceTemplateLabels = {\n appId: \"App ID\",\n appIdDescription: \"Choose the URL-safe id for the new workspace app.\",\n cancel: \"Cancel\",\n integrationSetup: \"Integration setup\",\n installed: \"Installed\",\n remix: \"Add app\",\n remixing: \"Creating app…\",\n remixSuccess: \"Template app creation started.\",\n remixError: \"Could not add this app\",\n appIdRequired: \"App ID is required.\",\n source: \"Source\",\n openApp: \"Open app\",\n viewLiveApp: \"View the live app\",\n};\n\nexport interface WorkspaceTemplateCardProps {\n template: CuratedWorkspaceTemplate;\n defaultAppId?: string;\n labels?: Partial<WorkspaceTemplateLabels>;\n className?: string;\n catalog?: boolean;\n onRemixSuccess?: (\n result: unknown,\n template: CuratedWorkspaceTemplate,\n ) => void;\n}\n\nfunction templateIdFor(template: CuratedWorkspaceTemplate): string {\n return template.templateId || template.id || template.appId || template.name;\n}\n\nfunction defaultAppIdFor(\n template: CuratedWorkspaceTemplate,\n defaultAppId?: string,\n): string {\n if (defaultAppId) return normalizeWorkspaceAppId(defaultAppId) || \"new-app\";\n const sourceId =\n normalizeWorkspaceAppId(template.appId || template.name) || \"new-app\";\n return `${sourceId}-app`;\n}\n\nfunction stringifyError(error: unknown): string {\n if (error instanceof Error && error.message) return error.message;\n if (typeof error === \"string\") return error;\n return \"Unknown error\";\n}\n\nfunction mergeLabels(\n labels?: Partial<WorkspaceTemplateLabels>,\n): WorkspaceTemplateLabels {\n return { ...DEFAULT_LABELS, ...labels };\n}\n\nexport function WorkspaceTemplateCard({\n template,\n defaultAppId,\n labels: labelOverrides,\n className,\n catalog = false,\n onRemixSuccess,\n}: WorkspaceTemplateCardProps) {\n const t = useT();\n const labels = useMemo(() => mergeLabels(labelOverrides), [labelOverrides]);\n const [open, setOpen] = useState(false);\n const [appId, setAppId] = useState(() =>\n defaultAppIdFor(template, defaultAppId),\n );\n const isInstalled = Boolean(template.installed || template.installedAppId);\n const liveUrl = template.liveUrl || template.productUrl;\n const setupNote = template.integrationSetup || template.setupNote;\n const notifyBuildInBuilder = useNotifyBuildInBuilder();\n const remix = useActionMutation(\"remix-workspace-template\", {\n onSuccess: (result) => {\n const mode = (result as { mode?: string } | null)?.mode;\n const message = (result as { message?: string } | null)?.message;\n const url = (result as { url?: string } | null)?.url;\n if (mode === \"builder-managed\" && url) {\n notifyBuildInBuilder(url);\n } else if (mode === \"builder\") {\n toast.success(labels.remixSuccess);\n } else if (mode === \"builder-unavailable\" || mode === \"app-id-taken\") {\n toast.error(message || labels.remixError);\n } else if (mode === \"coming-soon\") {\n toast.info(message || labels.remixSuccess);\n } else {\n toast.success(labels.remixSuccess);\n }\n setOpen(false);\n onRemixSuccess?.(result, template);\n },\n onError: (error) =>\n toast.error(`${labels.remixError}: ${stringifyError(error)}`),\n });\n\n useEffect(() => {\n if (open) {\n setAppId(defaultAppIdFor(template, defaultAppId));\n }\n }, [defaultAppId, open, template]);\n\n function submitRemix() {\n const normalizedAppId = normalizeWorkspaceAppId(appId);\n if (!normalizedAppId) {\n toast.error(labels.appIdRequired);\n return;\n }\n setAppId(normalizedAppId);\n\n remix.mutate({\n templateId: templateIdFor(template),\n appId: normalizedAppId,\n });\n }\n\n return (\n <AppListRow className={cn(\"items-center\", className)}>\n <AppIcon\n id={template.id || template.templateId || template.name}\n name={template.name}\n icon={template.icon || undefined}\n color={template.color || undefined}\n size=\"sm\"\n />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <h3 className=\"truncate text-sm font-semibold text-foreground\">\n {template.name}\n </h3>\n {isInstalled ? (\n <span className=\"inline-flex shrink-0 items-center gap-1 text-xs text-primary\">\n <IconCircleCheck size={13} />\n {labels.installed}\n </span>\n ) : null}\n </div>\n {template.description ? (\n <p className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {template.description}\n </p>\n ) : null}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {catalog ? (\n <>\n {liveUrl ? (\n <AppOpenActions\n name={template.name}\n href={liveUrl}\n rel=\"noreferrer\"\n labels={{\n ...appOpenActionLabels(t, template.name),\n openApp: labels.openApp,\n }}\n showNewTabOption\n />\n ) : null}\n <AppRowSettings\n name={template.name}\n addAppLabel={labels.remix}\n onAddApp={() => setOpen(true)}\n />\n </>\n ) : liveUrl ? (\n <Button variant=\"ghost\" size=\"sm\" className=\"shrink-0\" asChild>\n <a href={liveUrl} target=\"_blank\" rel=\"noreferrer\">\n {labels.viewLiveApp}\n <IconArrowUpRight />\n </a>\n </Button>\n ) : null}\n\n <Dialog\n open={open}\n onOpenChange={(nextOpen) => {\n if (!remix.isPending) setOpen(nextOpen);\n }}\n >\n {!catalog ? (\n <DialogTrigger asChild>\n <Button type=\"button\" variant=\"outline\" size=\"sm\">\n <IconPlus />\n {labels.remix}\n </Button>\n </DialogTrigger>\n ) : null}\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>{template.name}</DialogTitle>\n <DialogDescription>{labels.appIdDescription}</DialogDescription>\n </DialogHeader>\n <form\n className=\"flex flex-col gap-4\"\n onSubmit={(event) => {\n event.preventDefault();\n submitRemix();\n }}\n >\n <div className=\"flex flex-col gap-2\">\n <Label\n htmlFor={`workspace-template-app-id-${templateIdFor(template)}`}\n >\n {labels.appId}\n </Label>\n <Input\n id={`workspace-template-app-id-${templateIdFor(template)}`}\n value={appId}\n autoComplete=\"off\"\n onChange={(event) => setAppId(event.target.value)}\n onBlur={() => setAppId(normalizeWorkspaceAppId(appId))}\n disabled={remix.isPending}\n />\n </div>\n {setupNote ? (\n <div className=\"flex items-start gap-2 rounded-lg bg-muted px-3 py-2 text-xs leading-5 text-muted-foreground\">\n <IconPlugConnected className=\"mt-0.5 shrink-0\" size={15} />\n <span>\n <span className=\"font-medium text-foreground\">\n {labels.integrationSetup}:\n </span>{\" \"}\n {setupNote}\n </span>\n </div>\n ) : null}\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setOpen(false)}\n disabled={remix.isPending}\n >\n {labels.cancel}\n </Button>\n <Button type=\"submit\" disabled={remix.isPending}>\n {remix.isPending ? <Spinner /> : <IconArrowUpRight />}\n {remix.isPending ? labels.remixing : labels.remix}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n </div>\n </AppListRow>\n );\n}\n\nexport interface WorkspaceTemplatesSectionProps {\n templates: CuratedWorkspaceTemplatesResult;\n title?: ReactNode;\n defaultAppId?: string;\n labels?: Partial<WorkspaceTemplateLabels>;\n className?: string;\n cardClassName?: string;\n listClassName?: string;\n catalog?: boolean;\n onRemixSuccess?: (\n result: unknown,\n template: CuratedWorkspaceTemplate,\n ) => void;\n}\n\nfunction getTemplateItems(\n result: CuratedWorkspaceTemplatesResult,\n): CuratedWorkspaceTemplate[] {\n return Array.isArray(result) ? result : result.templates;\n}\n\nexport function WorkspaceTemplatesSection({\n templates: result,\n title,\n defaultAppId,\n labels,\n className,\n cardClassName,\n listClassName,\n catalog = false,\n onRemixSuccess,\n}: WorkspaceTemplatesSectionProps) {\n const templates = getTemplateItems(result);\n\n if (templates.length === 0) return null;\n\n return (\n <section className={cn(\"flex flex-col gap-3\", className)}>\n {title ? <div className=\"text-sm font-semibold\">{title}</div> : null}\n <div className={cn(\"overflow-hidden rounded-2xl bg-card\", listClassName)}>\n {templates.map((template) => (\n <WorkspaceTemplateCard\n key={templateIdFor(template)}\n template={template}\n defaultAppId={defaultAppId}\n labels={labels}\n catalog={catalog}\n className={cardClassName}\n onRemixSuccess={onRemixSuccess}\n />\n ))}\n </div>\n </section>\n );\n}\n"]}
|
package/dist/db/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAExE,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,KAAK,gBAAgB,GAAG,UAAU,CAAC,gBAAgB,EAAE,OAAO,MAAM,CAAC,CAAC;AAEpE,eAAO,MAAM,KAAK,EAA0B,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAExE,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,KAAK,gBAAgB,GAAG,UAAU,CAAC,gBAAgB,EAAE,OAAO,MAAM,CAAC,CAAC;AAEpE,eAAO,MAAM,KAAK,EAA0B,MAAM,gBAAgB,CAAC;AAwBnE,wBAAgB,EAAE,qBAEjB;AAED,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
|
package/dist/db/index.js
CHANGED
|
@@ -14,6 +14,7 @@ registerShareableResource({
|
|
|
14
14
|
allowPublic: false,
|
|
15
15
|
requireOrgMemberForUserShares: true,
|
|
16
16
|
supportsGroupShares: true,
|
|
17
|
+
canManageAccessKey: (resource) => resource.orgId ?? undefined,
|
|
17
18
|
canManageAccess: async (resource, ctx) => {
|
|
18
19
|
if (!ctx.userEmail || !ctx.orgId || resource?.orgId !== ctx.orgId) {
|
|
19
20
|
return false;
|
package/dist/db/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGvE,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAItC,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAA2B,CAAC;AAEnE,yBAAyB,CAAC;IACxB,IAAI,EAAE,eAAe;IACrB,aAAa,EAAE,MAAM,CAAC,aAAa;IACnC,WAAW,EAAE,MAAM,CAAC,kBAAkB;IACtC,WAAW,EAAE,eAAe;IAC5B,WAAW,EAAE,MAAM;IACnB,eAAe,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC5B,OAAO,QAAQ,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;IAChE,KAAK;IACL,WAAW,EAAE,KAAK;IAClB,6BAA6B,EAAE,IAAI;IACnC,mBAAmB,EAAE,IAAI;IACzB,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE;QACvC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,QAAQ,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC;YAClE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/D,OAAO,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC;IAC9C,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,UAAU,EAAE;IAChB,OAAO,KAAK,EAAE,CAAC;AACjB,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC","sourcesContent":["import { createGetDb } from \"@agent-native/core/db\";\nimport { readOrgMemberRole } from \"@agent-native/core/server\";\nimport { registerShareableResource } from \"@agent-native/core/sharing\";\nimport type { PgDatabase, PgQueryResultHKT } from \"drizzle-orm/pg-core\";\n\nimport * as schema from \"./schema.js\";\n\ntype DispatchDatabase = PgDatabase<PgQueryResultHKT, typeof schema>;\n\nexport const getDb = createGetDb(schema) as () => DispatchDatabase;\n\nregisterShareableResource({\n type: \"workspace-app\",\n resourceTable: schema.workspaceApps,\n sharesTable: schema.workspaceAppShares,\n displayName: \"Workspace app\",\n titleColumn: \"name\",\n getResourcePath: (resource) =>\n typeof resource?.path === \"string\" ? resource.path : undefined,\n getDb,\n allowPublic: false,\n requireOrgMemberForUserShares: true,\n supportsGroupShares: true,\n canManageAccess: async (resource, ctx) => {\n if (!ctx.userEmail || !ctx.orgId || resource?.orgId !== ctx.orgId) {\n return false;\n }\n const role = await readOrgMemberRole(ctx.orgId, ctx.userEmail);\n return role === \"owner\" || role === \"admin\";\n },\n});\n\nexport function db() {\n return getDb();\n}\n\nexport { schema };\nexport * from \"./schema.js\";\nexport * from \"./migrations.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAGvE,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAItC,MAAM,CAAC,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAA2B,CAAC;AAEnE,yBAAyB,CAAC;IACxB,IAAI,EAAE,eAAe;IACrB,aAAa,EAAE,MAAM,CAAC,aAAa;IACnC,WAAW,EAAE,MAAM,CAAC,kBAAkB;IACtC,WAAW,EAAE,eAAe;IAC5B,WAAW,EAAE,MAAM;IACnB,eAAe,EAAE,CAAC,QAAQ,EAAE,EAAE,CAC5B,OAAO,QAAQ,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;IAChE,KAAK;IACL,WAAW,EAAE,KAAK;IAClB,6BAA6B,EAAE,IAAI;IACnC,mBAAmB,EAAE,IAAI;IACzB,kBAAkB,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,IAAI,SAAS;IAC7D,eAAe,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE;QACvC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,QAAQ,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC;YAClE,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/D,OAAO,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC;IAC9C,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,UAAU,EAAE;IAChB,OAAO,KAAK,EAAE,CAAC;AACjB,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC","sourcesContent":["import { createGetDb } from \"@agent-native/core/db\";\nimport { readOrgMemberRole } from \"@agent-native/core/server\";\nimport { registerShareableResource } from \"@agent-native/core/sharing\";\nimport type { PgDatabase, PgQueryResultHKT } from \"drizzle-orm/pg-core\";\n\nimport * as schema from \"./schema.js\";\n\ntype DispatchDatabase = PgDatabase<PgQueryResultHKT, typeof schema>;\n\nexport const getDb = createGetDb(schema) as () => DispatchDatabase;\n\nregisterShareableResource({\n type: \"workspace-app\",\n resourceTable: schema.workspaceApps,\n sharesTable: schema.workspaceAppShares,\n displayName: \"Workspace app\",\n titleColumn: \"name\",\n getResourcePath: (resource) =>\n typeof resource?.path === \"string\" ? resource.path : undefined,\n getDb,\n allowPublic: false,\n requireOrgMemberForUserShares: true,\n supportsGroupShares: true,\n canManageAccessKey: (resource) => resource.orgId ?? undefined,\n canManageAccess: async (resource, ctx) => {\n if (!ctx.userEmail || !ctx.orgId || resource?.orgId !== ctx.orgId) {\n return false;\n }\n const role = await readOrgMemberRole(ctx.orgId, ctx.userEmail);\n return role === \"owner\" || role === \"admin\";\n },\n});\n\nexport function db() {\n return getDb();\n}\n\nexport { schema };\nexport * from \"./schema.js\";\nexport * from \"./migrations.js\";\n"]}
|
package/dist/lib/other-apps.d.ts
CHANGED
|
@@ -6,11 +6,20 @@ export interface ConnectedAppSummary {
|
|
|
6
6
|
homeUrl?: string;
|
|
7
7
|
color?: string;
|
|
8
8
|
source?: "builtin" | "custom" | "workspace";
|
|
9
|
+
/** Set by list-connected-agents when the organization hides hosted apps. */
|
|
10
|
+
hiddenFromLaunchers?: boolean;
|
|
9
11
|
}
|
|
10
12
|
export interface WorkspaceAppId {
|
|
11
13
|
id: string;
|
|
12
14
|
isDispatch?: boolean;
|
|
13
15
|
}
|
|
14
16
|
export declare function filterOtherApps(connectedApps: ConnectedAppSummary[], workspaceApps: WorkspaceAppId[]): ConnectedAppSummary[];
|
|
15
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Hosted apps for launcher surfaces. Rows the organization hides are left out
|
|
19
|
+
* unless `includeHiddenFromLaunchers` is set, which callers that resolve an
|
|
20
|
+
* app id to open (pane restore, `open_app`) need.
|
|
21
|
+
*/
|
|
22
|
+
export declare function filterBuiltInApps(connectedApps: ConnectedAppSummary[], workspaceApps: WorkspaceAppId[], { includeHiddenFromLaunchers }?: {
|
|
23
|
+
includeHiddenFromLaunchers?: boolean | undefined;
|
|
24
|
+
}): ConnectedAppSummary[];
|
|
16
25
|
//# sourceMappingURL=other-apps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"other-apps.d.ts","sourceRoot":"","sources":["../../src/lib/other-apps.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"other-apps.d.ts","sourceRoot":"","sources":["../../src/lib/other-apps.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC5C,4EAA4E;IAC5E,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAaD,wBAAgB,eAAe,CAC7B,aAAa,EAAE,mBAAmB,EAAE,EACpC,aAAa,EAAE,cAAc,EAAE,GAC9B,mBAAmB,EAAE,CAwBvB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,mBAAmB,EAAE,EACpC,aAAa,EAAE,cAAc,EAAE,EAC/B,EAAE,0BAAkC,EAAE;;CAAK,GAC1C,mBAAmB,EAAE,CA+BvB"}
|
package/dist/lib/other-apps.js
CHANGED
|
@@ -33,7 +33,12 @@ export function filterOtherApps(connectedApps, workspaceApps) {
|
|
|
33
33
|
})
|
|
34
34
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Hosted apps for launcher surfaces. Rows the organization hides are left out
|
|
38
|
+
* unless `includeHiddenFromLaunchers` is set, which callers that resolve an
|
|
39
|
+
* app id to open (pane restore, `open_app`) need.
|
|
40
|
+
*/
|
|
41
|
+
export function filterBuiltInApps(connectedApps, workspaceApps, { includeHiddenFromLaunchers = false } = {}) {
|
|
37
42
|
const workspaceAppIds = new Set([
|
|
38
43
|
"dispatch",
|
|
39
44
|
...workspaceApps.map((app) => app.id.trim().toLowerCase()),
|
|
@@ -45,6 +50,7 @@ export function filterBuiltInApps(connectedApps, workspaceApps) {
|
|
|
45
50
|
const url = app.homeUrl?.trim() || app.url;
|
|
46
51
|
if (!id ||
|
|
47
52
|
app.source !== "builtin" ||
|
|
53
|
+
(app.hiddenFromLaunchers && !includeHiddenFromLaunchers) ||
|
|
48
54
|
isDefaultWorkspaceAppHiddenId(id) ||
|
|
49
55
|
workspaceAppIds.has(id) ||
|
|
50
56
|
seen.has(id) ||
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"other-apps.js","sourceRoot":"","sources":["../../src/lib/other-apps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"other-apps.js","sourceRoot":"","sources":["../../src/lib/other-apps.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defaultWorkspaceAppUrl,\n isDefaultWorkspaceAppHiddenId,\n} from \"./workspace-apps\";\n\nexport interface ConnectedAppSummary {\n id: string;\n name: string;\n description?: string;\n url: string;\n homeUrl?: string;\n color?: string;\n source?: \"builtin\" | \"custom\" | \"workspace\";\n /** Set by list-connected-agents when the organization hides hosted apps. */\n hiddenFromLaunchers?: boolean;\n}\n\nexport interface WorkspaceAppId {\n id: string;\n isDispatch?: boolean;\n}\n\nconst HIDDEN_OTHER_APP_IDS = new Set([\"crm\", \"research\"]);\n\nfunction isHttpUrl(value: string): boolean {\n try {\n const url = new URL(value);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nexport function filterOtherApps(\n connectedApps: ConnectedAppSummary[],\n workspaceApps: WorkspaceAppId[],\n): ConnectedAppSummary[] {\n const workspaceAppIds = new Set([\n \"dispatch\",\n ...workspaceApps.map((app) => app.id.trim().toLowerCase()),\n ]);\n const seen = new Set<string>();\n\n return connectedApps\n .filter((app) => {\n const id = app.id.trim().toLowerCase();\n if (\n !id ||\n isDefaultWorkspaceAppHiddenId(id) ||\n HIDDEN_OTHER_APP_IDS.has(id) ||\n workspaceAppIds.has(id) ||\n seen.has(id)\n )\n return false;\n if (app.source !== \"custom\") return false;\n if (!isHttpUrl(app.url)) return false;\n seen.add(id);\n return true;\n })\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\n/**\n * Hosted apps for launcher surfaces. Rows the organization hides are left out\n * unless `includeHiddenFromLaunchers` is set, which callers that resolve an\n * app id to open (pane restore, `open_app`) need.\n */\nexport function filterBuiltInApps(\n connectedApps: ConnectedAppSummary[],\n workspaceApps: WorkspaceAppId[],\n { includeHiddenFromLaunchers = false } = {},\n): ConnectedAppSummary[] {\n const workspaceAppIds = new Set([\n \"dispatch\",\n ...workspaceApps.map((app) => app.id.trim().toLowerCase()),\n ]);\n const seen = new Set<string>();\n\n return connectedApps\n .filter((app) => {\n const id = app.id.trim().toLowerCase();\n const url = app.homeUrl?.trim() || app.url;\n if (\n !id ||\n app.source !== \"builtin\" ||\n (app.hiddenFromLaunchers && !includeHiddenFromLaunchers) ||\n isDefaultWorkspaceAppHiddenId(id) ||\n workspaceAppIds.has(id) ||\n seen.has(id) ||\n !isHttpUrl(url)\n ) {\n return false;\n }\n seen.add(id);\n return true;\n })\n .map((app) => ({\n ...app,\n url: defaultWorkspaceAppUrl(app.url),\n ...(app.homeUrl ? { homeUrl: defaultWorkspaceAppUrl(app.homeUrl) } : {}),\n }))\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n"]}
|
|
@@ -7,13 +7,69 @@ export declare function orderWorkspaceApps<T extends {
|
|
|
7
7
|
}>(apps: readonly T[], layout: ChatFirstAppLayoutPreference): T[];
|
|
8
8
|
export declare function workspaceAppMatchesQuery(app: {
|
|
9
9
|
name: string;
|
|
10
|
-
description?: string;
|
|
10
|
+
description?: string | undefined;
|
|
11
11
|
}, query: string): boolean;
|
|
12
|
-
|
|
13
|
-
export declare function
|
|
12
|
+
/** Pins (newest first) or unpins `appId`; a no-op when it already matches. */
|
|
13
|
+
export declare function setWorkspaceAppPinned(layout: ChatFirstAppLayoutPreference, appId: string, pinned: boolean): ChatFirstAppLayoutPreference;
|
|
14
|
+
export type WorkspaceAppsStatus = "loading" | "error" | "ready";
|
|
15
|
+
/**
|
|
16
|
+
* The workspace app list is known once it has arrived, and a failed refresh
|
|
17
|
+
* keeps the last one. Until then nothing can be tiered: an empty list is not
|
|
18
|
+
* "no apps", and a hosted app cannot be told from a mounted one.
|
|
19
|
+
*/
|
|
20
|
+
export declare function workspaceAppsStatus(query: {
|
|
21
|
+
data: unknown;
|
|
22
|
+
isError: boolean;
|
|
23
|
+
}): WorkspaceAppsStatus;
|
|
24
|
+
/**
|
|
25
|
+
* Both app lists: ready once workspace apps arrived and the hosted list has
|
|
26
|
+
* settled (arrived or failed), so the tiers, and the header actions placed by
|
|
27
|
+
* them, do not reshuffle when hosted apps land a moment later.
|
|
28
|
+
*/
|
|
29
|
+
export declare function appListsStatus(workspaceApps: {
|
|
30
|
+
data: unknown;
|
|
31
|
+
isError: boolean;
|
|
32
|
+
}, connectedApps: {
|
|
33
|
+
data: unknown;
|
|
34
|
+
isError: boolean;
|
|
35
|
+
}): WorkspaceAppsStatus;
|
|
36
|
+
/** Whether any of `apps` is pinned, before a search narrows the list. */
|
|
37
|
+
export declare function hasPinnedWorkspaceApp(apps: readonly {
|
|
38
|
+
id: string;
|
|
39
|
+
}[], layout: ChatFirstAppLayoutPreference): boolean;
|
|
40
|
+
export interface WorkspaceAppTiers<T> {
|
|
41
|
+
pinned: T[];
|
|
42
|
+
apps: T[];
|
|
43
|
+
hosted: T[];
|
|
44
|
+
}
|
|
45
|
+
export declare function compareWorkspaceAppNames(a: {
|
|
46
|
+
name: string;
|
|
47
|
+
}, b: {
|
|
48
|
+
name: string;
|
|
49
|
+
}): number;
|
|
50
|
+
/**
|
|
51
|
+
* Pinned apps leave their home tier and keep pin order (newest first). The
|
|
52
|
+
* Apps and Hosted apps (built-in catalog) tiers each sort A to Z.
|
|
53
|
+
*/
|
|
54
|
+
export declare function tierWorkspaceApps<T extends {
|
|
55
|
+
id: string;
|
|
56
|
+
name: string;
|
|
57
|
+
source?: string | undefined;
|
|
58
|
+
}>(apps: readonly T[], layout: ChatFirstAppLayoutPreference): WorkspaceAppTiers<T>;
|
|
59
|
+
type WorkspaceAppLayoutUpdate = (layout: ChatFirstAppLayoutPreference) => ChatFirstAppLayoutPreference;
|
|
60
|
+
export declare function updateWorkspaceAppLayout(update: WorkspaceAppLayoutUpdate): void;
|
|
61
|
+
declare function togglePinned(appId: string): void;
|
|
62
|
+
/** Test-only: forget the page's layout so the next read starts from storage. */
|
|
63
|
+
export declare function resetWorkspaceAppLayoutStoreForTests(): void;
|
|
64
|
+
export declare function useWorkspaceAppLayout({ hydrate, }?: {
|
|
65
|
+
hydrate?: boolean;
|
|
66
|
+
}): {
|
|
14
67
|
layout: ChatFirstAppLayoutPreference;
|
|
15
|
-
persistenceError:
|
|
16
|
-
|
|
17
|
-
|
|
68
|
+
persistenceError: {
|
|
69
|
+
scope: WorkspaceAppLayoutPersistenceError;
|
|
70
|
+
writeId: number;
|
|
71
|
+
} | null;
|
|
72
|
+
togglePinned: typeof togglePinned;
|
|
18
73
|
};
|
|
74
|
+
export {};
|
|
19
75
|
//# sourceMappingURL=workspace-app-layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-app-layout.d.ts","sourceRoot":"","sources":["../../src/lib/workspace-app-layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,4BAA4B,EAClC,MAAM,sCAAsC,CAAC;AAO9C,eAAO,MAAM,8BAA8B,0BAA0B,CAAC;AAEtE,MAAM,MAAM,kCAAkC,GAC1C,QAAQ,GACR,WAAW,GACX,MAAM,CAAC;AAEX,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,GACb,4BAA4B,CAwB9B;AAED,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACzD,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,MAAM,EAAE,4BAA4B,GACnC,CAAC,EAAE,CAQL;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"workspace-app-layout.d.ts","sourceRoot":"","sources":["../../src/lib/workspace-app-layout.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,4BAA4B,EAClC,MAAM,sCAAsC,CAAC;AAO9C,eAAO,MAAM,8BAA8B,0BAA0B,CAAC;AAEtE,MAAM,MAAM,kCAAkC,GAC1C,QAAQ,GACR,WAAW,GACX,MAAM,CAAC;AAEX,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,GACb,4BAA4B,CAwB9B;AAED,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EACzD,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,MAAM,EAAE,4BAA4B,GACnC,CAAC,EAAE,CAQL;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EACvD,KAAK,EAAE,MAAM,GACZ,OAAO,CAMT;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,4BAA4B,EACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,GACd,4BAA4B,CAS9B;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhE;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,mBAAmB,CAGtB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,aAAa,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,EAClD,aAAa,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACjD,mBAAmB,CAMrB;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EAC/B,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAGT;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,MAAM,EAAE,CAAC,EAAE,CAAC;IACZ,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,MAAM,EAAE,CAAC,EAAE,CAAC;CACb;AAED,wBAAgB,wBAAwB,CACtC,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACnB,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAClB,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,EAEnE,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,MAAM,EAAE,4BAA4B,GACnC,iBAAiB,CAAC,CAAC,CAAC,CAkBtB;AAWD,KAAK,wBAAwB,GAAG,CAC9B,MAAM,EAAE,4BAA4B,KACjC,4BAA4B,CAAC;AAyHlC,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,wBAAwB,QAWxE;AAID,iBAAS,YAAY,CAAC,KAAK,EAAE,MAAM,QAOlC;AAED,gFAAgF;AAChF,wBAAgB,oCAAoC,SAOnD;AAED,wBAAgB,qBAAqB,CAAC,EACpC,OAAc,GACf,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO;;;eApKlB,kCAAkC;iBAChC,MAAM;;;EA6KlB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { orderChatFirstAppIds, readChatFirstAppLayout, writeChatFirstAppLayout, } from "@agent-native/core/client/agent-chat";
|
|
2
2
|
import { readClientAppState, writeClientAppState, } from "@agent-native/core/client/application-state";
|
|
3
|
-
import {
|
|
3
|
+
import { useEffect, useSyncExternalStore } from "react";
|
|
4
4
|
export const WORKSPACE_APP_LAYOUT_STATE_KEY = "chat-first-app-layout";
|
|
5
5
|
export function normalizeWorkspaceAppLayout(value) {
|
|
6
6
|
if (!value || typeof value !== "object") {
|
|
@@ -34,50 +34,205 @@ export function workspaceAppMatchesQuery(app, query) {
|
|
|
34
34
|
.toLowerCase()
|
|
35
35
|
.includes(normalizedQuery);
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
/** Pins (newest first) or unpins `appId`; a no-op when it already matches. */
|
|
38
|
+
export function setWorkspaceAppPinned(layout, appId, pinned) {
|
|
38
39
|
const normalizedLayout = normalizeWorkspaceAppLayout(layout);
|
|
39
40
|
const normalizedAppId = appId.trim().toLowerCase();
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const isPinned = normalizedLayout.pinnedIds.includes(normalizedAppId);
|
|
42
|
+
if (isPinned === pinned)
|
|
43
|
+
return normalizedLayout;
|
|
44
|
+
const pinnedIds = pinned
|
|
45
|
+
? [normalizedAppId, ...normalizedLayout.pinnedIds]
|
|
46
|
+
: normalizedLayout.pinnedIds.filter((id) => id !== normalizedAppId);
|
|
43
47
|
return { ...normalizedLayout, pinnedIds };
|
|
44
48
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The workspace app list is known once it has arrived, and a failed refresh
|
|
51
|
+
* keeps the last one. Until then nothing can be tiered: an empty list is not
|
|
52
|
+
* "no apps", and a hosted app cannot be told from a mounted one.
|
|
53
|
+
*/
|
|
54
|
+
export function workspaceAppsStatus(query) {
|
|
55
|
+
if (query.data !== undefined)
|
|
56
|
+
return "ready";
|
|
57
|
+
return query.isError ? "error" : "loading";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Both app lists: ready once workspace apps arrived and the hosted list has
|
|
61
|
+
* settled (arrived or failed), so the tiers, and the header actions placed by
|
|
62
|
+
* them, do not reshuffle when hosted apps land a moment later.
|
|
63
|
+
*/
|
|
64
|
+
export function appListsStatus(workspaceApps, connectedApps) {
|
|
65
|
+
const status = workspaceAppsStatus(workspaceApps);
|
|
66
|
+
if (status !== "ready")
|
|
67
|
+
return status;
|
|
68
|
+
return connectedApps.data === undefined && !connectedApps.isError
|
|
69
|
+
? "loading"
|
|
70
|
+
: "ready";
|
|
71
|
+
}
|
|
72
|
+
/** Whether any of `apps` is pinned, before a search narrows the list. */
|
|
73
|
+
export function hasPinnedWorkspaceApp(apps, layout) {
|
|
74
|
+
const pinned = new Set(normalizeWorkspaceAppLayout(layout).pinnedIds);
|
|
75
|
+
return apps.some((app) => pinned.has(app.id.trim().toLowerCase()));
|
|
76
|
+
}
|
|
77
|
+
export function compareWorkspaceAppNames(a, b) {
|
|
78
|
+
return a.name.localeCompare(b.name);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Pinned apps leave their home tier and keep pin order (newest first). The
|
|
82
|
+
* Apps and Hosted apps (built-in catalog) tiers each sort A to Z.
|
|
83
|
+
*/
|
|
84
|
+
export function tierWorkspaceApps(apps, layout) {
|
|
85
|
+
const appsById = new Map(apps.map((app) => [app.id.trim().toLowerCase(), app]));
|
|
86
|
+
const pinned = normalizeWorkspaceAppLayout(layout)
|
|
87
|
+
.pinnedIds.map((id) => appsById.get(id))
|
|
88
|
+
.filter((app) => Boolean(app));
|
|
89
|
+
const pinnedSet = new Set(pinned);
|
|
90
|
+
const unpinned = apps.filter((app) => !pinnedSet.has(app));
|
|
91
|
+
return {
|
|
92
|
+
pinned,
|
|
93
|
+
apps: unpinned
|
|
94
|
+
.filter((app) => app.source !== "builtin")
|
|
95
|
+
.sort(compareWorkspaceAppNames),
|
|
96
|
+
hosted: unpinned
|
|
97
|
+
.filter((app) => app.source === "builtin")
|
|
98
|
+
.sort(compareWorkspaceAppNames),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
const SERVER_SNAPSHOT = {
|
|
102
|
+
layout: { pinnedIds: [], orderedIds: [] },
|
|
103
|
+
persistenceError: null,
|
|
104
|
+
};
|
|
105
|
+
// One store per page: every surface reads and writes the same pins, so a
|
|
106
|
+
// write always starts from the latest layout instead of a surface's copy.
|
|
107
|
+
let snapshot = null;
|
|
108
|
+
// Workspace state is written only after it has been read: until then a write
|
|
109
|
+
// would replace saved pins this page never saw. "failed" retries the read.
|
|
110
|
+
let hydration = "idle";
|
|
111
|
+
// Changes made before workspace state was read. They replay onto the read
|
|
112
|
+
// layout, then persist.
|
|
113
|
+
let pendingUpdates = [];
|
|
114
|
+
let deviceSaved = true;
|
|
115
|
+
let writeSequence = 0;
|
|
116
|
+
const listeners = new Set();
|
|
117
|
+
function currentSnapshot() {
|
|
118
|
+
snapshot ??= {
|
|
119
|
+
layout: normalizeWorkspaceAppLayout(readChatFirstAppLayout()),
|
|
120
|
+
persistenceError: null,
|
|
121
|
+
};
|
|
122
|
+
return snapshot;
|
|
123
|
+
}
|
|
124
|
+
function setSnapshot(next) {
|
|
125
|
+
snapshot = { ...currentSnapshot(), ...next };
|
|
126
|
+
for (const listener of listeners)
|
|
127
|
+
listener();
|
|
128
|
+
}
|
|
129
|
+
function writeDeviceLayout(next) {
|
|
130
|
+
deviceSaved = writeChatFirstAppLayout(next).ok;
|
|
131
|
+
}
|
|
132
|
+
function settlePersistence(writeId, workspaceSaved) {
|
|
133
|
+
if (writeId !== writeSequence)
|
|
134
|
+
return;
|
|
135
|
+
const scope = workspaceSaved
|
|
136
|
+
? deviceSaved
|
|
137
|
+
? null
|
|
138
|
+
: "device"
|
|
139
|
+
: deviceSaved
|
|
140
|
+
? "workspace"
|
|
141
|
+
: "both";
|
|
142
|
+
setSnapshot({ persistenceError: scope ? { scope, writeId } : null });
|
|
143
|
+
}
|
|
144
|
+
function persistWorkspaceAppLayout(next) {
|
|
145
|
+
writeDeviceLayout(next);
|
|
146
|
+
const writeId = ++writeSequence;
|
|
147
|
+
void writeClientAppState(WORKSPACE_APP_LAYOUT_STATE_KEY, next).then(() => settlePersistence(writeId, true), () => settlePersistence(writeId, false));
|
|
148
|
+
}
|
|
149
|
+
function finishHydration(saved) {
|
|
150
|
+
hydration = "done";
|
|
151
|
+
const updates = pendingUpdates;
|
|
152
|
+
pendingUpdates = [];
|
|
153
|
+
// Absent workspace state keeps the device layout, which already holds the
|
|
154
|
+
// queued updates.
|
|
155
|
+
const next = saved
|
|
156
|
+
? updates.reduce((layout, update) => normalizeWorkspaceAppLayout(update(layout)), saved)
|
|
157
|
+
: currentSnapshot().layout;
|
|
158
|
+
setSnapshot({ layout: next });
|
|
159
|
+
if (updates.length > 0) {
|
|
160
|
+
persistWorkspaceAppLayout(next);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (saved)
|
|
164
|
+
writeDeviceLayout(next);
|
|
165
|
+
// Nothing was saved before this read, so the only error it can clear is
|
|
166
|
+
// the earlier read failure.
|
|
167
|
+
setSnapshot({ persistenceError: null });
|
|
168
|
+
}
|
|
169
|
+
function isSavedWorkspaceAppLayout(value) {
|
|
170
|
+
if (!value || typeof value !== "object")
|
|
171
|
+
return false;
|
|
172
|
+
const candidate = value;
|
|
173
|
+
return (Array.isArray(candidate.pinnedIds) && Array.isArray(candidate.orderedIds));
|
|
174
|
+
}
|
|
175
|
+
function hydrateWorkspaceAppLayout() {
|
|
176
|
+
if (hydration === "pending" || hydration === "done")
|
|
177
|
+
return;
|
|
178
|
+
hydration = "pending";
|
|
179
|
+
void readClientAppState(WORKSPACE_APP_LAYOUT_STATE_KEY).then((value) => {
|
|
180
|
+
if (value === null)
|
|
181
|
+
return finishHydration(null);
|
|
182
|
+
// A malformed value is not "no pins": treat it as absent so the device
|
|
183
|
+
// pins survive, and the next save replaces it.
|
|
184
|
+
if (!isSavedWorkspaceAppLayout(value)) {
|
|
185
|
+
console.warn(`[dispatch] ignoring malformed ${WORKSPACE_APP_LAYOUT_STATE_KEY}`, value);
|
|
186
|
+
return finishHydration(null);
|
|
187
|
+
}
|
|
188
|
+
finishHydration(normalizeWorkspaceAppLayout(value));
|
|
189
|
+
}, () => {
|
|
190
|
+
hydration = "failed";
|
|
191
|
+
// Only unsaved pins make a failed read worth reporting.
|
|
192
|
+
if (pendingUpdates.length > 0)
|
|
193
|
+
settlePersistence(++writeSequence, false);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
function subscribe(listener) {
|
|
197
|
+
listeners.add(listener);
|
|
198
|
+
return () => {
|
|
199
|
+
listeners.delete(listener);
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
export function updateWorkspaceAppLayout(update) {
|
|
203
|
+
const next = normalizeWorkspaceAppLayout(update(currentSnapshot().layout));
|
|
204
|
+
setSnapshot({ layout: next });
|
|
205
|
+
if (hydration === "done") {
|
|
206
|
+
persistWorkspaceAppLayout(next);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
pendingUpdates.push(update);
|
|
210
|
+
writeDeviceLayout(next);
|
|
211
|
+
if (hydration === "failed")
|
|
212
|
+
settlePersistence(++writeSequence, false);
|
|
213
|
+
hydrateWorkspaceAppLayout();
|
|
214
|
+
}
|
|
215
|
+
// The click decides pin or unpin from what is on screen, so a change replayed
|
|
216
|
+
// onto workspace pins read later keeps that intent.
|
|
217
|
+
function togglePinned(appId) {
|
|
218
|
+
const pinned = !currentSnapshot().layout.pinnedIds.includes(appId.trim().toLowerCase());
|
|
219
|
+
updateWorkspaceAppLayout((layout) => setWorkspaceAppPinned(layout, appId, pinned));
|
|
220
|
+
}
|
|
221
|
+
/** Test-only: forget the page's layout so the next read starts from storage. */
|
|
222
|
+
export function resetWorkspaceAppLayoutStoreForTests() {
|
|
223
|
+
snapshot = null;
|
|
224
|
+
hydration = "idle";
|
|
225
|
+
pendingUpdates = [];
|
|
226
|
+
deviceSaved = true;
|
|
227
|
+
writeSequence = 0;
|
|
228
|
+
listeners.clear();
|
|
229
|
+
}
|
|
230
|
+
export function useWorkspaceAppLayout({ hydrate = true, } = {}) {
|
|
231
|
+
const { layout, persistenceError } = useSyncExternalStore(subscribe, currentSnapshot, () => SERVER_SNAPSHOT);
|
|
50
232
|
useEffect(() => {
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.then((value) => {
|
|
56
|
-
if (value !== null && !localChangeRef.current) {
|
|
57
|
-
setLayout(normalizeWorkspaceAppLayout(value));
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
.catch(() => {
|
|
61
|
-
// Device-local preferences remain usable when workspace state is unavailable.
|
|
62
|
-
});
|
|
63
|
-
}, []);
|
|
64
|
-
const persistLayout = useCallback((next) => {
|
|
65
|
-
localChangeRef.current = true;
|
|
66
|
-
const normalizedNext = normalizeWorkspaceAppLayout(next);
|
|
67
|
-
setLayout(normalizedNext);
|
|
68
|
-
const deviceResult = writeChatFirstAppLayout(normalizedNext);
|
|
69
|
-
const deviceFailed = !deviceResult.ok;
|
|
70
|
-
void writeClientAppState(WORKSPACE_APP_LAYOUT_STATE_KEY, normalizedNext)
|
|
71
|
-
.then(() => {
|
|
72
|
-
setPersistenceError(deviceFailed ? "device" : null);
|
|
73
|
-
})
|
|
74
|
-
.catch(() => {
|
|
75
|
-
setPersistenceError(deviceFailed ? "both" : "workspace");
|
|
76
|
-
});
|
|
77
|
-
}, []);
|
|
78
|
-
const togglePinned = useCallback((appId) => {
|
|
79
|
-
persistLayout(toggleWorkspaceAppPinned(layout, appId));
|
|
80
|
-
}, [layout, persistLayout]);
|
|
81
|
-
return { layout, persistenceError, persistLayout, togglePinned };
|
|
233
|
+
if (hydrate)
|
|
234
|
+
hydrateWorkspaceAppLayout();
|
|
235
|
+
}, [hydrate]);
|
|
236
|
+
return { layout, persistenceError, togglePinned };
|
|
82
237
|
}
|
|
83
238
|
//# sourceMappingURL=workspace-app-layout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-app-layout.js","sourceRoot":"","sources":["../../src/lib/workspace-app-layout.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n orderChatFirstAppIds,\n readChatFirstAppLayout,\n writeChatFirstAppLayout,\n type ChatFirstAppLayoutPreference,\n} from \"@agent-native/core/client/agent-chat\";\nimport {\n readClientAppState,\n writeClientAppState,\n} from \"@agent-native/core/client/application-state\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport const WORKSPACE_APP_LAYOUT_STATE_KEY = \"chat-first-app-layout\";\n\nexport type WorkspaceAppLayoutPersistenceError =\n | \"device\"\n | \"workspace\"\n | \"both\";\n\nexport function normalizeWorkspaceAppLayout(\n value: unknown,\n): ChatFirstAppLayoutPreference {\n if (!value || typeof value !== \"object\") {\n return { pinnedIds: [], orderedIds: [] };\n }\n\n const candidate = value as Partial<ChatFirstAppLayoutPreference>;\n const ids = (input: unknown): string[] =>\n Array.isArray(input)\n ? [\n ...new Set(\n input\n .filter(\n (id): id is string =>\n typeof id === \"string\" && id.trim().length > 0,\n )\n .map((id) => id.trim().toLowerCase()),\n ),\n ]\n : [];\n\n return {\n pinnedIds: ids(candidate.pinnedIds),\n orderedIds: ids(candidate.orderedIds),\n };\n}\n\nexport function orderWorkspaceApps<T extends { id: string }>(\n apps: readonly T[],\n layout: ChatFirstAppLayoutPreference,\n): T[] {\n const appIds = apps.map((app) => app.id.trim().toLowerCase());\n const appsById = new Map(\n apps.map((app) => [app.id.trim().toLowerCase(), app]),\n );\n return orderChatFirstAppIds(appIds, normalizeWorkspaceAppLayout(layout))\n .map((id) => appsById.get(id))\n .filter((app): app is T => Boolean(app));\n}\n\nexport function workspaceAppMatchesQuery(\n app: { name: string; description?: string },\n query: string,\n): boolean {\n const normalizedQuery = query.trim().toLowerCase();\n if (!normalizedQuery) return true;\n return `${app.name} ${app.description ?? \"\"}`\n .toLowerCase()\n .includes(normalizedQuery);\n}\n\nexport function toggleWorkspaceAppPinned(\n layout: ChatFirstAppLayoutPreference,\n appId: string,\n): ChatFirstAppLayoutPreference {\n const normalizedLayout = normalizeWorkspaceAppLayout(layout);\n const normalizedAppId = appId.trim().toLowerCase();\n const pinnedIds = normalizedLayout.pinnedIds.includes(normalizedAppId)\n ? normalizedLayout.pinnedIds.filter((id) => id !== normalizedAppId)\n : [normalizedAppId, ...normalizedLayout.pinnedIds];\n return { ...normalizedLayout, pinnedIds };\n}\n\nexport function useWorkspaceAppLayout() {\n const [layout, setLayout] = useState<ChatFirstAppLayoutPreference>(() =>\n normalizeWorkspaceAppLayout(readChatFirstAppLayout()),\n );\n const [persistenceError, setPersistenceError] =\n useState<WorkspaceAppLayoutPersistenceError | null>(null);\n const hydratedRef = useRef(false);\n const localChangeRef = useRef(false);\n\n useEffect(() => {\n if (hydratedRef.current) return;\n hydratedRef.current = true;\n void readClientAppState<unknown>(WORKSPACE_APP_LAYOUT_STATE_KEY)\n .then((value) => {\n if (value !== null && !localChangeRef.current) {\n setLayout(normalizeWorkspaceAppLayout(value));\n }\n })\n .catch(() => {\n // Device-local preferences remain usable when workspace state is unavailable.\n });\n }, []);\n\n const persistLayout = useCallback((next: ChatFirstAppLayoutPreference) => {\n localChangeRef.current = true;\n const normalizedNext = normalizeWorkspaceAppLayout(next);\n setLayout(normalizedNext);\n const deviceResult = writeChatFirstAppLayout(normalizedNext);\n const deviceFailed = !deviceResult.ok;\n\n void writeClientAppState(WORKSPACE_APP_LAYOUT_STATE_KEY, normalizedNext)\n .then(() => {\n setPersistenceError(deviceFailed ? \"device\" : null);\n })\n .catch(() => {\n setPersistenceError(deviceFailed ? \"both\" : \"workspace\");\n });\n }, []);\n\n const togglePinned = useCallback(\n (appId: string) => {\n persistLayout(toggleWorkspaceAppPinned(layout, appId));\n },\n [layout, persistLayout],\n );\n\n return { layout, persistenceError, persistLayout, togglePinned };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"workspace-app-layout.js","sourceRoot":"","sources":["../../src/lib/workspace-app-layout.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,GAExB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAExD,MAAM,CAAC,MAAM,8BAA8B,GAAG,uBAAuB,CAAC;AAOtE,MAAM,UAAU,2BAA2B,CACzC,KAAc;IAEd,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,SAAS,GAAG,KAA8C,CAAC;IACjE,MAAM,GAAG,GAAG,CAAC,KAAc,EAAY,EAAE,CACvC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAClB,CAAC,CAAC;YACE,GAAG,IAAI,GAAG,CACR,KAAK;iBACF,MAAM,CACL,CAAC,EAAE,EAAgB,EAAE,CACnB,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CACjD;iBACA,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CACxC;SACF;QACH,CAAC,CAAC,EAAE,CAAC;IAET,OAAO;QACL,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC;QACnC,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,IAAkB,EAClB,MAAoC;IAEpC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9D,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC,CACtD,CAAC;IACF,OAAO,oBAAoB,CAAC,MAAM,EAAE,2BAA2B,CAAC,MAAM,CAAC,CAAC;SACrE,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SAC7B,MAAM,CAAC,CAAC,GAAG,EAAY,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,GAAuD,EACvD,KAAa;IAEb,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,IAAI,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,WAAW,IAAI,EAAE,EAAE;SAC1C,WAAW,EAAE;SACb,QAAQ,CAAC,eAAe,CAAC,CAAC;AAC/B,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,qBAAqB,CACnC,MAAoC,EACpC,KAAa,EACb,MAAe;IAEf,MAAM,gBAAgB,GAAG,2BAA2B,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACtE,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,gBAAgB,CAAC;IACjD,MAAM,SAAS,GAAG,MAAM;QACtB,CAAC,CAAC,CAAC,eAAe,EAAE,GAAG,gBAAgB,CAAC,SAAS,CAAC;QAClD,CAAC,CAAC,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,eAAe,CAAC,CAAC;IACtE,OAAO,EAAE,GAAG,gBAAgB,EAAE,SAAS,EAAE,CAAC;AAC5C,CAAC;AAID;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAGnC;IACC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IAC7C,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,aAAkD,EAClD,aAAkD;IAElD,MAAM,MAAM,GAAG,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IACtC,OAAO,aAAa,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,OAAO;QAC/D,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,OAAO,CAAC;AACd,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,qBAAqB,CACnC,IAA+B,EAC/B,MAAoC;IAEpC,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,2BAA2B,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC;AAQD,MAAM,UAAU,wBAAwB,CACtC,CAAmB,EACnB,CAAmB;IAEnB,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAG/B,IAAkB,EAClB,MAAoC;IAEpC,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC,CACtD,CAAC;IACF,MAAM,MAAM,GAAG,2BAA2B,CAAC,MAAM,CAAC;SAC/C,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SACvC,MAAM,CAAC,CAAC,GAAG,EAAY,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,OAAO;QACL,MAAM;QACN,IAAI,EAAE,QAAQ;aACX,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;aACzC,IAAI,CAAC,wBAAwB,CAAC;QACjC,MAAM,EAAE,QAAQ;aACb,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC;aACzC,IAAI,CAAC,wBAAwB,CAAC;KAClC,CAAC;AACJ,CAAC;AAeD,MAAM,eAAe,GAA+B;IAClD,MAAM,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;IACzC,gBAAgB,EAAE,IAAI;CACvB,CAAC;AAEF,yEAAyE;AACzE,0EAA0E;AAC1E,IAAI,QAAQ,GAAsC,IAAI,CAAC;AACvD,6EAA6E;AAC7E,2EAA2E;AAC3E,IAAI,SAAS,GAA2C,MAAM,CAAC;AAC/D,0EAA0E;AAC1E,wBAAwB;AACxB,IAAI,cAAc,GAA+B,EAAE,CAAC;AACpD,IAAI,WAAW,GAAG,IAAI,CAAC;AACvB,IAAI,aAAa,GAAG,CAAC,CAAC;AACtB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAC;AAExC,SAAS,eAAe;IACtB,QAAQ,KAAK;QACX,MAAM,EAAE,2BAA2B,CAAC,sBAAsB,EAAE,CAAC;QAC7D,gBAAgB,EAAE,IAAI;KACvB,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,WAAW,CAAC,IAAyC;IAC5D,QAAQ,GAAG,EAAE,GAAG,eAAe,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7C,KAAK,MAAM,QAAQ,IAAI,SAAS;QAAE,QAAQ,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAkC;IAC3D,WAAW,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;AACjD,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe,EAAE,cAAuB;IACjE,IAAI,OAAO,KAAK,aAAa;QAAE,OAAO;IACtC,MAAM,KAAK,GAA8C,cAAc;QACrE,CAAC,CAAC,WAAW;YACX,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,QAAQ;QACZ,CAAC,CAAC,WAAW;YACX,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,yBAAyB,CAAC,IAAkC;IACnE,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACxB,MAAM,OAAO,GAAG,EAAE,aAAa,CAAC;IAChC,KAAK,mBAAmB,CAAC,8BAA8B,EAAE,IAAI,CAAC,CAAC,IAAI,CACjE,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,EACtC,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,CACxC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAA0C;IACjE,SAAS,GAAG,MAAM,CAAC;IACnB,MAAM,OAAO,GAAG,cAAc,CAAC;IAC/B,cAAc,GAAG,EAAE,CAAC;IACpB,0EAA0E;IAC1E,kBAAkB;IAClB,MAAM,IAAI,GAAG,KAAK;QAChB,CAAC,CAAC,OAAO,CAAC,MAAM,CACZ,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,2BAA2B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAC/D,KAAK,CACN;QACH,CAAC,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,yBAAyB,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IACD,IAAI,KAAK;QAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACnC,wEAAwE;IACxE,4BAA4B;IAC5B,WAAW,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAc;IAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,SAAS,GAAG,KAAgC,CAAC;IACnD,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,CAC1E,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB;IAChC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,MAAM;QAAE,OAAO;IAC5D,SAAS,GAAG,SAAS,CAAC;IACtB,KAAK,kBAAkB,CAAU,8BAA8B,CAAC,CAAC,IAAI,CACnE,CAAC,KAAK,EAAE,EAAE;QACR,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;QACjD,uEAAuE;QACvE,+CAA+C;QAC/C,IAAI,CAAC,yBAAyB,CAAC,KAAK,CAAC,EAAE,CAAC;YACtC,OAAO,CAAC,IAAI,CACV,iCAAiC,8BAA8B,EAAE,EACjE,KAAK,CACN,CAAC;YACF,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QACD,eAAe,CAAC,2BAA2B,CAAC,KAAK,CAAC,CAAC,CAAC;IACtD,CAAC,EACD,GAAG,EAAE;QACH,SAAS,GAAG,QAAQ,CAAC;QACrB,wDAAwD;QACxD,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;YAAE,iBAAiB,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;IAC3E,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,QAAoB;IACrC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,GAAG,EAAE;QACV,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAgC;IACvE,MAAM,IAAI,GAAG,2BAA2B,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3E,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9B,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,yBAAyB,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IACD,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,SAAS,KAAK,QAAQ;QAAE,iBAAiB,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;IACtE,yBAAyB,EAAE,CAAC;AAC9B,CAAC;AAED,8EAA8E;AAC9E,oDAAoD;AACpD,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,MAAM,GAAG,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CACzD,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAC3B,CAAC;IACF,wBAAwB,CAAC,CAAC,MAAM,EAAE,EAAE,CAClC,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAC7C,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,oCAAoC;IAClD,QAAQ,GAAG,IAAI,CAAC;IAChB,SAAS,GAAG,MAAM,CAAC;IACnB,cAAc,GAAG,EAAE,CAAC;IACpB,WAAW,GAAG,IAAI,CAAC;IACnB,aAAa,GAAG,CAAC,CAAC;IAClB,SAAS,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,EACpC,OAAO,GAAG,IAAI,GACf,GAA0B,EAAE;IAC3B,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,oBAAoB,CACvD,SAAS,EACT,eAAe,EACf,GAAG,EAAE,CAAC,eAAe,CACtB,CAAC;IACF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO;YAAE,yBAAyB,EAAE,CAAC;IAC3C,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAC;AACpD,CAAC","sourcesContent":["import {\n orderChatFirstAppIds,\n readChatFirstAppLayout,\n writeChatFirstAppLayout,\n type ChatFirstAppLayoutPreference,\n} from \"@agent-native/core/client/agent-chat\";\nimport {\n readClientAppState,\n writeClientAppState,\n} from \"@agent-native/core/client/application-state\";\nimport { useEffect, useSyncExternalStore } from \"react\";\n\nexport const WORKSPACE_APP_LAYOUT_STATE_KEY = \"chat-first-app-layout\";\n\nexport type WorkspaceAppLayoutPersistenceError =\n | \"device\"\n | \"workspace\"\n | \"both\";\n\nexport function normalizeWorkspaceAppLayout(\n value: unknown,\n): ChatFirstAppLayoutPreference {\n if (!value || typeof value !== \"object\") {\n return { pinnedIds: [], orderedIds: [] };\n }\n\n const candidate = value as Partial<ChatFirstAppLayoutPreference>;\n const ids = (input: unknown): string[] =>\n Array.isArray(input)\n ? [\n ...new Set(\n input\n .filter(\n (id): id is string =>\n typeof id === \"string\" && id.trim().length > 0,\n )\n .map((id) => id.trim().toLowerCase()),\n ),\n ]\n : [];\n\n return {\n pinnedIds: ids(candidate.pinnedIds),\n orderedIds: ids(candidate.orderedIds),\n };\n}\n\nexport function orderWorkspaceApps<T extends { id: string }>(\n apps: readonly T[],\n layout: ChatFirstAppLayoutPreference,\n): T[] {\n const appIds = apps.map((app) => app.id.trim().toLowerCase());\n const appsById = new Map(\n apps.map((app) => [app.id.trim().toLowerCase(), app]),\n );\n return orderChatFirstAppIds(appIds, normalizeWorkspaceAppLayout(layout))\n .map((id) => appsById.get(id))\n .filter((app): app is T => Boolean(app));\n}\n\nexport function workspaceAppMatchesQuery(\n app: { name: string; description?: string | undefined },\n query: string,\n): boolean {\n const normalizedQuery = query.trim().toLowerCase();\n if (!normalizedQuery) return true;\n return `${app.name} ${app.description ?? \"\"}`\n .toLowerCase()\n .includes(normalizedQuery);\n}\n\n/** Pins (newest first) or unpins `appId`; a no-op when it already matches. */\nexport function setWorkspaceAppPinned(\n layout: ChatFirstAppLayoutPreference,\n appId: string,\n pinned: boolean,\n): ChatFirstAppLayoutPreference {\n const normalizedLayout = normalizeWorkspaceAppLayout(layout);\n const normalizedAppId = appId.trim().toLowerCase();\n const isPinned = normalizedLayout.pinnedIds.includes(normalizedAppId);\n if (isPinned === pinned) return normalizedLayout;\n const pinnedIds = pinned\n ? [normalizedAppId, ...normalizedLayout.pinnedIds]\n : normalizedLayout.pinnedIds.filter((id) => id !== normalizedAppId);\n return { ...normalizedLayout, pinnedIds };\n}\n\nexport type WorkspaceAppsStatus = \"loading\" | \"error\" | \"ready\";\n\n/**\n * The workspace app list is known once it has arrived, and a failed refresh\n * keeps the last one. Until then nothing can be tiered: an empty list is not\n * \"no apps\", and a hosted app cannot be told from a mounted one.\n */\nexport function workspaceAppsStatus(query: {\n data: unknown;\n isError: boolean;\n}): WorkspaceAppsStatus {\n if (query.data !== undefined) return \"ready\";\n return query.isError ? \"error\" : \"loading\";\n}\n\n/**\n * Both app lists: ready once workspace apps arrived and the hosted list has\n * settled (arrived or failed), so the tiers, and the header actions placed by\n * them, do not reshuffle when hosted apps land a moment later.\n */\nexport function appListsStatus(\n workspaceApps: { data: unknown; isError: boolean },\n connectedApps: { data: unknown; isError: boolean },\n): WorkspaceAppsStatus {\n const status = workspaceAppsStatus(workspaceApps);\n if (status !== \"ready\") return status;\n return connectedApps.data === undefined && !connectedApps.isError\n ? \"loading\"\n : \"ready\";\n}\n\n/** Whether any of `apps` is pinned, before a search narrows the list. */\nexport function hasPinnedWorkspaceApp(\n apps: readonly { id: string }[],\n layout: ChatFirstAppLayoutPreference,\n): boolean {\n const pinned = new Set(normalizeWorkspaceAppLayout(layout).pinnedIds);\n return apps.some((app) => pinned.has(app.id.trim().toLowerCase()));\n}\n\nexport interface WorkspaceAppTiers<T> {\n pinned: T[];\n apps: T[];\n hosted: T[];\n}\n\nexport function compareWorkspaceAppNames(\n a: { name: string },\n b: { name: string },\n): number {\n return a.name.localeCompare(b.name);\n}\n\n/**\n * Pinned apps leave their home tier and keep pin order (newest first). The\n * Apps and Hosted apps (built-in catalog) tiers each sort A to Z.\n */\nexport function tierWorkspaceApps<\n T extends { id: string; name: string; source?: string | undefined },\n>(\n apps: readonly T[],\n layout: ChatFirstAppLayoutPreference,\n): WorkspaceAppTiers<T> {\n const appsById = new Map(\n apps.map((app) => [app.id.trim().toLowerCase(), app]),\n );\n const pinned = normalizeWorkspaceAppLayout(layout)\n .pinnedIds.map((id) => appsById.get(id))\n .filter((app): app is T => Boolean(app));\n const pinnedSet = new Set(pinned);\n const unpinned = apps.filter((app) => !pinnedSet.has(app));\n return {\n pinned,\n apps: unpinned\n .filter((app) => app.source !== \"builtin\")\n .sort(compareWorkspaceAppNames),\n hosted: unpinned\n .filter((app) => app.source === \"builtin\")\n .sort(compareWorkspaceAppNames),\n };\n}\n\ninterface WorkspaceAppLayoutSnapshot {\n layout: ChatFirstAppLayoutPreference;\n /** `writeId` is new for each save, so a dismissed notice shows again. */\n persistenceError: {\n scope: WorkspaceAppLayoutPersistenceError;\n writeId: number;\n } | null;\n}\n\ntype WorkspaceAppLayoutUpdate = (\n layout: ChatFirstAppLayoutPreference,\n) => ChatFirstAppLayoutPreference;\n\nconst SERVER_SNAPSHOT: WorkspaceAppLayoutSnapshot = {\n layout: { pinnedIds: [], orderedIds: [] },\n persistenceError: null,\n};\n\n// One store per page: every surface reads and writes the same pins, so a\n// write always starts from the latest layout instead of a surface's copy.\nlet snapshot: WorkspaceAppLayoutSnapshot | null = null;\n// Workspace state is written only after it has been read: until then a write\n// would replace saved pins this page never saw. \"failed\" retries the read.\nlet hydration: \"idle\" | \"pending\" | \"failed\" | \"done\" = \"idle\";\n// Changes made before workspace state was read. They replay onto the read\n// layout, then persist.\nlet pendingUpdates: WorkspaceAppLayoutUpdate[] = [];\nlet deviceSaved = true;\nlet writeSequence = 0;\nconst listeners = new Set<() => void>();\n\nfunction currentSnapshot(): WorkspaceAppLayoutSnapshot {\n snapshot ??= {\n layout: normalizeWorkspaceAppLayout(readChatFirstAppLayout()),\n persistenceError: null,\n };\n return snapshot;\n}\n\nfunction setSnapshot(next: Partial<WorkspaceAppLayoutSnapshot>) {\n snapshot = { ...currentSnapshot(), ...next };\n for (const listener of listeners) listener();\n}\n\nfunction writeDeviceLayout(next: ChatFirstAppLayoutPreference) {\n deviceSaved = writeChatFirstAppLayout(next).ok;\n}\n\nfunction settlePersistence(writeId: number, workspaceSaved: boolean) {\n if (writeId !== writeSequence) return;\n const scope: WorkspaceAppLayoutPersistenceError | null = workspaceSaved\n ? deviceSaved\n ? null\n : \"device\"\n : deviceSaved\n ? \"workspace\"\n : \"both\";\n setSnapshot({ persistenceError: scope ? { scope, writeId } : null });\n}\n\nfunction persistWorkspaceAppLayout(next: ChatFirstAppLayoutPreference) {\n writeDeviceLayout(next);\n const writeId = ++writeSequence;\n void writeClientAppState(WORKSPACE_APP_LAYOUT_STATE_KEY, next).then(\n () => settlePersistence(writeId, true),\n () => settlePersistence(writeId, false),\n );\n}\n\nfunction finishHydration(saved: ChatFirstAppLayoutPreference | null) {\n hydration = \"done\";\n const updates = pendingUpdates;\n pendingUpdates = [];\n // Absent workspace state keeps the device layout, which already holds the\n // queued updates.\n const next = saved\n ? updates.reduce(\n (layout, update) => normalizeWorkspaceAppLayout(update(layout)),\n saved,\n )\n : currentSnapshot().layout;\n setSnapshot({ layout: next });\n if (updates.length > 0) {\n persistWorkspaceAppLayout(next);\n return;\n }\n if (saved) writeDeviceLayout(next);\n // Nothing was saved before this read, so the only error it can clear is\n // the earlier read failure.\n setSnapshot({ persistenceError: null });\n}\n\nfunction isSavedWorkspaceAppLayout(value: unknown): boolean {\n if (!value || typeof value !== \"object\") return false;\n const candidate = value as Record<string, unknown>;\n return (\n Array.isArray(candidate.pinnedIds) && Array.isArray(candidate.orderedIds)\n );\n}\n\nfunction hydrateWorkspaceAppLayout() {\n if (hydration === \"pending\" || hydration === \"done\") return;\n hydration = \"pending\";\n void readClientAppState<unknown>(WORKSPACE_APP_LAYOUT_STATE_KEY).then(\n (value) => {\n if (value === null) return finishHydration(null);\n // A malformed value is not \"no pins\": treat it as absent so the device\n // pins survive, and the next save replaces it.\n if (!isSavedWorkspaceAppLayout(value)) {\n console.warn(\n `[dispatch] ignoring malformed ${WORKSPACE_APP_LAYOUT_STATE_KEY}`,\n value,\n );\n return finishHydration(null);\n }\n finishHydration(normalizeWorkspaceAppLayout(value));\n },\n () => {\n hydration = \"failed\";\n // Only unsaved pins make a failed read worth reporting.\n if (pendingUpdates.length > 0) settlePersistence(++writeSequence, false);\n },\n );\n}\n\nfunction subscribe(listener: () => void) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function updateWorkspaceAppLayout(update: WorkspaceAppLayoutUpdate) {\n const next = normalizeWorkspaceAppLayout(update(currentSnapshot().layout));\n setSnapshot({ layout: next });\n if (hydration === \"done\") {\n persistWorkspaceAppLayout(next);\n return;\n }\n pendingUpdates.push(update);\n writeDeviceLayout(next);\n if (hydration === \"failed\") settlePersistence(++writeSequence, false);\n hydrateWorkspaceAppLayout();\n}\n\n// The click decides pin or unpin from what is on screen, so a change replayed\n// onto workspace pins read later keeps that intent.\nfunction togglePinned(appId: string) {\n const pinned = !currentSnapshot().layout.pinnedIds.includes(\n appId.trim().toLowerCase(),\n );\n updateWorkspaceAppLayout((layout) =>\n setWorkspaceAppPinned(layout, appId, pinned),\n );\n}\n\n/** Test-only: forget the page's layout so the next read starts from storage. */\nexport function resetWorkspaceAppLayoutStoreForTests() {\n snapshot = null;\n hydration = \"idle\";\n pendingUpdates = [];\n deviceSaved = true;\n writeSequence = 0;\n listeners.clear();\n}\n\nexport function useWorkspaceAppLayout({\n hydrate = true,\n}: { hydrate?: boolean } = {}) {\n const { layout, persistenceError } = useSyncExternalStore(\n subscribe,\n currentSnapshot,\n () => SERVER_SNAPSHOT,\n );\n useEffect(() => {\n if (hydrate) hydrateWorkspaceAppLayout();\n }, [hydrate]);\n return { layout, persistenceError, togglePinned };\n}\n"]}
|