@scalar/api-client 3.3.1 → 3.4.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 +15 -0
- package/dist/monacoeditorwork/yaml.worker.bundle.js +92 -79
- package/dist/style.css +87 -57
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts +2 -0
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +5 -0
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.d.ts +4 -0
- package/dist/v2/blocks/operation-block/components/Header.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.js +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.js.map +1 -1
- package/dist/v2/blocks/operation-block/components/Header.vue.script.js +6 -0
- package/dist/v2/blocks/operation-block/components/Header.vue.script.js.map +1 -1
- package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts +2 -1
- package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/helpers/response-cache.js +9 -2
- package/dist/v2/blocks/operation-block/helpers/response-cache.js.map +1 -1
- package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestTable.vue.d.ts +2 -2
- package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts +2 -2
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +4 -0
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js +84 -71
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.d.ts +13 -0
- package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.d.ts.map +1 -0
- package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.js +28 -0
- package/dist/v2/blocks/scalar-address-bar-block/helpers/is-placeholder-path.js.map +1 -0
- package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.d.ts +16 -0
- package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.d.ts.map +1 -0
- package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.js +28 -0
- package/dist/v2/blocks/scalar-address-bar-block/helpers/refocus-blur-target.js.map +1 -0
- package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.d.ts +31 -0
- package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.d.ts.map +1 -0
- package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.js +18 -0
- package/dist/v2/blocks/scalar-address-bar-block/hooks/use-path-masking.js.map +1 -0
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.script.js +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/features/app/App.vue.d.ts +25 -1
- package/dist/v2/features/app/App.vue.d.ts.map +1 -1
- package/dist/v2/features/app/App.vue.js.map +1 -1
- package/dist/v2/features/app/App.vue.script.js +54 -39
- package/dist/v2/features/app/App.vue.script.js.map +1 -1
- package/dist/v2/features/app/app-events.js +4 -4
- package/dist/v2/features/app/app-events.js.map +1 -1
- package/dist/v2/features/app/app-state.d.ts +20 -14
- package/dist/v2/features/app/app-state.d.ts.map +1 -1
- package/dist/v2/features/app/app-state.js +89 -55
- package/dist/v2/features/app/app-state.js.map +1 -1
- package/dist/v2/features/app/components/AppHeader.vue.d.ts +26 -3
- package/dist/v2/features/app/components/AppHeader.vue.d.ts.map +1 -1
- package/dist/v2/features/app/components/AppHeader.vue.js.map +1 -1
- package/dist/v2/features/app/components/AppHeader.vue.script.js +15 -6
- package/dist/v2/features/app/components/AppHeader.vue.script.js.map +1 -1
- package/dist/v2/features/app/components/AppSidebar.vue.d.ts +2 -2
- package/dist/v2/features/app/components/AppSidebar.vue.d.ts.map +1 -1
- package/dist/v2/features/app/components/AppSidebar.vue.js +1 -1
- package/dist/v2/features/app/components/AppSidebar.vue.js.map +1 -1
- package/dist/v2/features/app/components/AppSidebar.vue.script.js +86 -108
- package/dist/v2/features/app/components/AppSidebar.vue.script.js.map +1 -1
- package/dist/v2/features/app/components/CreateVersionModal.vue.d.ts +28 -0
- package/dist/v2/features/app/components/CreateVersionModal.vue.d.ts.map +1 -0
- package/dist/v2/features/app/components/CreateVersionModal.vue.js +7 -0
- package/dist/v2/features/app/components/CreateVersionModal.vue.js.map +1 -0
- package/dist/v2/features/app/components/CreateVersionModal.vue.script.js +84 -0
- package/dist/v2/features/app/components/CreateVersionModal.vue.script.js.map +1 -0
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts +26 -0
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.d.ts.map +1 -0
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js +9 -0
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.js.map +1 -0
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js +376 -0
- package/dist/v2/features/app/components/DocumentBreadcrumb.vue.script.js.map +1 -0
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts +16 -0
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.d.ts.map +1 -0
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js +7 -0
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.js.map +1 -0
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js +51 -0
- package/dist/v2/features/app/components/DocumentSyncIndicator.vue.script.js.map +1 -0
- package/dist/v2/features/app/components/SidebarDocument.vue.d.ts +45 -0
- package/dist/v2/features/app/components/SidebarDocument.vue.d.ts.map +1 -0
- package/dist/v2/features/app/components/SidebarDocument.vue.js +7 -0
- package/dist/v2/features/app/components/SidebarDocument.vue.js.map +1 -0
- package/dist/v2/features/app/components/SidebarDocument.vue.script.js +137 -0
- package/dist/v2/features/app/components/SidebarDocument.vue.script.js.map +1 -0
- package/dist/v2/features/app/helpers/check-version-conflict.d.ts +51 -0
- package/dist/v2/features/app/helpers/check-version-conflict.d.ts.map +1 -0
- package/dist/v2/features/app/helpers/check-version-conflict.js +79 -0
- package/dist/v2/features/app/helpers/check-version-conflict.js.map +1 -0
- package/dist/v2/features/app/helpers/compute-version-status.d.ts +45 -0
- package/dist/v2/features/app/helpers/compute-version-status.d.ts.map +1 -0
- package/dist/v2/features/app/helpers/compute-version-status.js +18 -0
- package/dist/v2/features/app/helpers/compute-version-status.js.map +1 -0
- package/dist/v2/features/app/helpers/create-draft-registry-document.d.ts +39 -0
- package/dist/v2/features/app/helpers/create-draft-registry-document.d.ts.map +1 -0
- package/dist/v2/features/app/helpers/create-draft-registry-document.js +64 -0
- package/dist/v2/features/app/helpers/create-draft-registry-document.js.map +1 -0
- package/dist/v2/features/app/helpers/create-temp-operation.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/create-temp-operation.js +5 -8
- package/dist/v2/features/app/helpers/create-temp-operation.js.map +1 -1
- package/dist/v2/features/app/helpers/detect-document-conflicts.d.ts +26 -0
- package/dist/v2/features/app/helpers/detect-document-conflicts.d.ts.map +1 -0
- package/dist/v2/features/app/helpers/detect-document-conflicts.js +27 -0
- package/dist/v2/features/app/helpers/detect-document-conflicts.js.map +1 -0
- package/dist/v2/features/app/helpers/filter-workspaces.d.ts +14 -14
- package/dist/v2/features/app/helpers/filter-workspaces.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/filter-workspaces.js +15 -15
- package/dist/v2/features/app/helpers/filter-workspaces.js.map +1 -1
- package/dist/v2/features/app/helpers/group-workspaces.d.ts +23 -3
- package/dist/v2/features/app/helpers/group-workspaces.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/group-workspaces.js +22 -7
- package/dist/v2/features/app/helpers/group-workspaces.js.map +1 -1
- package/dist/v2/features/app/helpers/load-registry-document.d.ts +16 -1
- package/dist/v2/features/app/helpers/load-registry-document.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/load-registry-document.js +7 -6
- package/dist/v2/features/app/helpers/load-registry-document.js.map +1 -1
- package/dist/v2/features/app/helpers/routes.d.ts +5 -1
- package/dist/v2/features/app/helpers/routes.d.ts.map +1 -1
- package/dist/v2/features/app/helpers/routes.js +1 -1
- package/dist/v2/features/app/helpers/routes.js.map +1 -1
- package/dist/v2/features/app/helpers/version-status-presentation.d.ts +24 -0
- package/dist/v2/features/app/helpers/version-status-presentation.d.ts.map +1 -0
- package/dist/v2/features/app/helpers/version-status-presentation.js +43 -0
- package/dist/v2/features/app/helpers/version-status-presentation.js.map +1 -0
- package/dist/v2/features/app/hooks/use-active-document-version.d.ts +41 -0
- package/dist/v2/features/app/hooks/use-active-document-version.d.ts.map +1 -0
- package/dist/v2/features/app/hooks/use-active-document-version.js +60 -0
- package/dist/v2/features/app/hooks/use-active-document-version.js.map +1 -0
- package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts +71 -23
- package/dist/v2/features/app/hooks/use-sidebar-documents.d.ts.map +1 -1
- package/dist/v2/features/app/hooks/use-sidebar-documents.js +167 -45
- package/dist/v2/features/app/hooks/use-sidebar-documents.js.map +1 -1
- package/dist/v2/features/app/hooks/use-version-conflict-check.d.ts +35 -0
- package/dist/v2/features/app/hooks/use-version-conflict-check.d.ts.map +1 -0
- package/dist/v2/features/app/hooks/use-version-conflict-check.js +62 -0
- package/dist/v2/features/app/hooks/use-version-conflict-check.js.map +1 -0
- package/dist/v2/features/collection/DocumentCollection.vue.d.ts.map +1 -1
- package/dist/v2/features/collection/DocumentCollection.vue.js.map +1 -1
- package/dist/v2/features/collection/DocumentCollection.vue.script.js +6 -1
- package/dist/v2/features/collection/DocumentCollection.vue.script.js.map +1 -1
- package/dist/v2/features/collection/OperationCollection.vue.script.js +1 -0
- package/dist/v2/features/collection/OperationCollection.vue.script.js.map +1 -1
- package/dist/v2/features/collection/WorkspaceCollection.vue.script.js +1 -0
- package/dist/v2/features/collection/WorkspaceCollection.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Authentication.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Authentication.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Cookies.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Cookies.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Editor/Editor.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Editor/Editor.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Environment.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Environment.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/GetStarted.vue.d.ts +12 -4
- package/dist/v2/features/collection/components/GetStarted.vue.d.ts.map +1 -1
- package/dist/v2/features/collection/components/GetStarted.vue.js.map +1 -1
- package/dist/v2/features/collection/components/GetStarted.vue.script.js +56 -13
- package/dist/v2/features/collection/components/GetStarted.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Overview.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Overview.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js +2 -2
- package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js.map +1 -1
- package/dist/v2/features/collection/components/Scripts.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Scripts.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Servers.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Servers.vue.script.js.map +1 -1
- package/dist/v2/features/collection/components/Settings.vue.script.js +1 -0
- package/dist/v2/features/collection/components/Settings.vue.script.js.map +1 -1
- package/dist/v2/features/editor/hooks/use-three-way-merge-editor.js +1 -1
- package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
- package/dist/v2/features/operation/Operation.vue.js.map +1 -1
- package/dist/v2/features/operation/Operation.vue.script.js +3 -0
- package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
- package/dist/v2/helpers/safe-run.d.ts +25 -1
- package/dist/v2/helpers/safe-run.d.ts.map +1 -1
- package/dist/v2/helpers/safe-run.js +26 -2
- package/dist/v2/helpers/safe-run.js.map +1 -1
- package/package.json +12 -11
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useSidebarDocuments } from "./use-sidebar-documents.js";
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
//#region src/v2/features/app/hooks/use-active-document-version.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolves everything UI surfaces need to know about the document the user
|
|
6
|
+
* is currently viewing in a registry-backed workspace.
|
|
7
|
+
*
|
|
8
|
+
* The breadcrumb's version picker and the right-side sync indicator both
|
|
9
|
+
* need the same data:
|
|
10
|
+
*
|
|
11
|
+
* - the sidebar item for the active group (so titles match the registry),
|
|
12
|
+
* - the full version list for that group (used to render dropdown rows /
|
|
13
|
+
* feed `useVersionConflictCheck`),
|
|
14
|
+
* - and the currently active version (used for the picker selection and
|
|
15
|
+
* the standalone status icon).
|
|
16
|
+
*
|
|
17
|
+
* Pulling this into a composable keeps both surfaces aligned and avoids
|
|
18
|
+
* duplicating the active-version selection rules — in particular the
|
|
19
|
+
* fallback to the version declared on `x-scalar-registry-meta` when the
|
|
20
|
+
* sidebar's notion of the active version has not caught up yet (e.g. during
|
|
21
|
+
* a pending fetch).
|
|
22
|
+
*/
|
|
23
|
+
var useActiveDocumentVersion = ({ app, registryDocuments }) => {
|
|
24
|
+
const { documents } = useSidebarDocuments({
|
|
25
|
+
app,
|
|
26
|
+
managedDocs: () => registryDocuments().documents ?? []
|
|
27
|
+
});
|
|
28
|
+
/** Registry meta for the currently active document (if any). */
|
|
29
|
+
const activeRegistryMeta = computed(() => {
|
|
30
|
+
return (app.store.value?.workspace.activeDocument)?.["x-scalar-registry-meta"];
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Sidebar item representing the currently active registry-backed document.
|
|
34
|
+
* We match by `namespace + slug` because a single group can contain
|
|
35
|
+
* several versions and the active document may be any of them.
|
|
36
|
+
*/
|
|
37
|
+
const activeItem = computed(() => {
|
|
38
|
+
const meta = activeRegistryMeta.value;
|
|
39
|
+
if (!meta) return;
|
|
40
|
+
return documents.value.find((item) => item.registry?.namespace === meta.namespace && item.registry?.slug === meta.slug);
|
|
41
|
+
});
|
|
42
|
+
/** Versions for the active group, ordered with the latest first. */
|
|
43
|
+
const versions = computed(() => activeItem.value?.versions ?? []);
|
|
44
|
+
return {
|
|
45
|
+
documents,
|
|
46
|
+
activeRegistryMeta,
|
|
47
|
+
activeItem,
|
|
48
|
+
versions,
|
|
49
|
+
activeVersion: computed(() => {
|
|
50
|
+
const meta = activeRegistryMeta.value;
|
|
51
|
+
const list = versions.value;
|
|
52
|
+
if (!meta) return list[0];
|
|
53
|
+
return list.find((v) => v.version === meta.version) ?? list[0];
|
|
54
|
+
})
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
export { useActiveDocumentVersion };
|
|
59
|
+
|
|
60
|
+
//# sourceMappingURL=use-active-document-version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-active-document-version.js","names":[],"sources":["../../../../../src/v2/features/app/hooks/use-active-document-version.ts"],"sourcesContent":["import { type ComputedRef, computed } from 'vue'\n\nimport type { AppState } from '@/v2/features/app/app-state'\nimport {\n type RegistryDocumentsState,\n type SidebarDocumentItem,\n type SidebarDocumentVersion,\n useSidebarDocuments,\n} from '@/v2/features/app/hooks/use-sidebar-documents'\n\n/**\n * Resolves everything UI surfaces need to know about the document the user\n * is currently viewing in a registry-backed workspace.\n *\n * The breadcrumb's version picker and the right-side sync indicator both\n * need the same data:\n *\n * - the sidebar item for the active group (so titles match the registry),\n * - the full version list for that group (used to render dropdown rows /\n * feed `useVersionConflictCheck`),\n * - and the currently active version (used for the picker selection and\n * the standalone status icon).\n *\n * Pulling this into a composable keeps both surfaces aligned and avoids\n * duplicating the active-version selection rules — in particular the\n * fallback to the version declared on `x-scalar-registry-meta` when the\n * sidebar's notion of the active version has not caught up yet (e.g. during\n * a pending fetch).\n */\nexport const useActiveDocumentVersion = ({\n app,\n registryDocuments,\n}: {\n app: AppState\n /** Reactive accessor — components pass a getter so the composable stays prop-driven. */\n registryDocuments: () => RegistryDocumentsState\n}): {\n documents: ComputedRef<SidebarDocumentItem[]>\n activeRegistryMeta: ComputedRef<\n | {\n namespace: string\n slug: string\n version?: string\n commitHash?: string\n conflictCheckedAgainstHash?: string\n hasConflict?: boolean\n }\n | undefined\n >\n activeItem: ComputedRef<SidebarDocumentItem | undefined>\n versions: ComputedRef<SidebarDocumentVersion[]>\n activeVersion: ComputedRef<SidebarDocumentVersion | undefined>\n} => {\n const { documents } = useSidebarDocuments({\n app,\n managedDocs: () => registryDocuments().documents ?? [],\n })\n\n /** Registry meta for the currently active document (if any). */\n const activeRegistryMeta = computed(() => {\n const doc = app.store.value?.workspace.activeDocument\n return doc?.['x-scalar-registry-meta']\n })\n\n /**\n * Sidebar item representing the currently active registry-backed document.\n * We match by `namespace + slug` because a single group can contain\n * several versions and the active document may be any of them.\n */\n const activeItem = computed(() => {\n const meta = activeRegistryMeta.value\n if (!meta) {\n return undefined\n }\n return documents.value.find(\n (item) => item.registry?.namespace === meta.namespace && item.registry?.slug === meta.slug,\n )\n })\n\n /** Versions for the active group, ordered with the latest first. */\n const versions = computed<SidebarDocumentVersion[]>(() => activeItem.value?.versions ?? [])\n\n /**\n * The version currently active on screen. Prefers matching the version\n * declared on the active document's registry meta so consumers always\n * reflect what the user is viewing, even when the sidebar's notion of the\n * active version has not caught up yet (e.g. during a pending fetch).\n */\n const activeVersion = computed<SidebarDocumentVersion | undefined>(() => {\n const meta = activeRegistryMeta.value\n const list = versions.value\n if (!meta) {\n return list[0]\n }\n return list.find((v) => v.version === meta.version) ?? list[0]\n })\n\n return {\n documents,\n activeRegistryMeta,\n activeItem,\n versions,\n activeVersion,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA6BA,IAAa,4BAA4B,EACvC,KACA,wBAqBG;CACH,MAAM,EAAE,cAAc,oBAAoB;EACxC;EACA,mBAAmB,mBAAmB,CAAC,aAAa,EAAE;EACvD,CAAC;;CAGF,MAAM,qBAAqB,eAAe;AAExC,UADY,IAAI,MAAM,OAAO,UAAU,kBAC1B;GACb;;;;;;CAOF,MAAM,aAAa,eAAe;EAChC,MAAM,OAAO,mBAAmB;AAChC,MAAI,CAAC,KACH;AAEF,SAAO,UAAU,MAAM,MACpB,SAAS,KAAK,UAAU,cAAc,KAAK,aAAa,KAAK,UAAU,SAAS,KAAK,KACvF;GACD;;CAGF,MAAM,WAAW,eAAyC,WAAW,OAAO,YAAY,EAAE,CAAC;AAiB3F,QAAO;EACL;EACA;EACA;EACA;EACA,eAdoB,eAAmD;GACvE,MAAM,OAAO,mBAAmB;GAChC,MAAM,OAAO,SAAS;AACtB,OAAI,CAAC,KACH,QAAO,KAAK;AAEd,UAAO,KAAK,MAAM,MAAM,EAAE,YAAY,KAAK,QAAQ,IAAI,KAAK;IAC5D;EAQD"}
|
|
@@ -1,19 +1,51 @@
|
|
|
1
1
|
import type { AppState } from '@scalar/api-client/v2/features/app';
|
|
2
2
|
import type { TraversedDocument } from '@scalar/workspace-store/schemas/navigation';
|
|
3
3
|
import { type MaybeRefOrGetter } from 'vue';
|
|
4
|
+
import { type VersionStatus } from '../../../../v2/features/app/helpers/compute-version-status.js';
|
|
5
|
+
export type { VersionStatus };
|
|
4
6
|
/**
|
|
5
|
-
* A single
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* A single version of a registry-backed document.
|
|
8
|
+
*
|
|
9
|
+
* On team workspaces, a registry document can advertise multiple versions and
|
|
10
|
+
* each one may or may not have been imported into the local workspace store.
|
|
11
|
+
* Loaded versions surface their `documentName` and traversal `navigation`,
|
|
12
|
+
* unloaded versions are placeholders the sidebar can fetch on demand.
|
|
8
13
|
*/
|
|
9
14
|
export type SidebarDocumentVersion = {
|
|
10
|
-
/** Stable key
|
|
15
|
+
/** Stable key: workspace `documentName` when loaded, otherwise `${namespace}/${slug}@${version}`. */
|
|
11
16
|
key: string;
|
|
12
|
-
/**
|
|
17
|
+
/** Version identifier as advertised by the registry. */
|
|
18
|
+
version: string;
|
|
19
|
+
/** User-facing label for the version row. */
|
|
13
20
|
title: string;
|
|
14
|
-
/**
|
|
15
|
-
documentName
|
|
16
|
-
/**
|
|
21
|
+
/** Workspace store document name when this version is loaded locally. */
|
|
22
|
+
documentName?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Commit hash recorded on the locally loaded workspace document, if any.
|
|
25
|
+
* Undefined when the version has not been imported into the workspace
|
|
26
|
+
* store or when the loaded document does not carry a hash.
|
|
27
|
+
*/
|
|
28
|
+
commitHash?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Commit hash advertised by the registry for this version, if any.
|
|
31
|
+
* Compared against `commitHash` to derive `status`.
|
|
32
|
+
*/
|
|
33
|
+
registryCommitHash?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Sync status surfaced for the version row. Derived from the local /
|
|
36
|
+
* registry commit hashes, the document's dirty flag and the cached
|
|
37
|
+
* conflict-check result on `x-scalar-registry-meta`. `unknown` is used
|
|
38
|
+
* for versions that are not loaded into the workspace store yet.
|
|
39
|
+
*/
|
|
40
|
+
status: VersionStatus;
|
|
41
|
+
/**
|
|
42
|
+
* True when this row is the canonical "latest" version of the group: the
|
|
43
|
+
* first version the registry advertises. Drafts (locally-created versions
|
|
44
|
+
* the registry has not seen yet) never get this flag, even when they are
|
|
45
|
+
* surfaced ahead of the registry-advertised rows in the picker.
|
|
46
|
+
*/
|
|
47
|
+
isLatest: boolean;
|
|
48
|
+
/** Traversal tree for this version. Populated only when the version is loaded into the workspace store. */
|
|
17
49
|
navigation?: TraversedDocument;
|
|
18
50
|
};
|
|
19
51
|
/**
|
|
@@ -23,39 +55,53 @@ export type SidebarDocumentVersion = {
|
|
|
23
55
|
* - A workspace document that only exists locally (no registry link)
|
|
24
56
|
* - A workspace document that was imported from the registry
|
|
25
57
|
* - A registry document that has not yet been imported into the store
|
|
58
|
+
*
|
|
59
|
+
* For registry-backed entries, the parent fields (`navigation`, `documentName`)
|
|
60
|
+
* mirror the active version so the sidebar template can render a single tree
|
|
61
|
+
* without having to look up the active version itself. The full version list
|
|
62
|
+
* lives in `versions`.
|
|
26
63
|
*/
|
|
27
64
|
export type SidebarDocumentItem = {
|
|
28
|
-
/** Stable key used for sidebar state
|
|
65
|
+
/** Stable key used for sidebar state: `@namespace/slug` for registry-backed entries, document name otherwise. */
|
|
29
66
|
key: string;
|
|
30
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* User-facing title of the document. Registry-backed entries always surface
|
|
69
|
+
* the registry's title so the sidebar matches what the registry advertises,
|
|
70
|
+
* even when a locally loaded copy has been renamed. Standalone entries use
|
|
71
|
+
* the workspace document title.
|
|
72
|
+
*/
|
|
31
73
|
title: string;
|
|
32
|
-
/** Name of the document inside the workspace store (
|
|
74
|
+
/** Name of the document inside the workspace store (mirrors the active version on registry-backed entries). */
|
|
33
75
|
documentName?: string;
|
|
34
|
-
/** Registry
|
|
76
|
+
/** Registry coordinates for the document group (without the version, which lives on `versions[]`). */
|
|
35
77
|
registry?: {
|
|
36
78
|
namespace: string;
|
|
37
79
|
slug: string;
|
|
38
80
|
};
|
|
39
|
-
/**
|
|
40
|
-
* Traversal tree for the document if it has been loaded in the workspace store.
|
|
41
|
-
* When `undefined` the document still needs to be fetched from the registry
|
|
42
|
-
* before its nested content can be shown.
|
|
43
|
-
*/
|
|
81
|
+
/** Traversal tree of the active version (or the lone document for standalone entries). */
|
|
44
82
|
navigation?: TraversedDocument;
|
|
45
83
|
/** Whether the document is pinned (todo: derived from `x-scalar-pinned`) */
|
|
46
84
|
isPinned?: boolean;
|
|
47
85
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
86
|
+
* All known versions of the document, ordered with the registry's ordering
|
|
87
|
+
* preserved (latest first by convention). Loaded versions surface their
|
|
88
|
+
* workspace `documentName` and `navigation`, unloaded ones act as
|
|
89
|
+
* placeholders the sidebar can fetch on demand. Undefined for standalone
|
|
90
|
+
* entries that have no registry coordinates.
|
|
52
91
|
*/
|
|
53
92
|
versions?: SidebarDocumentVersion[];
|
|
93
|
+
/** Key of the version currently surfaced at the parent level (matches a `versions[].key`). */
|
|
94
|
+
activeVersionKey?: string;
|
|
95
|
+
};
|
|
96
|
+
type RegistryDocumentVersion = {
|
|
97
|
+
version: string;
|
|
98
|
+
commitHash?: string;
|
|
54
99
|
};
|
|
55
100
|
export type RegistryDocument = {
|
|
56
101
|
namespace: string;
|
|
57
102
|
slug: string;
|
|
58
103
|
title: string;
|
|
104
|
+
versions: RegistryDocumentVersion[];
|
|
59
105
|
};
|
|
60
106
|
/**
|
|
61
107
|
* Loading-aware wrapper for the registry documents prop.
|
|
@@ -80,8 +126,10 @@ export type RegistryDocumentsState = {
|
|
|
80
126
|
* Registry documents are not considered at all.
|
|
81
127
|
* - Team workspaces group workspace documents by `namespace + slug` from
|
|
82
128
|
* `x-scalar-registry-meta`. Each unique registry coordinate produces a
|
|
83
|
-
* single sidebar entry whose
|
|
84
|
-
*
|
|
129
|
+
* single sidebar entry whose versions are exposed as `versions`. The
|
|
130
|
+
* `versions` array merges the registry-advertised versions with any
|
|
131
|
+
* loaded workspace counterparts (matched by `version`). Registry
|
|
132
|
+
* documents that have no loaded match are still surfaced as entries
|
|
85
133
|
* waiting to be fetched.
|
|
86
134
|
*/
|
|
87
135
|
export declare function useSidebarDocuments({ app, managedDocs, }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-sidebar-documents.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/app/hooks/use-sidebar-documents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAA;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAA;AACnF,OAAO,EAAE,KAAK,gBAAgB,EAAqB,MAAM,KAAK,CAAA;AAE9D
|
|
1
|
+
{"version":3,"file":"use-sidebar-documents.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/app/hooks/use-sidebar-documents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAA;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAA;AACnF,OAAO,EAAE,KAAK,gBAAgB,EAAqB,MAAM,KAAK,CAAA;AAE9D,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,kDAAkD,CAAA;AAE3G,YAAY,EAAE,aAAa,EAAE,CAAA;AAE7B;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,qGAAqG;IACrG,GAAG,EAAE,MAAM,CAAA;IACX,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAA;IACf,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;;OAKG;IACH,MAAM,EAAE,aAAa,CAAA;IACrB;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,2GAA2G;IAC3G,UAAU,CAAC,EAAE,iBAAiB,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,iHAAiH;IACjH,GAAG,EAAE,MAAM,CAAA;IACX;;;;;OAKG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,+GAA+G;IAC/G,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,sGAAsG;IACtG,QAAQ,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9C,0FAA0F;IAC1F,UAAU,CAAC,EAAE,iBAAiB,CAAA;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAA;IACnC,8FAA8F;IAC9F,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,CAAA;AAsBD,KAAK,uBAAuB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,uBAAuB,EAAE,CAAA;CACpC,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAC9B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAA;AAMxD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,WAAW,GACZ,EAAE;IACD,GAAG,EAAE,QAAQ,CAAA;IACb,WAAW,EAAE,gBAAgB,CAAC,gBAAgB,EAAE,CAAC,CAAA;CAClD;;;;EA+HA"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { computeVersionStatus } from "../helpers/compute-version-status.js";
|
|
1
2
|
import { computed, toValue } from "vue";
|
|
2
3
|
//#region src/v2/features/app/hooks/use-sidebar-documents.ts
|
|
3
4
|
var registryKey = (namespace, slug) => `@${namespace}/${slug}`;
|
|
5
|
+
var versionKey = (namespace, slug, version) => `${registryKey(namespace, slug)}@${version}`;
|
|
4
6
|
/**
|
|
5
7
|
* Builds a unified list of sidebar documents.
|
|
6
8
|
*
|
|
@@ -9,38 +11,49 @@ var registryKey = (namespace, slug) => `@${namespace}/${slug}`;
|
|
|
9
11
|
* Registry documents are not considered at all.
|
|
10
12
|
* - Team workspaces group workspace documents by `namespace + slug` from
|
|
11
13
|
* `x-scalar-registry-meta`. Each unique registry coordinate produces a
|
|
12
|
-
* single sidebar entry whose
|
|
13
|
-
*
|
|
14
|
+
* single sidebar entry whose versions are exposed as `versions`. The
|
|
15
|
+
* `versions` array merges the registry-advertised versions with any
|
|
16
|
+
* loaded workspace counterparts (matched by `version`). Registry
|
|
17
|
+
* documents that have no loaded match are still surfaced as entries
|
|
14
18
|
* waiting to be fetched.
|
|
15
19
|
*/
|
|
16
20
|
function useSidebarDocuments({ app, managedDocs }) {
|
|
17
21
|
const isTeamWorkspace = app.workspace.isTeamWorkspace;
|
|
18
|
-
/** Raw workspace documents
|
|
22
|
+
/** Raw workspace documents projected into the shape the grouping logic needs. */
|
|
19
23
|
const workspaceEntries = computed(() => {
|
|
20
24
|
const store = app.store.value;
|
|
21
25
|
if (!store) return [];
|
|
22
26
|
return Object.entries(store.workspace.documents).map(([name, doc]) => {
|
|
23
27
|
const registry = doc?.["x-scalar-registry-meta"];
|
|
24
28
|
const navigation = doc?.["x-scalar-navigation"];
|
|
25
|
-
const title = navigation?.title || doc?.info?.title || "Untitled";
|
|
26
|
-
const isTeam = isTeamWorkspace.value;
|
|
27
29
|
return {
|
|
28
|
-
key: isTeam && registry ? registryKey(registry.namespace, registry.slug) : name,
|
|
29
|
-
title,
|
|
30
30
|
documentName: name,
|
|
31
|
-
|
|
32
|
-
namespace: registry.namespace,
|
|
33
|
-
slug: registry.slug
|
|
34
|
-
} : void 0,
|
|
31
|
+
title: navigation?.title || doc?.info?.title || "Untitled",
|
|
35
32
|
navigation,
|
|
36
|
-
isPinned: false
|
|
33
|
+
isPinned: false,
|
|
34
|
+
isDirty: doc?.["x-scalar-is-dirty"] === true,
|
|
35
|
+
registry: registry ? {
|
|
36
|
+
namespace: registry.namespace,
|
|
37
|
+
slug: registry.slug,
|
|
38
|
+
version: registry.version,
|
|
39
|
+
commitHash: registry.commitHash,
|
|
40
|
+
conflictCheckedAgainstHash: registry.conflictCheckedAgainstHash,
|
|
41
|
+
hasConflict: registry.hasConflict
|
|
42
|
+
} : void 0
|
|
37
43
|
};
|
|
38
44
|
});
|
|
39
45
|
});
|
|
40
46
|
const documents = computed(() => {
|
|
41
|
-
if (!isTeamWorkspace.value) return workspaceEntries.value
|
|
47
|
+
if (!isTeamWorkspace.value) return workspaceEntries.value.map((entry) => ({
|
|
48
|
+
key: entry.documentName,
|
|
49
|
+
title: entry.title,
|
|
50
|
+
documentName: entry.documentName,
|
|
51
|
+
registry: void 0,
|
|
52
|
+
navigation: entry.navigation,
|
|
53
|
+
isPinned: entry.isPinned ?? false
|
|
54
|
+
}));
|
|
42
55
|
const activeDocumentSlug = app.activeEntities.documentSlug.value;
|
|
43
|
-
const
|
|
56
|
+
const workspaceByRegistry = /* @__PURE__ */ new Map();
|
|
44
57
|
const standalone = [];
|
|
45
58
|
for (const entry of workspaceEntries.value) {
|
|
46
59
|
if (!entry.registry) {
|
|
@@ -48,42 +61,41 @@ function useSidebarDocuments({ app, managedDocs }) {
|
|
|
48
61
|
continue;
|
|
49
62
|
}
|
|
50
63
|
const key = registryKey(entry.registry.namespace, entry.registry.slug);
|
|
51
|
-
const bucket =
|
|
64
|
+
const bucket = workspaceByRegistry.get(key);
|
|
52
65
|
if (bucket) bucket.push(entry);
|
|
53
|
-
else
|
|
66
|
+
else workspaceByRegistry.set(key, [entry]);
|
|
54
67
|
}
|
|
55
68
|
const grouped = [];
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
navigation: e.navigation
|
|
66
|
-
}));
|
|
67
|
-
grouped.push({
|
|
68
|
-
...primary,
|
|
69
|
-
isPinned: entries.some((e) => e.isPinned),
|
|
70
|
-
versions: versions.length ? versions : void 0
|
|
69
|
+
const consumedRegistryKeys = /* @__PURE__ */ new Set();
|
|
70
|
+
for (const doc of toValue(managedDocs)) {
|
|
71
|
+
const key = registryKey(doc.namespace, doc.slug);
|
|
72
|
+
consumedRegistryKeys.add(key);
|
|
73
|
+
const item = buildRegistryItem({
|
|
74
|
+
key,
|
|
75
|
+
registry: doc,
|
|
76
|
+
loaded: workspaceByRegistry.get(key) ?? [],
|
|
77
|
+
activeDocumentSlug
|
|
71
78
|
});
|
|
79
|
+
if (item) grouped.push(item);
|
|
72
80
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
81
|
+
for (const [key, loaded] of workspaceByRegistry) {
|
|
82
|
+
if (consumedRegistryKeys.has(key)) continue;
|
|
83
|
+
const first = loaded[0]?.registry;
|
|
84
|
+
if (!first) continue;
|
|
85
|
+
const item = buildRegistryItem({
|
|
86
|
+
key,
|
|
87
|
+
registry: {
|
|
88
|
+
namespace: first.namespace,
|
|
89
|
+
slug: first.slug,
|
|
90
|
+
title: loaded[0]?.title ?? first.slug,
|
|
91
|
+
versions: []
|
|
92
|
+
},
|
|
93
|
+
loaded,
|
|
94
|
+
activeDocumentSlug
|
|
95
|
+
});
|
|
96
|
+
if (item) grouped.push(item);
|
|
97
|
+
}
|
|
98
|
+
return [...grouped, ...standalone.map(toStandaloneItem)];
|
|
87
99
|
});
|
|
88
100
|
return {
|
|
89
101
|
documents,
|
|
@@ -91,6 +103,116 @@ function useSidebarDocuments({ app, managedDocs }) {
|
|
|
91
103
|
rest: computed(() => documents.value.filter((d) => !d.isPinned))
|
|
92
104
|
};
|
|
93
105
|
}
|
|
106
|
+
/** Project a standalone (non-registry) workspace entry into a sidebar item. */
|
|
107
|
+
var toStandaloneItem = (entry) => ({
|
|
108
|
+
key: entry.documentName,
|
|
109
|
+
title: entry.title,
|
|
110
|
+
documentName: entry.documentName,
|
|
111
|
+
registry: void 0,
|
|
112
|
+
navigation: entry.navigation,
|
|
113
|
+
isPinned: entry.isPinned ?? false
|
|
114
|
+
});
|
|
115
|
+
/**
|
|
116
|
+
* Build a single registry-backed sidebar item. The version list is assembled
|
|
117
|
+
* by walking the registry's advertised versions in order and pairing them
|
|
118
|
+
* with any loaded workspace document that claims the same `version` string.
|
|
119
|
+
* Loaded versions that the registry has not advertised are appended at the
|
|
120
|
+
* end so they stay visible until the registry catches up.
|
|
121
|
+
*/
|
|
122
|
+
var buildRegistryItem = ({ key, registry, loaded, activeDocumentSlug }) => {
|
|
123
|
+
const loadedByVersion = /* @__PURE__ */ new Map();
|
|
124
|
+
const orphans = [];
|
|
125
|
+
for (const entry of loaded) {
|
|
126
|
+
const version = entry.registry?.version;
|
|
127
|
+
if (!version) {
|
|
128
|
+
orphans.push(entry);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (loadedByVersion.has(version)) {
|
|
132
|
+
orphans.push(entry);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
loadedByVersion.set(version, entry);
|
|
136
|
+
}
|
|
137
|
+
const versions = [];
|
|
138
|
+
const groupTitle = registry.title || registry.slug;
|
|
139
|
+
const draftEntries = [];
|
|
140
|
+
for (const [version, match] of loadedByVersion) {
|
|
141
|
+
if (registry.versions.some((v) => v.version === version)) continue;
|
|
142
|
+
draftEntries.push([version, match]);
|
|
143
|
+
}
|
|
144
|
+
draftEntries.reverse();
|
|
145
|
+
for (const [version, match] of draftEntries) versions.push({
|
|
146
|
+
key: match.documentName,
|
|
147
|
+
version,
|
|
148
|
+
title: groupTitle,
|
|
149
|
+
documentName: match.documentName,
|
|
150
|
+
commitHash: match.registry?.commitHash,
|
|
151
|
+
registryCommitHash: void 0,
|
|
152
|
+
status: computeVersionStatus({
|
|
153
|
+
isLoaded: true,
|
|
154
|
+
localHash: match.registry?.commitHash,
|
|
155
|
+
registryHash: void 0,
|
|
156
|
+
isDirty: match.isDirty
|
|
157
|
+
}),
|
|
158
|
+
isLatest: false,
|
|
159
|
+
navigation: match.navigation
|
|
160
|
+
});
|
|
161
|
+
registry.versions.forEach((v, registryIndex) => {
|
|
162
|
+
const match = loadedByVersion.get(v.version);
|
|
163
|
+
const localHash = match?.registry?.commitHash;
|
|
164
|
+
const registryHash = v.commitHash;
|
|
165
|
+
versions.push({
|
|
166
|
+
key: match ? match.documentName : versionKey(registry.namespace, registry.slug, v.version),
|
|
167
|
+
version: v.version,
|
|
168
|
+
title: groupTitle,
|
|
169
|
+
documentName: match?.documentName,
|
|
170
|
+
commitHash: localHash,
|
|
171
|
+
registryCommitHash: registryHash,
|
|
172
|
+
status: computeVersionStatus({
|
|
173
|
+
isLoaded: Boolean(match),
|
|
174
|
+
localHash,
|
|
175
|
+
registryHash,
|
|
176
|
+
isDirty: match?.isDirty,
|
|
177
|
+
conflictCheckedAgainstHash: match?.registry?.conflictCheckedAgainstHash,
|
|
178
|
+
hasConflict: match?.registry?.hasConflict
|
|
179
|
+
}),
|
|
180
|
+
isLatest: registryIndex === 0,
|
|
181
|
+
navigation: match?.navigation
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
for (const orphan of orphans) versions.push({
|
|
185
|
+
key: orphan.documentName,
|
|
186
|
+
version: orphan.registry?.version ?? "",
|
|
187
|
+
title: groupTitle,
|
|
188
|
+
documentName: orphan.documentName,
|
|
189
|
+
commitHash: orphan.registry?.commitHash,
|
|
190
|
+
registryCommitHash: void 0,
|
|
191
|
+
status: computeVersionStatus({
|
|
192
|
+
isLoaded: true,
|
|
193
|
+
localHash: orphan.registry?.commitHash,
|
|
194
|
+
registryHash: void 0,
|
|
195
|
+
isDirty: orphan.isDirty
|
|
196
|
+
}),
|
|
197
|
+
isLatest: false,
|
|
198
|
+
navigation: orphan.navigation
|
|
199
|
+
});
|
|
200
|
+
if (versions.length === 0) return;
|
|
201
|
+
const activeVersion = versions.find((v) => v.documentName !== void 0 && v.documentName === activeDocumentSlug) ?? versions.find((v) => v.documentName !== void 0) ?? versions[0];
|
|
202
|
+
return {
|
|
203
|
+
key,
|
|
204
|
+
title: groupTitle,
|
|
205
|
+
documentName: activeVersion.documentName,
|
|
206
|
+
registry: {
|
|
207
|
+
namespace: registry.namespace,
|
|
208
|
+
slug: registry.slug
|
|
209
|
+
},
|
|
210
|
+
navigation: activeVersion.navigation,
|
|
211
|
+
isPinned: loaded.some((e) => e.isPinned),
|
|
212
|
+
versions,
|
|
213
|
+
activeVersionKey: activeVersion.key
|
|
214
|
+
};
|
|
215
|
+
};
|
|
94
216
|
//#endregion
|
|
95
217
|
export { useSidebarDocuments };
|
|
96
218
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-sidebar-documents.js","names":[],"sources":["../../../../../src/v2/features/app/hooks/use-sidebar-documents.ts"],"sourcesContent":["import type { AppState } from '@scalar/api-client/v2/features/app'\nimport type { TraversedDocument } from '@scalar/workspace-store/schemas/navigation'\nimport { type MaybeRefOrGetter, computed, toValue } from 'vue'\n\n/**\n * A single \"version\" of a document grouped under a registry namespace + slug.\n * Only used on team workspaces, where multiple local documents may share the\n * same registry coordinates.\n */\nexport type SidebarDocumentVersion = {\n /** Stable key, matches the workspace document name */\n key: string\n /** User facing label for the version */\n title: string\n /** Name of the document inside the workspace store */\n documentName: string\n /** Traversal tree for the document (if it has been loaded) */\n navigation?: TraversedDocument\n}\n\n/**\n * A unified item for the top-level of our sidebar.\n *\n * It can represent one of three things:\n * - A workspace document that only exists locally (no registry link)\n * - A workspace document that was imported from the registry\n * - A registry document that has not yet been imported into the store\n */\nexport type SidebarDocumentItem = {\n /** Stable key used for sidebar state keyed by `namespace/slug` or document name */\n key: string\n /** User facing title of the document */\n title: string\n /** Name of the document inside the workspace store (if loaded) */\n documentName?: string\n /** Registry metadata if available */\n registry?: { namespace: string; slug: string }\n /**\n * Traversal tree for the document if it has been loaded in the workspace store.\n * When `undefined` the document still needs to be fetched from the registry\n * before its nested content can be shown.\n */\n navigation?: TraversedDocument\n /** Whether the document is pinned (todo: derived from `x-scalar-pinned`) */\n isPinned?: boolean\n /**\n * TODO: implement versioning logic\n * Other loaded documents that share this item's `namespace + slug`. Only\n * populated on team workspaces where we collapse duplicates into a single\n * entry with multiple versions.\n */\n versions?: SidebarDocumentVersion[]\n}\n\ntype WorkspaceDocumentEntry = SidebarDocumentItem & { documentName: string }\n\nexport type RegistryDocument = {\n namespace: string\n slug: string\n title: string\n}\n\n/**\n * Loading-aware wrapper for the registry documents prop.\n *\n * The sidebar uses the `status` to decide whether to render skeleton\n * placeholders while the registry is being fetched. `documents` is optional\n * during loading so callers can either render nothing or stream in cached\n * results while a refresh is still in flight.\n */\nexport type RegistryDocumentsState =\n | { status: 'loading'; documents?: RegistryDocument[] }\n | { status: 'success'; documents: RegistryDocument[] }\n\nconst registryKey = (namespace: string, slug: string) => `@${namespace}/${slug}`\n\n/**\n * Builds a unified list of sidebar documents.\n *\n * Behavior:\n * - Local workspaces (`teamUid === 'local'`) only show workspace documents.\n * Registry documents are not considered at all.\n * - Team workspaces group workspace documents by `namespace + slug` from\n * `x-scalar-registry-meta`. Each unique registry coordinate produces a\n * single sidebar entry whose additional matches are exposed as `versions`.\n * Registry documents that have no loaded match are appended as entries\n * waiting to be fetched.\n */\nexport function useSidebarDocuments({\n app,\n managedDocs,\n}: {\n app: AppState\n managedDocs: MaybeRefOrGetter<RegistryDocument[]>\n}) {\n const isTeamWorkspace = app.workspace.isTeamWorkspace\n\n /** Raw workspace documents mapped to sidebar entries (pre-grouping). */\n const workspaceEntries = computed<WorkspaceDocumentEntry[]>(() => {\n const store = app.store.value\n if (!store) {\n return []\n }\n\n return Object.entries(store.workspace.documents).map(([name, doc]) => {\n const registry = doc?.['x-scalar-registry-meta']\n const navigation = doc?.['x-scalar-navigation'] as TraversedDocument | undefined\n\n const title = navigation?.title || doc?.info?.title || 'Untitled'\n\n // On team workspaces we key by registry coordinates so entries with the\n // same `namespace/slug` can later be grouped into a single row with\n // versions. On local workspaces we always key by the workspace document\n // name, which is guaranteed to be unique because it is the map key in\n // `store.workspace.documents`. If we derived the key from registry meta\n // on local workspaces too, two documents sharing the same\n // `x-scalar-registry-meta` would produce duplicate Vue `:key`s in the\n // sidebar `v-for` and silently collide on re-render.\n const isTeam = isTeamWorkspace.value\n return {\n key: isTeam && registry ? registryKey(registry.namespace, registry.slug) : name,\n title,\n documentName: name,\n registry: isTeam && registry ? { namespace: registry.namespace, slug: registry.slug } : undefined,\n navigation,\n // TODO: we can implement this later\n isPinned: false,\n }\n })\n })\n const documents = computed<SidebarDocumentItem[]>(() => {\n // Local workspaces: show the workspace document list as-is, no registry\n // grouping and no registry document lookups.\n if (!isTeamWorkspace.value) {\n return workspaceEntries.value\n }\n\n const activeDocumentSlug = app.activeEntities.documentSlug.value\n\n // 1. Bucket workspace documents by their registry `namespace + slug`.\n // Documents without registry meta remain standalone entries.\n const groups = new Map<string, WorkspaceDocumentEntry[]>()\n const standalone: WorkspaceDocumentEntry[] = []\n\n for (const entry of workspaceEntries.value) {\n if (!entry.registry) {\n standalone.push(entry)\n continue\n }\n const key = registryKey(entry.registry.namespace, entry.registry.slug)\n const bucket = groups.get(key)\n if (bucket) {\n bucket.push(entry)\n } else {\n groups.set(key, [entry])\n }\n }\n\n // 2. Collapse each group into a single sidebar entry. The active document\n // is promoted to primary when possible so the visible entry matches\n // what is currently being viewed. The remaining documents in the\n // group become selectable versions.\n const grouped: SidebarDocumentItem[] = []\n for (const [, entries] of groups) {\n const activeIndex = entries.findIndex((e) => e.documentName === activeDocumentSlug)\n const primaryIndex = activeIndex === -1 ? 0 : activeIndex\n const primary = entries[primaryIndex]\n if (!primary) {\n continue\n }\n\n const versions = entries\n .filter((_, i) => i !== primaryIndex)\n .map<SidebarDocumentVersion>((e) => ({\n key: e.documentName,\n title: e.title,\n documentName: e.documentName,\n navigation: e.navigation,\n }))\n\n grouped.push({\n ...primary,\n isPinned: entries.some((e) => e.isPinned),\n versions: versions.length ? versions : undefined,\n })\n }\n\n // 3. Merge in registry documents that have no loaded counterpart yet.\n // They render as placeholders until the user clicks to fetch them.\n const loadedKeys = new Set(groups.keys())\n const registryOnly = toValue(managedDocs)\n .filter((doc) => !loadedKeys.has(registryKey(doc.namespace, doc.slug)))\n .map<SidebarDocumentItem>((doc) => ({\n key: registryKey(doc.namespace, doc.slug),\n title: doc.title || doc.slug,\n registry: { namespace: doc.namespace, slug: doc.slug },\n }))\n\n return [...grouped, ...registryOnly, ...standalone]\n })\n\n const pinned = computed(() => documents.value.filter((d) => d.isPinned))\n const rest = computed(() => documents.value.filter((d) => !d.isPinned))\n\n return { documents, pinned, rest }\n}\n"],"mappings":";;AA0EA,IAAM,eAAe,WAAmB,SAAiB,IAAI,UAAU,GAAG;;;;;;;;;;;;;AAc1E,SAAgB,oBAAoB,EAClC,KACA,eAIC;CACD,MAAM,kBAAkB,IAAI,UAAU;;CAGtC,MAAM,mBAAmB,eAAyC;EAChE,MAAM,QAAQ,IAAI,MAAM;AACxB,MAAI,CAAC,MACH,QAAO,EAAE;AAGX,SAAO,OAAO,QAAQ,MAAM,UAAU,UAAU,CAAC,KAAK,CAAC,MAAM,SAAS;GACpE,MAAM,WAAW,MAAM;GACvB,MAAM,aAAa,MAAM;GAEzB,MAAM,QAAQ,YAAY,SAAS,KAAK,MAAM,SAAS;GAUvD,MAAM,SAAS,gBAAgB;AAC/B,UAAO;IACL,KAAK,UAAU,WAAW,YAAY,SAAS,WAAW,SAAS,KAAK,GAAG;IAC3E;IACA,cAAc;IACd,UAAU,UAAU,WAAW;KAAE,WAAW,SAAS;KAAW,MAAM,SAAS;KAAM,GAAG,KAAA;IACxF;IAEA,UAAU;IACX;IACD;GACF;CACF,MAAM,YAAY,eAAsC;AAGtD,MAAI,CAAC,gBAAgB,MACnB,QAAO,iBAAiB;EAG1B,MAAM,qBAAqB,IAAI,eAAe,aAAa;EAI3D,MAAM,yBAAS,IAAI,KAAuC;EAC1D,MAAM,aAAuC,EAAE;AAE/C,OAAK,MAAM,SAAS,iBAAiB,OAAO;AAC1C,OAAI,CAAC,MAAM,UAAU;AACnB,eAAW,KAAK,MAAM;AACtB;;GAEF,MAAM,MAAM,YAAY,MAAM,SAAS,WAAW,MAAM,SAAS,KAAK;GACtE,MAAM,SAAS,OAAO,IAAI,IAAI;AAC9B,OAAI,OACF,QAAO,KAAK,MAAM;OAElB,QAAO,IAAI,KAAK,CAAC,MAAM,CAAC;;EAQ5B,MAAM,UAAiC,EAAE;AACzC,OAAK,MAAM,GAAG,YAAY,QAAQ;GAChC,MAAM,cAAc,QAAQ,WAAW,MAAM,EAAE,iBAAiB,mBAAmB;GACnF,MAAM,eAAe,gBAAgB,KAAK,IAAI;GAC9C,MAAM,UAAU,QAAQ;AACxB,OAAI,CAAC,QACH;GAGF,MAAM,WAAW,QACd,QAAQ,GAAG,MAAM,MAAM,aAAa,CACpC,KAA6B,OAAO;IACnC,KAAK,EAAE;IACP,OAAO,EAAE;IACT,cAAc,EAAE;IAChB,YAAY,EAAE;IACf,EAAE;AAEL,WAAQ,KAAK;IACX,GAAG;IACH,UAAU,QAAQ,MAAM,MAAM,EAAE,SAAS;IACzC,UAAU,SAAS,SAAS,WAAW,KAAA;IACxC,CAAC;;EAKJ,MAAM,aAAa,IAAI,IAAI,OAAO,MAAM,CAAC;EACzC,MAAM,eAAe,QAAQ,YAAY,CACtC,QAAQ,QAAQ,CAAC,WAAW,IAAI,YAAY,IAAI,WAAW,IAAI,KAAK,CAAC,CAAC,CACtE,KAA0B,SAAS;GAClC,KAAK,YAAY,IAAI,WAAW,IAAI,KAAK;GACzC,OAAO,IAAI,SAAS,IAAI;GACxB,UAAU;IAAE,WAAW,IAAI;IAAW,MAAM,IAAI;IAAM;GACvD,EAAE;AAEL,SAAO;GAAC,GAAG;GAAS,GAAG;GAAc,GAAG;GAAW;GACnD;AAKF,QAAO;EAAE;EAAW,QAHL,eAAe,UAAU,MAAM,QAAQ,MAAM,EAAE,SAAS,CAAC;EAG5C,MAFf,eAAe,UAAU,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS,CAAC;EAErC"}
|
|
1
|
+
{"version":3,"file":"use-sidebar-documents.js","names":[],"sources":["../../../../../src/v2/features/app/hooks/use-sidebar-documents.ts"],"sourcesContent":["import type { AppState } from '@scalar/api-client/v2/features/app'\nimport type { TraversedDocument } from '@scalar/workspace-store/schemas/navigation'\nimport { type MaybeRefOrGetter, computed, toValue } from 'vue'\n\nimport { type VersionStatus, computeVersionStatus } from '@/v2/features/app/helpers/compute-version-status'\n\nexport type { VersionStatus }\n\n/**\n * A single version of a registry-backed document.\n *\n * On team workspaces, a registry document can advertise multiple versions and\n * each one may or may not have been imported into the local workspace store.\n * Loaded versions surface their `documentName` and traversal `navigation`,\n * unloaded versions are placeholders the sidebar can fetch on demand.\n */\nexport type SidebarDocumentVersion = {\n /** Stable key: workspace `documentName` when loaded, otherwise `${namespace}/${slug}@${version}`. */\n key: string\n /** Version identifier as advertised by the registry. */\n version: string\n /** User-facing label for the version row. */\n title: string\n /** Workspace store document name when this version is loaded locally. */\n documentName?: string\n /**\n * Commit hash recorded on the locally loaded workspace document, if any.\n * Undefined when the version has not been imported into the workspace\n * store or when the loaded document does not carry a hash.\n */\n commitHash?: string\n /**\n * Commit hash advertised by the registry for this version, if any.\n * Compared against `commitHash` to derive `status`.\n */\n registryCommitHash?: string\n /**\n * Sync status surfaced for the version row. Derived from the local /\n * registry commit hashes, the document's dirty flag and the cached\n * conflict-check result on `x-scalar-registry-meta`. `unknown` is used\n * for versions that are not loaded into the workspace store yet.\n */\n status: VersionStatus\n /**\n * True when this row is the canonical \"latest\" version of the group: the\n * first version the registry advertises. Drafts (locally-created versions\n * the registry has not seen yet) never get this flag, even when they are\n * surfaced ahead of the registry-advertised rows in the picker.\n */\n isLatest: boolean\n /** Traversal tree for this version. Populated only when the version is loaded into the workspace store. */\n navigation?: TraversedDocument\n}\n\n/**\n * A unified item for the top-level of our sidebar.\n *\n * It can represent one of three things:\n * - A workspace document that only exists locally (no registry link)\n * - A workspace document that was imported from the registry\n * - A registry document that has not yet been imported into the store\n *\n * For registry-backed entries, the parent fields (`navigation`, `documentName`)\n * mirror the active version so the sidebar template can render a single tree\n * without having to look up the active version itself. The full version list\n * lives in `versions`.\n */\nexport type SidebarDocumentItem = {\n /** Stable key used for sidebar state: `@namespace/slug` for registry-backed entries, document name otherwise. */\n key: string\n /**\n * User-facing title of the document. Registry-backed entries always surface\n * the registry's title so the sidebar matches what the registry advertises,\n * even when a locally loaded copy has been renamed. Standalone entries use\n * the workspace document title.\n */\n title: string\n /** Name of the document inside the workspace store (mirrors the active version on registry-backed entries). */\n documentName?: string\n /** Registry coordinates for the document group (without the version, which lives on `versions[]`). */\n registry?: { namespace: string; slug: string }\n /** Traversal tree of the active version (or the lone document for standalone entries). */\n navigation?: TraversedDocument\n /** Whether the document is pinned (todo: derived from `x-scalar-pinned`) */\n isPinned?: boolean\n /**\n * All known versions of the document, ordered with the registry's ordering\n * preserved (latest first by convention). Loaded versions surface their\n * workspace `documentName` and `navigation`, unloaded ones act as\n * placeholders the sidebar can fetch on demand. Undefined for standalone\n * entries that have no registry coordinates.\n */\n versions?: SidebarDocumentVersion[]\n /** Key of the version currently surfaced at the parent level (matches a `versions[].key`). */\n activeVersionKey?: string\n}\n\n/** Internal projection of a workspace document used during grouping. */\ntype WorkspaceDocumentEntry = {\n documentName: string\n title: string\n navigation?: TraversedDocument\n isPinned?: boolean\n /** Whether the workspace document has uncommitted local edits. */\n isDirty?: boolean\n registry?: {\n namespace: string\n slug: string\n version?: string\n commitHash?: string\n /** Last registry hash the conflict cache was computed against. */\n conflictCheckedAgainstHash?: string\n /** Cached conflict-check outcome for `conflictCheckedAgainstHash`. */\n hasConflict?: boolean\n }\n}\n\ntype RegistryDocumentVersion = {\n version: string\n commitHash?: string\n}\n\nexport type RegistryDocument = {\n namespace: string\n slug: string\n title: string\n versions: RegistryDocumentVersion[]\n}\n\n/**\n * Loading-aware wrapper for the registry documents prop.\n *\n * The sidebar uses the `status` to decide whether to render skeleton\n * placeholders while the registry is being fetched. `documents` is optional\n * during loading so callers can either render nothing or stream in cached\n * results while a refresh is still in flight.\n */\nexport type RegistryDocumentsState =\n | { status: 'loading'; documents?: RegistryDocument[] }\n | { status: 'success'; documents: RegistryDocument[] }\n\nconst registryKey = (namespace: string, slug: string) => `@${namespace}/${slug}`\n\nconst versionKey = (namespace: string, slug: string, version: string) => `${registryKey(namespace, slug)}@${version}`\n\n/**\n * Builds a unified list of sidebar documents.\n *\n * Behavior:\n * - Local workspaces (`teamUid === 'local'`) only show workspace documents.\n * Registry documents are not considered at all.\n * - Team workspaces group workspace documents by `namespace + slug` from\n * `x-scalar-registry-meta`. Each unique registry coordinate produces a\n * single sidebar entry whose versions are exposed as `versions`. The\n * `versions` array merges the registry-advertised versions with any\n * loaded workspace counterparts (matched by `version`). Registry\n * documents that have no loaded match are still surfaced as entries\n * waiting to be fetched.\n */\nexport function useSidebarDocuments({\n app,\n managedDocs,\n}: {\n app: AppState\n managedDocs: MaybeRefOrGetter<RegistryDocument[]>\n}) {\n const isTeamWorkspace = app.workspace.isTeamWorkspace\n\n /** Raw workspace documents projected into the shape the grouping logic needs. */\n const workspaceEntries = computed<WorkspaceDocumentEntry[]>(() => {\n const store = app.store.value\n if (!store) {\n return []\n }\n\n return Object.entries(store.workspace.documents).map(([name, doc]) => {\n const registry = doc?.['x-scalar-registry-meta']\n const navigation = doc?.['x-scalar-navigation'] as TraversedDocument | undefined\n\n const title = navigation?.title || doc?.info?.title || 'Untitled'\n\n return {\n documentName: name,\n title,\n navigation,\n // TODO: we can implement this later\n isPinned: false,\n isDirty: doc?.['x-scalar-is-dirty'] === true,\n registry: registry\n ? {\n namespace: registry.namespace,\n slug: registry.slug,\n version: registry.version,\n commitHash: registry.commitHash,\n conflictCheckedAgainstHash: registry.conflictCheckedAgainstHash,\n hasConflict: registry.hasConflict,\n }\n : undefined,\n }\n })\n })\n\n const documents = computed<SidebarDocumentItem[]>(() => {\n // Local workspaces: show the workspace document list as-is, no registry\n // grouping and no registry document lookups. The sidebar key is derived\n // from the workspace document name (which is guaranteed unique because\n // it is the map key in `store.workspace.documents`). If we keyed by\n // registry coordinates instead, two local documents sharing the same\n // `x-scalar-registry-meta` would produce duplicate Vue `:key`s in the\n // sidebar `v-for` and silently collide on re-render.\n if (!isTeamWorkspace.value) {\n return workspaceEntries.value.map<SidebarDocumentItem>((entry) => ({\n key: entry.documentName,\n title: entry.title,\n documentName: entry.documentName,\n registry: undefined,\n navigation: entry.navigation,\n isPinned: entry.isPinned ?? false,\n }))\n }\n\n const activeDocumentSlug = app.activeEntities.documentSlug.value\n\n // 1. Bucket workspace documents by their registry `namespace + slug`.\n // Documents without registry meta remain standalone entries.\n const workspaceByRegistry = new Map<string, WorkspaceDocumentEntry[]>()\n const standalone: WorkspaceDocumentEntry[] = []\n\n for (const entry of workspaceEntries.value) {\n if (!entry.registry) {\n standalone.push(entry)\n continue\n }\n const key = registryKey(entry.registry.namespace, entry.registry.slug)\n const bucket = workspaceByRegistry.get(key)\n if (bucket) {\n bucket.push(entry)\n } else {\n workspaceByRegistry.set(key, [entry])\n }\n }\n\n // 2. Build entries from the registry, merging in any loaded workspace\n // counterparts. The registry's version order is preserved so the\n // \"first\" version on each entry is the latest one advertised.\n const grouped: SidebarDocumentItem[] = []\n const consumedRegistryKeys = new Set<string>()\n\n for (const doc of toValue(managedDocs)) {\n const key = registryKey(doc.namespace, doc.slug)\n consumedRegistryKeys.add(key)\n const loaded = workspaceByRegistry.get(key) ?? []\n const item = buildRegistryItem({ key, registry: doc, loaded, activeDocumentSlug })\n if (item) {\n grouped.push(item)\n }\n }\n\n // 3. Workspace docs that point at a registry coordinate the registry has\n // not advertised (yet) still need to appear in the sidebar so the user\n // is not stranded without an entry to click.\n for (const [key, loaded] of workspaceByRegistry) {\n if (consumedRegistryKeys.has(key)) {\n continue\n }\n const first = loaded[0]?.registry\n if (!first) {\n continue\n }\n const item = buildRegistryItem({\n key,\n registry: {\n namespace: first.namespace,\n slug: first.slug,\n title: loaded[0]?.title ?? first.slug,\n versions: [],\n },\n loaded,\n activeDocumentSlug,\n })\n if (item) {\n grouped.push(item)\n }\n }\n\n return [...grouped, ...standalone.map(toStandaloneItem)]\n })\n\n const pinned = computed(() => documents.value.filter((d) => d.isPinned))\n const rest = computed(() => documents.value.filter((d) => !d.isPinned))\n\n return { documents, pinned, rest }\n}\n\n/** Project a standalone (non-registry) workspace entry into a sidebar item. */\nconst toStandaloneItem = (entry: WorkspaceDocumentEntry): SidebarDocumentItem => ({\n key: entry.documentName,\n title: entry.title,\n documentName: entry.documentName,\n registry: undefined,\n navigation: entry.navigation,\n isPinned: entry.isPinned ?? false,\n})\n\n/**\n * Build a single registry-backed sidebar item. The version list is assembled\n * by walking the registry's advertised versions in order and pairing them\n * with any loaded workspace document that claims the same `version` string.\n * Loaded versions that the registry has not advertised are appended at the\n * end so they stay visible until the registry catches up.\n */\nconst buildRegistryItem = ({\n key,\n registry,\n loaded,\n activeDocumentSlug,\n}: {\n key: string\n registry: RegistryDocument\n loaded: WorkspaceDocumentEntry[]\n activeDocumentSlug: string | undefined\n}): SidebarDocumentItem | undefined => {\n // Index loaded workspace docs by the version they claim. A workspace doc\n // that does not declare a `version` is treated as an orphan and pushed to\n // the bottom of the version list — it still belongs to the group but we\n // cannot reconcile it with the registry.\n const loadedByVersion = new Map<string, WorkspaceDocumentEntry>()\n const orphans: WorkspaceDocumentEntry[] = []\n\n for (const entry of loaded) {\n const version = entry.registry?.version\n if (!version) {\n orphans.push(entry)\n continue\n }\n if (loadedByVersion.has(version)) {\n // Multiple workspace docs claim the same version; keep the first one\n // (registry order wins) and surface the rest as orphans so they remain\n // visible instead of silently disappearing.\n orphans.push(entry)\n continue\n }\n loadedByVersion.set(version, entry)\n }\n\n const versions: SidebarDocumentVersion[] = []\n\n // Registry-backed rows always surface the registry title so the sidebar\n // matches what the registry advertises. Local renames are intentionally\n // ignored here; the slug is the last-resort fallback so the row always has\n // something to render.\n const groupTitle = registry.title || registry.slug\n\n // Build the drafts list first: entries left in `loadedByVersion` after we\n // remove every version the registry advertises. The workspace store\n // preserves insertion order, so the newest draft is naturally last —\n // reverse it here to surface the most recently created draft first.\n const draftEntries: [string, WorkspaceDocumentEntry][] = []\n for (const [version, match] of loadedByVersion) {\n if (registry.versions.some((v) => v.version === version)) {\n continue\n }\n draftEntries.push([version, match])\n }\n draftEntries.reverse()\n\n // Drafts go on top: the user just created them and the registry has not\n // seen them yet, so they are the most relevant rows in the picker.\n // Drafts never carry the \"Latest\" badge — that label always belongs to\n // the latest registry-advertised version, regardless of row position.\n for (const [version, match] of draftEntries) {\n versions.push({\n key: match.documentName,\n version,\n title: groupTitle,\n documentName: match.documentName,\n commitHash: match.registry?.commitHash,\n registryCommitHash: undefined,\n status: computeVersionStatus({\n isLoaded: true,\n localHash: match.registry?.commitHash,\n registryHash: undefined,\n isDirty: match.isDirty,\n }),\n isLatest: false,\n navigation: match.navigation,\n })\n }\n\n // Then the registry-advertised versions, in the order the registry\n // returned them (latest first by convention). The first one is the\n // canonical \"latest\" — flagged here so the picker can render the badge\n // independent of row order in the array.\n registry.versions.forEach((v, registryIndex) => {\n const match = loadedByVersion.get(v.version)\n const localHash = match?.registry?.commitHash\n const registryHash = v.commitHash\n versions.push({\n key: match ? match.documentName : versionKey(registry.namespace, registry.slug, v.version),\n version: v.version,\n title: groupTitle,\n documentName: match?.documentName,\n commitHash: localHash,\n registryCommitHash: registryHash,\n status: computeVersionStatus({\n isLoaded: Boolean(match),\n localHash,\n registryHash,\n isDirty: match?.isDirty,\n conflictCheckedAgainstHash: match?.registry?.conflictCheckedAgainstHash,\n hasConflict: match?.registry?.hasConflict,\n }),\n isLatest: registryIndex === 0,\n navigation: match?.navigation,\n })\n })\n\n // Loaded docs that did not declare a version at all.\n for (const orphan of orphans) {\n versions.push({\n key: orphan.documentName,\n version: orphan.registry?.version ?? '',\n title: groupTitle,\n documentName: orphan.documentName,\n commitHash: orphan.registry?.commitHash,\n registryCommitHash: undefined,\n status: computeVersionStatus({\n isLoaded: true,\n localHash: orphan.registry?.commitHash,\n registryHash: undefined,\n isDirty: orphan.isDirty,\n }),\n isLatest: false,\n navigation: orphan.navigation,\n })\n }\n\n if (versions.length === 0) {\n return undefined\n }\n\n // Pick the active version: prefer a loaded match against the active\n // document slug, then any loaded version, then fall back to the first\n // version (the latest advertised by the registry).\n const activeVersion =\n versions.find((v) => v.documentName !== undefined && v.documentName === activeDocumentSlug) ??\n versions.find((v) => v.documentName !== undefined) ??\n versions[0]!\n\n return {\n key,\n title: groupTitle,\n documentName: activeVersion.documentName,\n registry: { namespace: registry.namespace, slug: registry.slug },\n navigation: activeVersion.navigation,\n isPinned: loaded.some((e) => e.isPinned),\n versions,\n activeVersionKey: activeVersion.key,\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { WorkspaceStore } from '@scalar/workspace-store/client';
|
|
2
|
+
import { type MaybeRefOrGetter } from 'vue';
|
|
3
|
+
import type { SidebarDocumentVersion } from '../../../../v2/features/app/hooks/use-sidebar-documents.js';
|
|
4
|
+
import type { ImportDocumentFromRegistry } from '../../../../v2/types/configuration';
|
|
5
|
+
/**
|
|
6
|
+
* Kicks off background `checkVersionConflict` calls for every loaded
|
|
7
|
+
* registry-backed version of the active document group whose status
|
|
8
|
+
* indicates a fresh three-way merge is needed.
|
|
9
|
+
*
|
|
10
|
+
* Scope is limited to the *active document group* on purpose: the breadcrumb
|
|
11
|
+
* only renders the picker for the document the user is currently viewing,
|
|
12
|
+
* so spending requests on versions outside that group would be wasted work.
|
|
13
|
+
* Within the active group, every loaded version is checked because the
|
|
14
|
+
* picker dropdown surfaces a status icon for each row — switching versions
|
|
15
|
+
* later should not block on a new request when the user opens the dropdown.
|
|
16
|
+
*
|
|
17
|
+
* The helper writes the result to `x-scalar-registry-meta` on the workspace
|
|
18
|
+
* document, which then flows back through `useSidebarDocuments` and updates
|
|
19
|
+
* the row icon. The in-memory `inflight` map guards against firing the same
|
|
20
|
+
* request twice while the cache write is still pending.
|
|
21
|
+
*/
|
|
22
|
+
export declare const useVersionConflictCheck: ({ store, fetcher, registry, versions, }: {
|
|
23
|
+
/** Workspace store the conflict result is cached on. */
|
|
24
|
+
store: MaybeRefOrGetter<WorkspaceStore | null>;
|
|
25
|
+
/** Registry fetcher used to pull the latest remote document for the merge. */
|
|
26
|
+
fetcher: MaybeRefOrGetter<ImportDocumentFromRegistry | undefined>;
|
|
27
|
+
/** Registry coordinates of the group these versions belong to. */
|
|
28
|
+
registry: MaybeRefOrGetter<{
|
|
29
|
+
namespace: string;
|
|
30
|
+
slug: string;
|
|
31
|
+
} | undefined>;
|
|
32
|
+
/** All versions of the active document group. */
|
|
33
|
+
versions: MaybeRefOrGetter<SidebarDocumentVersion[]>;
|
|
34
|
+
}) => void;
|
|
35
|
+
//# sourceMappingURL=use-version-conflict-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-version-conflict-check.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/app/hooks/use-version-conflict-check.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,KAAK,gBAAgB,EAAkB,MAAM,KAAK,CAAA;AAG3D,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAA;AAC3F,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAA;AAE1E;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,uBAAuB,GAAI,yCAKrC;IACD,wDAAwD;IACxD,KAAK,EAAE,gBAAgB,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;IAC9C,8EAA8E;IAC9E,OAAO,EAAE,gBAAgB,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAAA;IACjE,kEAAkE;IAClE,QAAQ,EAAE,gBAAgB,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC,CAAA;IAC3E,iDAAiD;IACjD,QAAQ,EAAE,gBAAgB,CAAC,sBAAsB,EAAE,CAAC,CAAA;CACrD,KAAG,IA0EH,CAAA"}
|