@anchrd/intel 0.59.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/README.md +496 -0
- package/bin/intel.mjs +134 -0
- package/dist/adapters/cloudflare/cloudflare-flow-workflow.d.ts +42 -0
- package/dist/adapters/cloudflare/cloudflare-flow-workflow.js +89 -0
- package/dist/adapters/cloudflare/cloudflare.d.ts +29 -0
- package/dist/adapters/cloudflare/cloudflare.js +416 -0
- package/dist/adapters/cloudflare/cloudflare.types.d.ts +31 -0
- package/dist/adapters/cloudflare/cloudflare.types.js +1 -0
- package/dist/adapters/content/content.d.ts +3 -0
- package/dist/adapters/content/content.js +128 -0
- package/dist/adapters/content/content.types.d.ts +38 -0
- package/dist/adapters/content/content.types.js +1 -0
- package/dist/adapters/db/db-audit.d.ts +62 -0
- package/dist/adapters/db/db-audit.js +150 -0
- package/dist/adapters/db/db-boards.d.ts +6 -0
- package/dist/adapters/db/db-boards.js +324 -0
- package/dist/adapters/db/db-feed.d.ts +30 -0
- package/dist/adapters/db/db-feed.js +276 -0
- package/dist/adapters/db/db-flows.d.ts +42 -0
- package/dist/adapters/db/db-flows.js +1311 -0
- package/dist/adapters/db/db-grants.d.ts +133 -0
- package/dist/adapters/db/db-grants.js +269 -0
- package/dist/adapters/db/db-indexing.d.ts +3 -0
- package/dist/adapters/db/db-indexing.js +200 -0
- package/dist/adapters/db/db-oauth.d.ts +3 -0
- package/dist/adapters/db/db-oauth.js +26 -0
- package/dist/adapters/db/db-prompts.d.ts +46 -0
- package/dist/adapters/db/db-prompts.js +144 -0
- package/dist/adapters/db/db.d.ts +6 -0
- package/dist/adapters/db/db.js +1687 -0
- package/dist/adapters/db/db.types.d.ts +16 -0
- package/dist/adapters/db/db.types.js +1 -0
- package/dist/adapters/document-converter/document-converter.d.ts +2 -0
- package/dist/adapters/document-converter/document-converter.js +26 -0
- package/dist/adapters/document-converter/document-converter.types.d.ts +17 -0
- package/dist/adapters/document-converter/document-converter.types.js +1 -0
- package/dist/adapters/flow-runtime/flow-runtime.d.ts +3 -0
- package/dist/adapters/flow-runtime/flow-runtime.js +22 -0
- package/dist/adapters/flow-runtime/flow-runtime.types.d.ts +19 -0
- package/dist/adapters/flow-runtime/flow-runtime.types.js +1 -0
- package/dist/adapters/index-queue/index-queue.d.ts +10 -0
- package/dist/adapters/index-queue/index-queue.js +12 -0
- package/dist/adapters/index-queue/index-queue.types.d.ts +11 -0
- package/dist/adapters/index-queue/index-queue.types.js +1 -0
- package/dist/adapters/json-schema/json-schema.d.ts +2 -0
- package/dist/adapters/json-schema/json-schema.js +77 -0
- package/dist/adapters/openid/openid.d.ts +5 -0
- package/dist/adapters/openid/openid.js +301 -0
- package/dist/adapters/portal-tokens/portal-tokens.d.ts +8 -0
- package/dist/adapters/portal-tokens/portal-tokens.js +79 -0
- package/dist/adapters/remote-tools/remote-tools.d.ts +5 -0
- package/dist/adapters/remote-tools/remote-tools.js +129 -0
- package/dist/adapters/semantic-index/semantic-index.d.ts +2 -0
- package/dist/adapters/semantic-index/semantic-index.js +139 -0
- package/dist/adapters/semantic-index/semantic-index.types.d.ts +56 -0
- package/dist/adapters/semantic-index/semantic-index.types.js +1 -0
- package/dist/adapters/session-cookie/session-cookie.d.ts +5 -0
- package/dist/adapters/session-cookie/session-cookie.js +87 -0
- package/dist/adapters/tool-source-policy/tool-source-policy.d.ts +1 -0
- package/dist/adapters/tool-source-policy/tool-source-policy.js +22 -0
- package/dist/audit/audit.d.ts +2 -0
- package/dist/audit/audit.js +87 -0
- package/dist/audit/audit.types.d.ts +23 -0
- package/dist/audit/audit.types.js +1 -0
- package/dist/auth/auth.d.ts +2 -0
- package/dist/auth/auth.js +284 -0
- package/dist/auth/auth.types.d.ts +108 -0
- package/dist/auth/auth.types.js +1 -0
- package/dist/boards/boards.d.ts +44 -0
- package/dist/boards/boards.js +447 -0
- package/dist/boards/boards.types.d.ts +117 -0
- package/dist/boards/boards.types.js +1 -0
- package/dist/build/build.d.ts +2 -0
- package/dist/build/build.js +192 -0
- package/dist/build/build.types.d.ts +17 -0
- package/dist/build/build.types.js +1 -0
- package/dist/bundle/bundle.d.ts +4 -0
- package/dist/bundle/bundle.js +1194 -0
- package/dist/bundle/bundle.types.d.ts +33 -0
- package/dist/bundle/bundle.types.js +1 -0
- package/dist/cli/cli.d.ts +4 -0
- package/dist/cli/cli.js +262 -0
- package/dist/cli/cli.types.d.ts +14 -0
- package/dist/cli/cli.types.js +1 -0
- package/dist/contract/audit.d.ts +50 -0
- package/dist/contract/audit.js +72 -0
- package/dist/contract/board.d.ts +150 -0
- package/dist/contract/board.js +262 -0
- package/dist/contract/bundle.d.ts +147 -0
- package/dist/contract/bundle.js +139 -0
- package/dist/contract/contract.d.ts +112 -0
- package/dist/contract/contract.js +143 -0
- package/dist/contract/feed.d.ts +126 -0
- package/dist/contract/feed.js +149 -0
- package/dist/contract/flow-run.d.ts +346 -0
- package/dist/contract/flow-run.js +194 -0
- package/dist/contract/flow.d.ts +1057 -0
- package/dist/contract/flow.js +552 -0
- package/dist/contract/node.d.ts +551 -0
- package/dist/contract/node.js +456 -0
- package/dist/contract/share.d.ts +216 -0
- package/dist/contract/share.js +134 -0
- package/dist/contract/table.d.ts +171 -0
- package/dist/contract/table.js +117 -0
- package/dist/contract/tool.d.ts +122 -0
- package/dist/contract/tool.js +172 -0
- package/dist/feed/feed.d.ts +2 -0
- package/dist/feed/feed.js +77 -0
- package/dist/feed/feed.types.d.ts +23 -0
- package/dist/feed/feed.types.js +1 -0
- package/dist/flows/flows.d.ts +41 -0
- package/dist/flows/flows.js +2216 -0
- package/dist/flows/flows.types.d.ts +339 -0
- package/dist/flows/flows.types.js +1 -0
- package/dist/http/http.d.ts +9 -0
- package/dist/http/http.js +874 -0
- package/dist/http/http.types.d.ts +22 -0
- package/dist/http/http.types.js +1 -0
- package/dist/indexing/indexing.d.ts +6 -0
- package/dist/indexing/indexing.js +239 -0
- package/dist/indexing/indexing.types.d.ts +11 -0
- package/dist/indexing/indexing.types.js +1 -0
- package/dist/intel/intel.d.ts +3 -0
- package/dist/intel/intel.js +194 -0
- package/dist/intel/intel.types.d.ts +24 -0
- package/dist/intel/intel.types.js +1 -0
- package/dist/mcp/mcp.d.ts +2 -0
- package/dist/mcp/mcp.js +1292 -0
- package/dist/mcp/mcp.types.d.ts +25 -0
- package/dist/mcp/mcp.types.js +1 -0
- package/dist/nodes/document-links/document-links.d.ts +20 -0
- package/dist/nodes/document-links/document-links.js +57 -0
- package/dist/nodes/nodes.d.ts +2 -0
- package/dist/nodes/nodes.js +1667 -0
- package/dist/nodes/nodes.types.d.ts +511 -0
- package/dist/nodes/nodes.types.js +1 -0
- package/dist/prepare/prepare.d.ts +4 -0
- package/dist/prepare/prepare.js +16 -0
- package/dist/prepare/prepare.types.d.ts +9 -0
- package/dist/prepare/prepare.types.js +1 -0
- package/dist/prompts/prompts.d.ts +2 -0
- package/dist/prompts/prompts.js +65 -0
- package/dist/prompts/prompts.types.d.ts +71 -0
- package/dist/prompts/prompts.types.js +1 -0
- package/dist/shared/callers/callers.d.ts +28 -0
- package/dist/shared/callers/callers.js +30 -0
- package/dist/shared/csv/csv.d.ts +13 -0
- package/dist/shared/csv/csv.js +85 -0
- package/dist/shared/document-text/document-text.d.ts +21 -0
- package/dist/shared/document-text/document-text.js +31 -0
- package/dist/shared/gate-authorization/gate-authorization.d.ts +5 -0
- package/dist/shared/gate-authorization/gate-authorization.js +26 -0
- package/dist/shared/grant-expiry/grant-expiry.d.ts +19 -0
- package/dist/shared/grant-expiry/grant-expiry.js +26 -0
- package/dist/shared/intel-error/intel-error.d.ts +22 -0
- package/dist/shared/intel-error/intel-error.js +27 -0
- package/dist/shared/plain-title/plain-title.d.ts +16 -0
- package/dist/shared/plain-title/plain-title.js +45 -0
- package/dist/shared/problem-details/problem-details.d.ts +30 -0
- package/dist/shared/problem-details/problem-details.js +18 -0
- package/dist/shared/report-unexpected-error/report-unexpected-error.d.ts +1 -0
- package/dist/shared/report-unexpected-error/report-unexpected-error.js +37 -0
- package/dist/shared/safe-return-path/safe-return-path.d.ts +2 -0
- package/dist/shared/safe-return-path/safe-return-path.js +11 -0
- package/dist/shared/sha256/sha256.d.ts +2 -0
- package/dist/shared/sha256/sha256.js +14 -0
- package/dist/tools/tool-servers/tool-servers.d.ts +46 -0
- package/dist/tools/tool-servers/tool-servers.js +177 -0
- package/dist/tools/tools.d.ts +2 -0
- package/dist/tools/tools.js +207 -0
- package/dist/tools/tools.types.d.ts +56 -0
- package/dist/tools/tools.types.js +1 -0
- package/examples/branding/favicon.svg +5 -0
- package/examples/branding/logo.svg +5 -0
- package/examples/branding/theme.css +16 -0
- package/examples/dev.vars.example +7 -0
- package/examples/intel.json +9 -0
- package/migrations/0000_intel_foundation.sql +203 -0
- package/migrations/0001_portal_native_tools.sql +21 -0
- package/migrations/0002_flows_in_the_knowledge_tree.sql +34 -0
- package/migrations/0003_folder_permissions.sql +211 -0
- package/migrations/0004_subflow_runs.sql +14 -0
- package/migrations/0005_flow_node_cleanup.sql +28 -0
- package/migrations/0005_tables_in_the_knowledge_tree.sql +68 -0
- package/migrations/0006_links_are_written_in_the_text.sql +20 -0
- package/migrations/0007_no_node_waits.sql +69 -0
- package/migrations/0008_three_layers.sql +130 -0
- package/migrations/0009_no_context_policy.sql +48 -0
- package/migrations/0010_no_run_waits_a_year.sql +27 -0
- package/migrations/0011_one_name_for_the_tree.sql +53 -0
- package/migrations/0012_table_snapshots.sql +29 -0
- package/migrations/0017_a_vector_per_card.sql +38 -0
- package/migrations/0018_no_context_policy_at_last.sql +97 -0
- package/migrations/0019_one_name_for_the_grants.sql +52 -0
- package/migrations/0020_cascade_purge_replay.sql +11 -0
- package/migrations/0021_a_flow_carries_its_own_grant.sql +44 -0
- package/migrations/0022_a_cursor_over_the_journal.sql +14 -0
- package/migrations/0023_a_board_and_its_tasks.sql +116 -0
- package/migrations/0024_the_archive_is_a_column.sql +33 -0
- package/migrations/0025_archiving_takes_the_subtree.sql +29 -0
- package/migrations/0026_one_feed_over_two_kinds.sql +23 -0
- package/migrations/0027_the_runs_of_every_flow.sql +27 -0
- package/migrations/0028_a_prompt_name_over_two_kinds.sql +70 -0
- package/package.json +118 -0
- package/src/contract/CLAUDE.md +152 -0
- package/src/contract/README.md +102 -0
- package/src/contract/audit.ts +85 -0
- package/src/contract/board.ts +306 -0
- package/src/contract/bundle.ts +157 -0
- package/src/contract/contract.ts +161 -0
- package/src/contract/feed.ts +165 -0
- package/src/contract/flow-run.ts +241 -0
- package/src/contract/flow.ts +675 -0
- package/src/contract/node.ts +583 -0
- package/src/contract/share.ts +196 -0
- package/src/contract/table.ts +178 -0
- package/src/contract/tool.ts +202 -0
- package/ui/README.md +110 -0
- package/ui/components.json +21 -0
- package/ui/index.html +13 -0
- package/ui/package.json +11 -0
- package/ui/scripts/lint-tokens.mjs +187 -0
- package/ui/src/access-summary/access-summary.tsx +385 -0
- package/ui/src/app/action-slot/action-slot.tsx +27 -0
- package/ui/src/app/app-sidebar/app-sidebar.tsx +71 -0
- package/ui/src/app/app-tree/app-tree.tsx +1175 -0
- package/ui/src/app/app.tsx +87 -0
- package/ui/src/app/header-search/header-search.tsx +294 -0
- package/ui/src/app/reindex-dialog/reindex-dialog.tsx +79 -0
- package/ui/src/app/settings-dialog/settings-dialog.tsx +135 -0
- package/ui/src/app/sidebar-preferences/sidebar-preferences.ts +68 -0
- package/ui/src/app/sidebar-preferences/sidebar-preferences.types.ts +15 -0
- package/ui/src/app/sidebar-resize-handle/sidebar-resize-handle.tsx +86 -0
- package/ui/src/app/tree-expansion/tree-expansion.ts +107 -0
- package/ui/src/app/tree-expansion/tree-expansion.types.ts +31 -0
- package/ui/src/app/tree-move/tree-move.tsx +427 -0
- package/ui/src/app/tree-reveal/tree-reveal.ts +64 -0
- package/ui/src/app/tree-reveal/tree-reveal.types.ts +16 -0
- package/ui/src/app/user-footer/user-footer.tsx +188 -0
- package/ui/src/app/view-menu/view-menu.tsx +115 -0
- package/ui/src/app-root/app-root.tsx +109 -0
- package/ui/src/app-root/app-root.types.ts +27 -0
- package/ui/src/archive/archive.tsx +417 -0
- package/ui/src/attachment-detail/attachment-detail.ts +52 -0
- package/ui/src/attachment-viewer/attachment-viewer.tsx +166 -0
- package/ui/src/blocknote-view/blocknote-view.tsx +30 -0
- package/ui/src/board/board-assignee/board-assignee-picker.tsx +132 -0
- package/ui/src/board/board-assignee/board-assignee.ts +48 -0
- package/ui/src/board/board-assignee/board-assignee.tsx +75 -0
- package/ui/src/board/board-chip/board-chip.tsx +46 -0
- package/ui/src/board/board-crumbs/board-crumbs.ts +56 -0
- package/ui/src/board/board-crumbs/board-crumbs.tsx +111 -0
- package/ui/src/board/board-data/board-data.ts +195 -0
- package/ui/src/board/board-data/board-data.types.ts +38 -0
- package/ui/src/board/board-dates/board-dates.ts +40 -0
- package/ui/src/board/board-dates/board-dates.tsx +105 -0
- package/ui/src/board/board-kanban/board-kanban.ts +162 -0
- package/ui/src/board/board-kanban/board-kanban.tsx +680 -0
- package/ui/src/board/board-open-task/board-open-task.ts +32 -0
- package/ui/src/board/board-panel/board-panel.tsx +259 -0
- package/ui/src/board/board-settings/board-settings.tsx +226 -0
- package/ui/src/board/board-status/board-status.tsx +60 -0
- package/ui/src/board/board-stripes/board-stripes.ts +128 -0
- package/ui/src/board/board-table/board-table.ts +53 -0
- package/ui/src/board/board-table/board-table.tsx +610 -0
- package/ui/src/board/board-task/board-task.ts +108 -0
- package/ui/src/board/board-task/board-task.tsx +335 -0
- package/ui/src/board/board-title-row/board-title-row.tsx +66 -0
- package/ui/src/branding/branding.tsx +17 -0
- package/ui/src/branding/custom-logo.ts +1 -0
- package/ui/src/branding/favicon.default.svg +5 -0
- package/ui/src/branding/favicon.svg +5 -0
- package/ui/src/components/ui/avatar.tsx +39 -0
- package/ui/src/components/ui/button.tsx +64 -0
- package/ui/src/components/ui/collapsible.tsx +20 -0
- package/ui/src/components/ui/command.tsx +160 -0
- package/ui/src/components/ui/dialog.tsx +143 -0
- package/ui/src/components/ui/dropdown-menu.tsx +187 -0
- package/ui/src/components/ui/input.tsx +21 -0
- package/ui/src/components/ui/popover.tsx +41 -0
- package/ui/src/components/ui/select.tsx +163 -0
- package/ui/src/components/ui/separator.tsx +26 -0
- package/ui/src/components/ui/sheet.tsx +136 -0
- package/ui/src/components/ui/sidebar.tsx +693 -0
- package/ui/src/components/ui/skeleton.tsx +13 -0
- package/ui/src/components/ui/switch.tsx +25 -0
- package/ui/src/components/ui/table.tsx +82 -0
- package/ui/src/components/ui/tabs.tsx +52 -0
- package/ui/src/components/ui/tooltip.tsx +51 -0
- package/ui/src/data/intel-data-provider/intel-data-provider.ts +685 -0
- package/ui/src/data/intel-data-provider/intel-data-provider.types.ts +266 -0
- package/ui/src/data/query-client.ts +18 -0
- package/ui/src/data/request-refusal/refusal-notice.tsx +36 -0
- package/ui/src/data/request-refusal/request-refusal.ts +51 -0
- package/ui/src/data/sign-in/sign-in.ts +97 -0
- package/ui/src/data/sign-in/sign-in.types.ts +15 -0
- package/ui/src/document-link/document-link.tsx +114 -0
- package/ui/src/document-markdown/document-markdown.ts +195 -0
- package/ui/src/editor-schema/editor-schema.ts +23 -0
- package/ui/src/entry-picker/entry-picker.tsx +238 -0
- package/ui/src/feed/feed.tsx +344 -0
- package/ui/src/file-preview/file-preview-view.tsx +496 -0
- package/ui/src/file-preview/file-preview.tsx +28 -0
- package/ui/src/file-preview/pdf-file-preview.tsx +5 -0
- package/ui/src/file-preview/presentation-file-preview.tsx +21 -0
- package/ui/src/file-preview/spreadsheet-file-preview.tsx +5 -0
- package/ui/src/file-preview/word-file-preview.tsx +5 -0
- package/ui/src/flow-runs/flow-runs.tsx +238 -0
- package/ui/src/flows/flows.tsx +1646 -0
- package/ui/src/flows/node-icon/node-icon.ts +34 -0
- package/ui/src/flows/node-palette/node-palette.tsx +214 -0
- package/ui/src/flows/node-palette/node-palette.types.ts +15 -0
- package/ui/src/folder-contents/folder-contents.tsx +321 -0
- package/ui/src/folder-index/folder-index.ts +55 -0
- package/ui/src/frontmatter/frontmatter.tsx +193 -0
- package/ui/src/graph-pane/graph-pane.tsx +53 -0
- package/ui/src/hooks/use-mobile.ts +19 -0
- package/ui/src/i18n/custom.json +4 -0
- package/ui/src/i18n/de.json +609 -0
- package/ui/src/i18n/en.json +609 -0
- package/ui/src/i18n/es.json +609 -0
- package/ui/src/i18n/i18n-context.tsx +65 -0
- package/ui/src/i18n/i18n-languages/i18n-languages.ts +83 -0
- package/ui/src/i18n/i18n.ts +32 -0
- package/ui/src/i18n/i18n.types.ts +49 -0
- package/ui/src/kind-icon.ts +97 -0
- package/ui/src/lib/utils.ts +6 -0
- package/ui/src/main.tsx +68 -0
- package/ui/src/modal/modal.tsx +53 -0
- package/ui/src/node-details/node-details.tsx +545 -0
- package/ui/src/node-editor/node-editor.tsx +304 -0
- package/ui/src/node-graph/graph-notice.tsx +21 -0
- package/ui/src/node-graph/node-graph.ts +214 -0
- package/ui/src/node-graph/node-graph.tsx +295 -0
- package/ui/src/node-import/node-import.tsx +418 -0
- package/ui/src/node-save-error.ts +46 -0
- package/ui/src/node-source/node-source.tsx +128 -0
- package/ui/src/node-table/node-table.tsx +107 -0
- package/ui/src/nodes/nodes.tsx +240 -0
- package/ui/src/rename-resource/rename-resource.ts +80 -0
- package/ui/src/resolved-names/resolved-names.tsx +67 -0
- package/ui/src/resource-error.ts +33 -0
- package/ui/src/resource-menu/resource-menu.tsx +1156 -0
- package/ui/src/router/router-context.ts +6 -0
- package/ui/src/router/router.tsx +67 -0
- package/ui/src/router/router.types.ts +8 -0
- package/ui/src/router/selection-search.ts +88 -0
- package/ui/src/save-button/save-button.tsx +94 -0
- package/ui/src/section-hint/section-hint.tsx +40 -0
- package/ui/src/sign-in-refused/sign-in-refused.tsx +35 -0
- package/ui/src/styles.css +189 -0
- package/ui/src/table-columns/table-columns.tsx +379 -0
- package/ui/src/theme/custom.css +1 -0
- package/ui/src/theme/theme-context.tsx +89 -0
- package/ui/src/theme/theme.ts +70 -0
- package/ui/src/time/relative-time.tsx +41 -0
- package/ui/src/time/time-context.tsx +78 -0
- package/ui/src/time/time.ts +165 -0
- package/ui/src/title-row/title-row.tsx +185 -0
- package/ui/src/tools/tools.tsx +546 -0
- package/ui/src/user-name/user-name.ts +61 -0
- package/ui/src/verbatim/verbatim.tsx +68 -0
- package/ui/tsconfig.json +17 -0
- package/ui/vite.config.ts +129 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// The ONE place a timestamp becomes a readable sentence (#467).
|
|
2
|
+
//
|
|
3
|
+
// Every surface used to call `toLocaleString(locale)` for itself, which silently takes the DEVICE's
|
|
4
|
+
// zone. Three things follow that are not true:
|
|
5
|
+
//
|
|
6
|
+
// 1. Whoever travels, or uses a device in another zone, reads different times for the same
|
|
7
|
+
// events. For a record of what happened that is where it stops being evidence.
|
|
8
|
+
// 2. Nowhere does it say WHICH zone applies. A time without a zone is a number, not a statement —
|
|
9
|
+
// and it looks exactly like a real one.
|
|
10
|
+
// 3. Two people looking at the same entry see different times and cannot refer to one in
|
|
11
|
+
// conversation.
|
|
12
|
+
//
|
|
13
|
+
// ⚠️ **The zone is a LENS for reading, never a change to the value.** What is stored and sent stays
|
|
14
|
+
// UTC; this module only formats.
|
|
15
|
+
//
|
|
16
|
+
// ⚠️ The comment in `settings-dialog.tsx` is what this file answers: the timezone left with the
|
|
17
|
+
// Agents (#388) because nothing read it, and "a preference that changes nothing on screen is worse
|
|
18
|
+
// than none". This exists BEFORE the preference does, and that order is the whole of #467.
|
|
19
|
+
|
|
20
|
+
export interface TimeZoneStore {
|
|
21
|
+
getItem(key: string): string | null;
|
|
22
|
+
setItem(key: string, value: string): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const StorageKey = "intel.timezone";
|
|
26
|
+
|
|
27
|
+
// "This device's zone" as an explicit choice rather than an empty field: an empty field would look
|
|
28
|
+
// as if nothing were set, and invite somebody to set what already holds.
|
|
29
|
+
export const DeviceZone = "device";
|
|
30
|
+
export type ZoneChoice = string;
|
|
31
|
+
|
|
32
|
+
// ⚠️ Falling back to UTC rather than throwing: in an environment without Intl a time in UTC is
|
|
33
|
+
// still a time, while a thrown exception is an empty screen.
|
|
34
|
+
export function deviceZone(): string {
|
|
35
|
+
try {
|
|
36
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
37
|
+
} catch {
|
|
38
|
+
return "UTC";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// The stored value comes out of `localStorage` and may have been edited by hand, written by an older
|
|
43
|
+
// build, or name a zone this runtime does not know.
|
|
44
|
+
export function isKnownZone(zone: string): boolean {
|
|
45
|
+
if (zone === DeviceZone) return true;
|
|
46
|
+
try {
|
|
47
|
+
new Intl.DateTimeFormat("en-US", { timeZone: zone });
|
|
48
|
+
return true;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function readZoneChoice(store?: TimeZoneStore): ZoneChoice {
|
|
55
|
+
try {
|
|
56
|
+
const stored = store?.getItem(StorageKey);
|
|
57
|
+
return stored && isKnownZone(stored) ? stored : DeviceZone;
|
|
58
|
+
} catch {
|
|
59
|
+
return DeviceZone;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function rememberZoneChoice(choice: ZoneChoice, store?: TimeZoneStore): void {
|
|
64
|
+
try {
|
|
65
|
+
store?.setItem(StorageKey, choice);
|
|
66
|
+
} catch {
|
|
67
|
+
// Without storage the choice holds for this session. Less than the reader wanted, more than an
|
|
68
|
+
// error they cannot switch off.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function resolveZone(choice: ZoneChoice): string {
|
|
73
|
+
return choice === DeviceZone || !isKnownZone(choice) ? deviceZone() : choice;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A timestamp as a readable sentence — WITH its zone.
|
|
78
|
+
*
|
|
79
|
+
* ⚠️ The abbreviation is not decoration: a shifted time without one is precisely the silent
|
|
80
|
+
* misstatement this ticket is written against. And it comes from the runtime rather than from a
|
|
81
|
+
* string in the code — the runtime knows daylight saving, an appended label would be wrong for half
|
|
82
|
+
* the year.
|
|
83
|
+
*
|
|
84
|
+
* ⚠️ Individual components rather than `dateStyle`/`timeStyle`: Intl refuses the two style
|
|
85
|
+
* shorthands TOGETHER with `timeZoneName` and throws `Invalid option` — inside a table cell that
|
|
86
|
+
* takes the whole list with it. Found the hard way in `anchrd/gate#286`, where it read as "the row
|
|
87
|
+
* is missing" rather than as a formatting error.
|
|
88
|
+
*/
|
|
89
|
+
export function formatDateTime(value: string, locale: string, choice: ZoneChoice): string {
|
|
90
|
+
const date = new Date(value);
|
|
91
|
+
// An unreadable timestamp travels through rather than rendering as "Invalid Date": the raw value
|
|
92
|
+
// at least says what stood there.
|
|
93
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
94
|
+
return date.toLocaleString(locale, {
|
|
95
|
+
timeZone: resolveZone(choice),
|
|
96
|
+
year: "numeric",
|
|
97
|
+
month: "short",
|
|
98
|
+
day: "2-digit",
|
|
99
|
+
hour: "2-digit",
|
|
100
|
+
minute: "2-digit",
|
|
101
|
+
timeZoneName: "short",
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The date alone, for the column that only ever showed one (the folder table's "Changed").
|
|
107
|
+
*
|
|
108
|
+
* ⚠️ It still resolves through the chosen zone, and that is the point rather than a detail: near
|
|
109
|
+
* midnight a date is exactly the value that differs between two zones, and a bare date carries no
|
|
110
|
+
* abbreviation to warn anybody.
|
|
111
|
+
*/
|
|
112
|
+
export function formatDate(value: string, locale: string, choice: ZoneChoice): string {
|
|
113
|
+
const date = new Date(value);
|
|
114
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
115
|
+
return date.toLocaleDateString(locale, { timeZone: resolveZone(choice) });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const Minute = 60_000;
|
|
119
|
+
const Hour = 60 * Minute;
|
|
120
|
+
const Day = 24 * Hour;
|
|
121
|
+
const Month = 30 * Day;
|
|
122
|
+
|
|
123
|
+
/** A compact list value. Thirty days is the explicit month boundary; calendar labels stay in the tooltip. */
|
|
124
|
+
export function formatRelativeTime(
|
|
125
|
+
value: string,
|
|
126
|
+
locale: string,
|
|
127
|
+
choice: ZoneChoice,
|
|
128
|
+
now: number,
|
|
129
|
+
): string {
|
|
130
|
+
const date = new Date(value);
|
|
131
|
+
const target = date.getTime();
|
|
132
|
+
if (Number.isNaN(target)) return value;
|
|
133
|
+
const difference = target - now;
|
|
134
|
+
const distance = Math.abs(difference);
|
|
135
|
+
const relative = new Intl.RelativeTimeFormat(locale, { numeric: "auto", style: "short" });
|
|
136
|
+
if (distance < Minute) return relative.format(0, "second");
|
|
137
|
+
if (distance < Hour) return relative.format(Math.trunc(difference / Minute), "minute");
|
|
138
|
+
if (distance < Day) return relative.format(Math.trunc(difference / Hour), "hour");
|
|
139
|
+
if (distance < Month) return relative.format(Math.trunc(difference / Day), "day");
|
|
140
|
+
return formatDate(value, locale, choice);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ⚠️ A short curated list rather than `Intl.supportedValuesOf("timeZone")` — that is over 400
|
|
144
|
+
// entries, and a dropdown of 400 rows without a search is not a choice but an imposition. A zone
|
|
145
|
+
// missing here is added once it has been missed three times; until then the device's zone is the
|
|
146
|
+
// answer, and it is the right one for almost everybody. Ordered by offset, so the list reads like a
|
|
147
|
+
// map.
|
|
148
|
+
export const ZoneOptions: readonly string[] = [
|
|
149
|
+
"UTC",
|
|
150
|
+
"Europe/Lisbon",
|
|
151
|
+
"Europe/Berlin",
|
|
152
|
+
"Europe/Athens",
|
|
153
|
+
"Europe/Moscow",
|
|
154
|
+
"Asia/Dubai",
|
|
155
|
+
"Asia/Kolkata",
|
|
156
|
+
"Asia/Singapore",
|
|
157
|
+
"Asia/Tokyo",
|
|
158
|
+
"Australia/Sydney",
|
|
159
|
+
"Pacific/Auckland",
|
|
160
|
+
"America/Sao_Paulo",
|
|
161
|
+
"America/New_York",
|
|
162
|
+
"America/Chicago",
|
|
163
|
+
"America/Denver",
|
|
164
|
+
"America/Los_Angeles",
|
|
165
|
+
];
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
type HTMLAttributes,
|
|
4
|
+
type ReactNode,
|
|
5
|
+
useContext,
|
|
6
|
+
useEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { ResourceAccessSummary } from "@/access-summary/access-summary.tsx";
|
|
11
|
+
import { useI18n } from "@/i18n/i18n-context.tsx";
|
|
12
|
+
import { cn } from "@/lib/utils";
|
|
13
|
+
import { NodeDetails } from "@/node-details/node-details.tsx";
|
|
14
|
+
import { ResourceMenu, type ResourceTarget } from "@/resource-menu/resource-menu.tsx";
|
|
15
|
+
|
|
16
|
+
const TitleRowScrollContext = createContext<{
|
|
17
|
+
scrolled: boolean;
|
|
18
|
+
setScrolled(scrolled: boolean): void;
|
|
19
|
+
} | null>(null);
|
|
20
|
+
|
|
21
|
+
export function TitleRowFrame({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
|
|
22
|
+
const [scrolled, setScrolled] = useState(false);
|
|
23
|
+
const value = useMemo(() => ({ scrolled, setScrolled }), [scrolled]);
|
|
24
|
+
return (
|
|
25
|
+
<TitleRowScrollContext.Provider value={value}>
|
|
26
|
+
<div className={className} {...props} />
|
|
27
|
+
</TitleRowScrollContext.Provider>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function TitleRowScrollArea({
|
|
32
|
+
className,
|
|
33
|
+
onScroll,
|
|
34
|
+
...props
|
|
35
|
+
}: HTMLAttributes<HTMLDivElement>) {
|
|
36
|
+
const scroll = useContext(TitleRowScrollContext);
|
|
37
|
+
const setScrolled = scroll?.setScrolled;
|
|
38
|
+
useEffect(() => () => setScrolled?.(false), [setScrolled]);
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
className={className}
|
|
42
|
+
onScroll={(event) => {
|
|
43
|
+
scroll?.setScrolled(event.currentTarget.scrollTop > 0);
|
|
44
|
+
onScroll?.(event);
|
|
45
|
+
}}
|
|
46
|
+
{...props}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The one line an open thing gets: its name on the left, everything that acts on it on the right
|
|
53
|
+
* (#53).
|
|
54
|
+
*
|
|
55
|
+
* ⚠️ The order of the right-hand group belongs to this component, not to its callers. Whatever they
|
|
56
|
+
* pass as `children` is rendered before the menu and the menu is appended last, always — so a screen
|
|
57
|
+
* that grows a new button cannot push the three dots to the left, and there is no second place where
|
|
58
|
+
* the rule could be forgotten. That is the whole point: the menu holds rename, move, share and
|
|
59
|
+
* archive, and a position one has to look for is a position one stops using.
|
|
60
|
+
*
|
|
61
|
+
* The two slots are for what belongs to this thing but lives further down the tree, where its
|
|
62
|
+
* state is. `title-meta` is a quiet word beside the name (a table's row count); `title-actions` is a
|
|
63
|
+
* button in the group (saving a document, exporting a table). Both are filled through `ActionSlot`,
|
|
64
|
+
* and the one in the group sits before the menu for the same reason `children` do.
|
|
65
|
+
*/
|
|
66
|
+
export function TitleRow({
|
|
67
|
+
title,
|
|
68
|
+
crumbs,
|
|
69
|
+
target,
|
|
70
|
+
separated,
|
|
71
|
+
children,
|
|
72
|
+
}: {
|
|
73
|
+
/**
|
|
74
|
+
* ⚠️ **Not drawn while `crumbs` is set** — the path names the thing then, and nothing falls back
|
|
75
|
+
* to this. It stays required all the same, so every caller has to state in one word what the row
|
|
76
|
+
* is about: the next reader of this call site should not have to follow a component two files
|
|
77
|
+
* away to find out.
|
|
78
|
+
*/
|
|
79
|
+
title: string;
|
|
80
|
+
/**
|
|
81
|
+
* A path that stands in for the name.
|
|
82
|
+
*
|
|
83
|
+
* ⚠️ **It REPLACES the heading, it does not join it.** An open board card carries its name in the
|
|
84
|
+
* path already, and the same sentence twice above one another says nothing twice (#692). The row
|
|
85
|
+
* itself, its menu order and its slots stay exactly as they are: only what identifies the thing
|
|
86
|
+
* changes, because for a card the answer is "where it sits", not just "what it is called".
|
|
87
|
+
*/
|
|
88
|
+
crumbs?: ReactNode;
|
|
89
|
+
/**
|
|
90
|
+
* What the three-dot menu acts on. ⚠️ **Absent means NO menu**, and that is a real state rather
|
|
91
|
+
* than an oversight: a card whose node has not arrived yet has nothing the menu could rename,
|
|
92
|
+
* move or archive, and pointing it at the container instead would archive the wrong thing without
|
|
93
|
+
* asking (#692).
|
|
94
|
+
*/
|
|
95
|
+
target?: ResourceTarget;
|
|
96
|
+
/**
|
|
97
|
+
* A separator that does NOT wait for a scroll.
|
|
98
|
+
*
|
|
99
|
+
* ⚠️ For a surface where scrolling cannot happen, and that is the only case it is for (#634). The
|
|
100
|
+
* edge below this row is normally `scrolled`, set by `TitleRowScrollArea` — which is right where
|
|
101
|
+
* content moves under the row. The flow canvas does not scroll, it pans: nothing ever sets
|
|
102
|
+
* `scrolled`, so the row sat on the dark canvas with no edge at all. Do not pass this where the
|
|
103
|
+
* content does scroll; a permanent edge there would replace a signal with decoration.
|
|
104
|
+
*/
|
|
105
|
+
separated?: boolean;
|
|
106
|
+
children?: ReactNode;
|
|
107
|
+
}) {
|
|
108
|
+
const i18n = useI18n();
|
|
109
|
+
const scroll = useContext(TitleRowScrollContext);
|
|
110
|
+
const setScrolled = scroll?.setScrolled;
|
|
111
|
+
const targetId =
|
|
112
|
+
target === undefined ? undefined : target.type === "flow" ? target.flow.id : target.node.id;
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
void targetId;
|
|
115
|
+
setScrolled?.(false);
|
|
116
|
+
}, [setScrolled, targetId]);
|
|
117
|
+
return (
|
|
118
|
+
<div
|
|
119
|
+
data-scrolled={scroll?.scrolled || undefined}
|
|
120
|
+
className={cn(
|
|
121
|
+
"relative z-10 flex shrink-0 justify-between gap-5 px-6 py-4 transition-shadow",
|
|
122
|
+
// ⚠️ Two alignments for two shapes (#724). A document's name can carry a description under
|
|
123
|
+
// it, so its block starts at the top and the menu lines up with the FIRST line. A path is
|
|
124
|
+
// always one line, and starting it at the top leaves it sitting a hair above the icons it
|
|
125
|
+
// shares the row with. Centred, the two read as one line, which is what they are.
|
|
126
|
+
crumbs === undefined ? "items-start" : "items-center",
|
|
127
|
+
(separated || scroll?.scrolled) && "shadow-[inset_0_-1px_0_var(--border)]",
|
|
128
|
+
)}
|
|
129
|
+
>
|
|
130
|
+
<div className="flex min-w-0 items-center gap-3">
|
|
131
|
+
<div className="min-w-0">
|
|
132
|
+
<div className="flex min-w-0 flex-wrap items-baseline gap-x-3">
|
|
133
|
+
{crumbs === undefined ? (
|
|
134
|
+
<h2 className="truncate text-lg font-semibold">{title}</h2>
|
|
135
|
+
) : (
|
|
136
|
+
crumbs
|
|
137
|
+
)}
|
|
138
|
+
{/* ⚠️ **The one place the slash command is written out** (#775). Quiet, beside the name,
|
|
139
|
+
where somebody who has the document open can read what to type. Not in the sidebar —
|
|
140
|
+
240px cut the titles down to `Angebo…` to say this — and not in the menu entry, which
|
|
141
|
+
is one line above it and would be the same sentence twice.
|
|
142
|
+
|
|
143
|
+
⚠️ It carries its own accessible name rather than standing as bare text: `/billing`
|
|
144
|
+
out of context is a path, and a reader who cannot see the layout has nothing telling
|
|
145
|
+
them it is a command. */}
|
|
146
|
+
{target?.type === "node" && target.node.promptName !== null ? (
|
|
147
|
+
<span className="truncate text-sm text-muted-foreground">
|
|
148
|
+
<span className="sr-only">
|
|
149
|
+
{i18n.t("prompt.command", { name: target.node.promptName })}
|
|
150
|
+
</span>
|
|
151
|
+
<span aria-hidden="true">/{target.node.promptName}</span>
|
|
152
|
+
</span>
|
|
153
|
+
) : null}
|
|
154
|
+
{target?.type === "node" && target.node.kind === "folder" ? (
|
|
155
|
+
<ResourceAccessSummary resourceId={target.node.id} ownerId={target.node.ownerId} />
|
|
156
|
+
) : null}
|
|
157
|
+
{/* A flow carries its own grants since #530, so who reaches it is worth showing where
|
|
158
|
+
it stands — the same question the folder above already answers here. */}
|
|
159
|
+
{target?.type === "flow" ? (
|
|
160
|
+
<ResourceAccessSummary
|
|
161
|
+
kind="flow"
|
|
162
|
+
resourceId={target.flow.id}
|
|
163
|
+
ownerId={target.flow.ownerId}
|
|
164
|
+
/>
|
|
165
|
+
) : null}
|
|
166
|
+
<span data-slot="title-meta" className="text-sm text-muted-foreground" />
|
|
167
|
+
</div>
|
|
168
|
+
{/* ⚠️ **The description is no longer running text under the name** (#819). It sits in the
|
|
169
|
+
details field with the facts of its kind, where it can also be changed — a file had
|
|
170
|
+
such a field and nothing else did. No target means nothing to describe and nothing to
|
|
171
|
+
change: an open card whose node has not arrived yet is the case (#692). */}
|
|
172
|
+
{target === undefined ? null : <NodeDetails key={targetId} target={target} />}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
{/* ⚠️ Document order is tab order here — nothing carries a `tabIndex`. The menu is therefore
|
|
176
|
+
reached last by the keyboard for the same reason it stands last on screen, and the two
|
|
177
|
+
cannot drift apart without someone rewriting this line. */}
|
|
178
|
+
<div className="flex shrink-0 items-center gap-2">
|
|
179
|
+
<div data-slot="title-actions" className="flex items-center gap-2" />
|
|
180
|
+
{children}
|
|
181
|
+
{target === undefined ? null : <ResourceMenu target={target} variant="title" />}
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
);
|
|
185
|
+
}
|