@rightkit/document-workspace 0.0.0-stage → 0.1.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 +5 -0
- package/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +21 -0
- package/README.md +51 -2
- package/dist/app/App.d.ts +1 -0
- package/dist/app/App.js +6 -0
- package/dist/app/AppDialogs.d.ts +52 -0
- package/dist/app/AppDialogs.js +23 -0
- package/dist/app/AppDialogsHost.d.ts +31 -0
- package/dist/app/AppDialogsHost.js +30 -0
- package/dist/app/AppLifecycle.d.ts +19 -0
- package/dist/app/AppLifecycle.js +87 -0
- package/dist/app/AppProvider.d.ts +317 -0
- package/dist/app/AppProvider.js +217 -0
- package/dist/app/AppRoot.d.ts +8 -0
- package/dist/app/AppRoot.js +159 -0
- package/dist/app/AppShell.d.ts +2 -0
- package/dist/app/AppShell.js +81 -0
- package/dist/app/CommandPalette.d.ts +13 -0
- package/dist/app/CommandPalette.js +47 -0
- package/dist/app/DocActionBar.d.ts +36 -0
- package/dist/app/DocActionBar.js +300 -0
- package/dist/app/DocumentContextMenu.d.ts +29 -0
- package/dist/app/DocumentContextMenu.js +122 -0
- package/dist/app/DocumentPane.d.ts +52 -0
- package/dist/app/DocumentPane.js +30 -0
- package/dist/app/DocumentRouterTable.d.ts +58 -0
- package/dist/app/DocumentRouterTable.js +143 -0
- package/dist/app/ErrorBoundary.d.ts +12 -0
- package/dist/app/ErrorBoundary.js +16 -0
- package/dist/app/FindBar.d.ts +12 -0
- package/dist/app/FindBar.js +199 -0
- package/dist/app/LiveTitle.d.ts +14 -0
- package/dist/app/LiveTitle.js +14 -0
- package/dist/app/OpeningProgress.d.ts +13 -0
- package/dist/app/OpeningProgress.js +21 -0
- package/dist/app/PrintPreviewWindow.d.ts +2 -0
- package/dist/app/PrintPreviewWindow.js +57 -0
- package/dist/app/ShortcutHelp.d.ts +3 -0
- package/dist/app/ShortcutHelp.js +99 -0
- package/dist/app/Sidebar.d.ts +36 -0
- package/dist/app/Sidebar.js +121 -0
- package/dist/app/ToastViewport.d.ts +1 -0
- package/dist/app/ToastViewport.js +31 -0
- package/dist/app/Toolbar.d.ts +26 -0
- package/dist/app/Toolbar.js +63 -0
- package/dist/app/activeFormatSavers.d.ts +7 -0
- package/dist/app/activeFormatSavers.js +4 -0
- package/dist/app/clipboardPaths.d.ts +1 -0
- package/dist/app/clipboardPaths.js +31 -0
- package/dist/app/documentDrafts.d.ts +17 -0
- package/dist/app/documentDrafts.js +104 -0
- package/dist/app/draftResolution.d.ts +5 -0
- package/dist/app/draftResolution.js +25 -0
- package/dist/app/markdownPaletteActions.d.ts +8 -0
- package/dist/app/markdownPaletteActions.js +107 -0
- package/dist/app/resourceCensusDev.d.ts +41 -0
- package/dist/app/resourceCensusDev.js +518 -0
- package/dist/app/setupRecovery.d.ts +34 -0
- package/dist/app/setupRecovery.js +70 -0
- package/dist/app/shell/DocStatsPill.d.ts +18 -0
- package/dist/app/shell/DocStatsPill.js +32 -0
- package/dist/app/shell/DocumentTools.d.ts +9 -0
- package/dist/app/shell/DocumentTools.js +73 -0
- package/dist/app/shell/InfoInspector.d.ts +9 -0
- package/dist/app/shell/InfoInspector.js +67 -0
- package/dist/app/shell/StartPage.d.ts +9 -0
- package/dist/app/shell/StartPage.js +49 -0
- package/dist/app/shell/readEdit.d.ts +6 -0
- package/dist/app/shell/readEdit.js +6 -0
- package/dist/app/sidebar/SidebarDocumentMenu.d.ts +20 -0
- package/dist/app/sidebar/SidebarDocumentMenu.js +56 -0
- package/dist/app/sidebar/SidebarExpandedPanel.d.ts +9 -0
- package/dist/app/sidebar/SidebarExpandedPanel.js +78 -0
- package/dist/app/sidebar/SidebarIcons.d.ts +3 -0
- package/dist/app/sidebar/SidebarIcons.js +18 -0
- package/dist/app/sidebar/SidebarMenus.d.ts +19 -0
- package/dist/app/sidebar/SidebarMenus.js +64 -0
- package/dist/app/sidebar/SidebarPathUtils.d.ts +10 -0
- package/dist/app/sidebar/SidebarPathUtils.js +55 -0
- package/dist/app/sidebar/SidebarPrimitives.d.ts +12 -0
- package/dist/app/sidebar/SidebarPrimitives.js +45 -0
- package/dist/app/sidebar/SidebarRail.d.ts +5 -0
- package/dist/app/sidebar/SidebarRail.js +37 -0
- package/dist/app/sidebar/explorer/ExplorerRowMenu.d.ts +21 -0
- package/dist/app/sidebar/explorer/ExplorerRowMenu.js +37 -0
- package/dist/app/sidebar/explorer/ExplorerSections.d.ts +16 -0
- package/dist/app/sidebar/explorer/ExplorerSections.js +259 -0
- package/dist/app/sidebar/explorer/ExplorerTree.d.ts +46 -0
- package/dist/app/sidebar/explorer/ExplorerTree.js +387 -0
- package/dist/app/sidebar/explorer/explorerState.d.ts +37 -0
- package/dist/app/sidebar/explorer/explorerState.js +135 -0
- package/dist/app/tabMountPolicy.d.ts +45 -0
- package/dist/app/tabMountPolicy.js +104 -0
- package/dist/app/tabWarmOrder.d.ts +7 -0
- package/dist/app/tabWarmOrder.js +48 -0
- package/dist/app/tabs/TabFuseCurves.d.ts +3 -0
- package/dist/app/tabs/TabFuseCurves.js +15 -0
- package/dist/app/tabs/TabOverview.d.ts +24 -0
- package/dist/app/tabs/TabOverview.js +121 -0
- package/dist/app/tabs/TabStrip.d.ts +42 -0
- package/dist/app/tabs/TabStrip.js +380 -0
- package/dist/app/tabs/tabIds.d.ts +5 -0
- package/dist/app/tabs/tabIds.js +7 -0
- package/dist/app/tabs/useTabDirty.d.ts +3 -0
- package/dist/app/tabs/useTabDirty.js +11 -0
- package/dist/app/useAppChromeState.d.ts +21 -0
- package/dist/app/useAppChromeState.js +48 -0
- package/dist/app/useAppCommands.d.ts +66 -0
- package/dist/app/useAppCommands.js +71 -0
- package/dist/app/useAppDocumentCore.d.ts +210 -0
- package/dist/app/useAppDocumentCore.js +40 -0
- package/dist/app/useAppEffects.d.ts +18 -0
- package/dist/app/useAppEffects.js +52 -0
- package/dist/app/useAppPaneSearch.d.ts +37 -0
- package/dist/app/useAppPaneSearch.js +74 -0
- package/dist/app/useAppShellSetup.d.ts +40 -0
- package/dist/app/useAppShellSetup.js +52 -0
- package/dist/app/useAppSlots.d.ts +28 -0
- package/dist/app/useAppSlots.js +40 -0
- package/dist/app/useAppTabChrome.d.ts +51 -0
- package/dist/app/useAppTabChrome.js +66 -0
- package/dist/app/useAutoSave.d.ts +34 -0
- package/dist/app/useAutoSave.js +116 -0
- package/dist/app/useCloseAll.d.ts +52 -0
- package/dist/app/useCloseAll.js +295 -0
- package/dist/app/useClosedTabEviction.d.ts +10 -0
- package/dist/app/useClosedTabEviction.js +38 -0
- package/dist/app/useCommandPalette.d.ts +44 -0
- package/dist/app/useCommandPalette.js +254 -0
- package/dist/app/useCrossDocSearch.d.ts +7 -0
- package/dist/app/useCrossDocSearch.js +94 -0
- package/dist/app/useDistractionFree.d.ts +21 -0
- package/dist/app/useDistractionFree.js +73 -0
- package/dist/app/useDocumentCreation.d.ts +18 -0
- package/dist/app/useDocumentCreation.js +63 -0
- package/dist/app/useDocumentDirty.d.ts +31 -0
- package/dist/app/useDocumentDirty.js +46 -0
- package/dist/app/useDocumentLoader.d.ts +55 -0
- package/dist/app/useDocumentLoader.js +267 -0
- package/dist/app/useDocumentOutputActions.d.ts +6 -0
- package/dist/app/useDocumentOutputActions.js +45 -0
- package/dist/app/useDocumentRuntimeEffects.d.ts +36 -0
- package/dist/app/useDocumentRuntimeEffects.js +458 -0
- package/dist/app/useDocumentSaver.d.ts +58 -0
- package/dist/app/useDocumentSaver.js +511 -0
- package/dist/app/useDocumentTabs.d.ts +41 -0
- package/dist/app/useDocumentTabs.js +207 -0
- package/dist/app/useDocumentWatcher.d.ts +83 -0
- package/dist/app/useDocumentWatcher.js +393 -0
- package/dist/app/useDocumentZoom.d.ts +24 -0
- package/dist/app/useDocumentZoom.js +104 -0
- package/dist/app/useDocuments.d.ts +169 -0
- package/dist/app/useDocuments.js +455 -0
- package/dist/app/useDraftConfirmGate.d.ts +27 -0
- package/dist/app/useDraftConfirmGate.js +47 -0
- package/dist/app/useFileDragOverlay.d.ts +12 -0
- package/dist/app/useFileDragOverlay.js +49 -0
- package/dist/app/useFormatApis.d.ts +13 -0
- package/dist/app/useFormatApis.js +62 -0
- package/dist/app/useFormatDirtyState.d.ts +29 -0
- package/dist/app/useFormatDirtyState.js +81 -0
- package/dist/app/useGlobalShortcuts.d.ts +47 -0
- package/dist/app/useGlobalShortcuts.js +359 -0
- package/dist/app/useHtmlSession.d.ts +68 -0
- package/dist/app/useHtmlSession.js +463 -0
- package/dist/app/useHtmlSessionProps.d.ts +33 -0
- package/dist/app/useHtmlSessionProps.js +57 -0
- package/dist/app/useLibrary.d.ts +21 -0
- package/dist/app/useLibrary.js +81 -0
- package/dist/app/useOpenFromClipboard.d.ts +7 -0
- package/dist/app/useOpenFromClipboard.js +44 -0
- package/dist/app/usePaneLiveness.d.ts +29 -0
- package/dist/app/usePaneLiveness.js +199 -0
- package/dist/app/usePendingSavePaths.d.ts +19 -0
- package/dist/app/usePendingSavePaths.js +67 -0
- package/dist/app/useReadyShow.d.ts +12 -0
- package/dist/app/useReadyShow.js +142 -0
- package/dist/app/useSearchController.d.ts +22 -0
- package/dist/app/useSearchController.js +114 -0
- package/dist/app/useSetupRecovery.d.ts +41 -0
- package/dist/app/useSetupRecovery.js +153 -0
- package/dist/app/useTabChrome.d.ts +40 -0
- package/dist/app/useTabChrome.js +115 -0
- package/dist/app/useViewState.d.ts +27 -0
- package/dist/app/useViewState.js +160 -0
- package/dist/appName.d.ts +2 -0
- package/dist/appName.js +8 -0
- package/dist/documents/DocumentRouter.d.ts +102 -0
- package/dist/documents/DocumentRouter.js +153 -0
- package/dist/documents/FileTypeIcon.d.ts +6 -0
- package/dist/documents/FileTypeIcon.js +93 -0
- package/dist/documents/ImageDocument.d.ts +14 -0
- package/dist/documents/ImageDocument.js +61 -0
- package/dist/documents/capabilities.d.ts +17 -0
- package/dist/documents/capabilities.js +18 -0
- package/dist/documents/html/HtmlDocument.d.ts +15 -0
- package/dist/documents/html/HtmlDocument.js +584 -0
- package/dist/documents/html/HtmlDocumentLayout.d.ts +87 -0
- package/dist/documents/html/HtmlDocumentLayout.js +25 -0
- package/dist/documents/html/HtmlDocumentProps.d.ts +60 -0
- package/dist/documents/html/HtmlDocumentProps.js +1 -0
- package/dist/documents/html/HtmlDocumentSource.d.ts +34 -0
- package/dist/documents/html/HtmlDocumentSource.js +28 -0
- package/dist/documents/markdown/MarkdownSplitPane.d.ts +115 -0
- package/dist/documents/markdown/MarkdownSplitPane.js +352 -0
- package/dist/documents/mdx/MdxSplitPane.d.ts +32 -0
- package/dist/documents/mdx/MdxSplitPane.js +60 -0
- package/dist/documents/txt/LinkDialog.d.ts +8 -0
- package/dist/documents/txt/LinkDialog.js +34 -0
- package/dist/documents/txt/MarkdownSourceToolbar.d.ts +8 -0
- package/dist/documents/txt/MarkdownSourceToolbar.js +25 -0
- package/dist/documents/txt/SourceEditorToolbar.d.ts +12 -0
- package/dist/documents/txt/SourceEditorToolbar.js +4 -0
- package/dist/documents/txt/TxtEditor.d.ts +39 -0
- package/dist/documents/txt/TxtEditor.js +186 -0
- package/dist/documents/txt/sourceEditorTypes.d.ts +49 -0
- package/dist/documents/txt/sourceEditorTypes.js +1 -0
- package/dist/documents/txt/sourceExtensions.d.ts +38 -0
- package/dist/documents/txt/sourceExtensions.js +444 -0
- package/dist/documents/txt/sourceFormatting.d.ts +18 -0
- package/dist/documents/txt/sourceFormatting.js +183 -0
- package/dist/documents/txt/sourceTheme.d.ts +5 -0
- package/dist/documents/txt/sourceTheme.js +220 -0
- package/dist/documents/txt/useCodeMirrorSourceEditor.d.ts +69 -0
- package/dist/documents/txt/useCodeMirrorSourceEditor.js +546 -0
- package/dist/documents/txt/useSourceSearch.d.ts +39 -0
- package/dist/documents/txt/useSourceSearch.js +122 -0
- package/dist/documents/txt/useTextEditorCommands.d.ts +26 -0
- package/dist/documents/txt/useTextEditorCommands.js +151 -0
- package/dist/documents/web/LivePreviewPane.d.ts +11 -0
- package/dist/documents/web/LivePreviewPane.js +58 -0
- package/dist/env.d.ts +66 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +123 -0
- package/dist/settings/AppearanceMenu.d.ts +9 -0
- package/dist/settings/AppearanceMenu.js +54 -0
- package/dist/settings/SettingsPanel.d.ts +7 -0
- package/dist/settings/SettingsPanel.js +104 -0
- package/dist/settings/publishedSections.d.ts +22 -0
- package/dist/settings/publishedSections.js +79 -0
- package/dist/settings/sections/AboutSection.d.ts +1 -0
- package/dist/settings/sections/AboutSection.js +13 -0
- package/dist/settings/sections/DiagnosticsSection.d.ts +1 -0
- package/dist/settings/sections/DiagnosticsSection.js +42 -0
- package/dist/settings/sections/PrivacySection.d.ts +3 -0
- package/dist/settings/sections/PrivacySection.js +51 -0
- package/dist/settings/sections/UpdateLicenseBlock.d.ts +10 -0
- package/dist/settings/sections/UpdateLicenseBlock.js +158 -0
- package/dist/state/explorer.d.ts +32 -0
- package/dist/state/explorer.js +111 -0
- package/dist/state/legal.d.ts +51 -0
- package/dist/state/legal.js +130 -0
- package/dist/state/library.d.ts +33 -0
- package/dist/state/library.js +110 -0
- package/dist/state/updateLicense.d.ts +31 -0
- package/dist/state/updateLicense.js +340 -0
- package/dist/styles/explorer.css +219 -0
- package/dist/styles/index.css +1477 -0
- package/dist/styles/tabs.css +467 -0
- package/dist/styles.css +6 -0
- package/package.json +88 -3
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { browserQaLicenseClient, nativeIpc, openExternal } from "@rightkit/document-core/state/tauriBridge";
|
|
2
|
+
import { createLicenseClient } from "@rightkit/license";
|
|
3
|
+
import { createPersistedCheckCache, isNewerVersion as semverIsNewer, } from "@rightkit/app-update";
|
|
4
|
+
import { publicInstallerUrl as suitePublicInstallerUrl } from "@rightkit/app-update/suite-api";
|
|
5
|
+
import { UPDATE_MESSAGES, createNativeUpdateClient, } from "@rightkit/app-update/native";
|
|
6
|
+
import { isMac } from "@rightkit/document-core/platform";
|
|
7
|
+
import { logError } from "@rightkit/document-core/state/diagnostics";
|
|
8
|
+
import { hostAppName } from "../appName.js";
|
|
9
|
+
const FALLBACK_APP_VERSION = "0.0.0-dev";
|
|
10
|
+
export function resolvedAppVersion() {
|
|
11
|
+
const version = typeof __APP_VERSION__ === "string" ? __APP_VERSION__.trim() : "";
|
|
12
|
+
if (version)
|
|
13
|
+
return version;
|
|
14
|
+
const message = `${hostAppName()} build is missing __APP_VERSION__; release/update version truth is unavailable.`;
|
|
15
|
+
if (import.meta.env?.PROD) {
|
|
16
|
+
throw new Error(message);
|
|
17
|
+
}
|
|
18
|
+
console.warn(`${message} Using ${FALLBACK_APP_VERSION} for this non-production harness.`);
|
|
19
|
+
return FALLBACK_APP_VERSION;
|
|
20
|
+
}
|
|
21
|
+
export const APP_VERSION = resolvedAppVersion();
|
|
22
|
+
// Purchase CTA. /pricing is the real route (→ /checkout); /updates does not exist (was a 404).
|
|
23
|
+
export const UPDATE_LICENSE_URL = "https://viewright.cc/pricing/";
|
|
24
|
+
// The Right Suite app key: the owners (the native update host and @rightkit/app-update/suite-api)
|
|
25
|
+
// derive every host and URL from it, so this file names none.
|
|
26
|
+
const APP_KEY = "viewright";
|
|
27
|
+
// One-time purge of records the pre-cutover webview kept: the token-bearing licence and the
|
|
28
|
+
// device-id cache. Native code owns both now; nothing token-bearing may remain in web storage.
|
|
29
|
+
for (const legacyKey of ["vr.updateLicense.v1", "vr.deviceId.v1"]) {
|
|
30
|
+
try {
|
|
31
|
+
localStorage.removeItem(legacyKey);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
/* ignore */
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// ── Licence: the shell-owned native client. The webview holds no key, token, device id or
|
|
38
|
+
// record; it sends commands and receives validated LicenseView display values. ──
|
|
39
|
+
let licenseClientPromise = null;
|
|
40
|
+
export function getLicenseClient() {
|
|
41
|
+
licenseClientPromise ??= (async () => (await browserQaLicenseClient()) ?? createLicenseClient(nativeIpc))();
|
|
42
|
+
return licenseClientPromise;
|
|
43
|
+
}
|
|
44
|
+
// ── Updates: the shell-owned native update host. Check yields an opaque handle; download and
|
|
45
|
+
// install take that handle. authorization headers, tokens and licence binding stay native. ──
|
|
46
|
+
let nativeUpdates = null;
|
|
47
|
+
function updates() {
|
|
48
|
+
nativeUpdates ??= createNativeUpdateClient(nativeIpc);
|
|
49
|
+
return nativeUpdates;
|
|
50
|
+
}
|
|
51
|
+
/** Refusals that mean "this licence does not entitle the update" (nudge to the licence panel). */
|
|
52
|
+
const LICENSE_REFUSALS = new Set([
|
|
53
|
+
"notLicensed",
|
|
54
|
+
"expired",
|
|
55
|
+
"revoked",
|
|
56
|
+
"tierIneligible",
|
|
57
|
+
"disabledNoPublicPatch",
|
|
58
|
+
]);
|
|
59
|
+
let pendingUpdate = null;
|
|
60
|
+
let pendingExternalUpdateUrl = null;
|
|
61
|
+
function publicInstallerUrl() {
|
|
62
|
+
return suitePublicInstallerUrl(APP_KEY, isMac() ? "mac/current/Host_universal.dmg" : "windows/current/Host_x64-setup.exe");
|
|
63
|
+
}
|
|
64
|
+
export async function openPendingExternalUpdate() {
|
|
65
|
+
if (pendingExternalUpdateUrl)
|
|
66
|
+
await openExternal(pendingExternalUpdateUrl);
|
|
67
|
+
}
|
|
68
|
+
// ── Release status (app policy: manual-download fallback and the paid-update nudge). The shell's
|
|
69
|
+
// update host reads it natively (`rightkit_update_release_status`, https only, no redirect, closed
|
|
70
|
+
// shape); the webview holds no network capability. The platform filter is set natively. ──
|
|
71
|
+
function fetchCurrentReleaseStatus() {
|
|
72
|
+
return updates().releaseStatus();
|
|
73
|
+
}
|
|
74
|
+
async function latestProUpdateVersion() {
|
|
75
|
+
try {
|
|
76
|
+
const status = await fetchCurrentReleaseStatus();
|
|
77
|
+
return status.updateVersion && isNewerVersion(status.updateVersion, APP_VERSION)
|
|
78
|
+
? status.updateVersion
|
|
79
|
+
: null;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// ── Last-known-good update-check cache (@rightkit/app-update createPersistedCheckCache). A
|
|
86
|
+
// network hiccup after an earlier good check shows that result instead of "failed". Only
|
|
87
|
+
// results that need no process-local handle are persisted. ──
|
|
88
|
+
export const UPDATE_CHECK_CACHE_KEY = "vr.updateCheck.v3";
|
|
89
|
+
// A persisted result younger than this is served without a network round-trip.
|
|
90
|
+
const UPDATE_CHECK_DEBOUNCE_MS = 30_000;
|
|
91
|
+
const checkCacheStore = {
|
|
92
|
+
async read() {
|
|
93
|
+
try {
|
|
94
|
+
return localStorage.getItem(UPDATE_CHECK_CACHE_KEY);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
async write(text) {
|
|
101
|
+
localStorage.setItem(UPDATE_CHECK_CACHE_KEY, text);
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
const updateCheckCache = createPersistedCheckCache({
|
|
105
|
+
store: checkCacheStore,
|
|
106
|
+
minIntervalMs: UPDATE_CHECK_DEBOUNCE_MS,
|
|
107
|
+
// Also the write gate: a result that fails validation is returned but never persisted.
|
|
108
|
+
validate: (value) => {
|
|
109
|
+
const v = value;
|
|
110
|
+
return (typeof v === "object" &&
|
|
111
|
+
v !== null &&
|
|
112
|
+
(v.state === "current" || v.state === "available-external") &&
|
|
113
|
+
typeof v.version === "string");
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
function applyCached(cached, setLatestVersion, setUpdateState, setLatestTier) {
|
|
117
|
+
setLatestVersion(cached.version);
|
|
118
|
+
setLatestTier?.(cached.tier ?? null);
|
|
119
|
+
if (cached.state === "available-external")
|
|
120
|
+
pendingExternalUpdateUrl = publicInstallerUrl();
|
|
121
|
+
setUpdateState(cached.state);
|
|
122
|
+
}
|
|
123
|
+
async function resultFromCheck(view) {
|
|
124
|
+
if (!view.available) {
|
|
125
|
+
const nudge = await latestProUpdateVersion();
|
|
126
|
+
return nudge
|
|
127
|
+
? { state: "license-required", tier: "update", version: nudge }
|
|
128
|
+
: { state: "current", tier: null, version: APP_VERSION };
|
|
129
|
+
}
|
|
130
|
+
const tier = view.kind ?? null;
|
|
131
|
+
const version = view.version ?? "";
|
|
132
|
+
if (view.eligible && view.handleId) {
|
|
133
|
+
return { state: "available", tier, version, handleId: view.handleId };
|
|
134
|
+
}
|
|
135
|
+
if (view.refusal === "offline")
|
|
136
|
+
throw new Error("offline");
|
|
137
|
+
if (LICENSE_REFUSALS.has(view.refusal))
|
|
138
|
+
return { state: "license-required", tier, version };
|
|
139
|
+
return { state: "failed" };
|
|
140
|
+
}
|
|
141
|
+
// Step 1: check only, through the native update host.
|
|
142
|
+
export async function checkForUpdate(setLatestVersion, setUpdateState, setLatestTier) {
|
|
143
|
+
pendingUpdate = null;
|
|
144
|
+
pendingExternalUpdateUrl = null;
|
|
145
|
+
setUpdateState("checking");
|
|
146
|
+
let outcome;
|
|
147
|
+
try {
|
|
148
|
+
outcome = await updateCheckCache.run(async () => resultFromCheck(await updates().check()));
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return checkPublicReleaseFallback(setLatestVersion, setUpdateState, setLatestTier);
|
|
152
|
+
}
|
|
153
|
+
const result = outcome.value;
|
|
154
|
+
if (outcome.source === "last-known-good") {
|
|
155
|
+
if (result.state === "current") {
|
|
156
|
+
applyCached(result, setLatestVersion, setUpdateState, setLatestTier);
|
|
157
|
+
return "current";
|
|
158
|
+
}
|
|
159
|
+
return checkPublicReleaseFallback(setLatestVersion, setUpdateState, setLatestTier);
|
|
160
|
+
}
|
|
161
|
+
if (outcome.source === "cache" && (result.state === "current" || result.state === "available-external")) {
|
|
162
|
+
applyCached(result, setLatestVersion, setUpdateState, setLatestTier);
|
|
163
|
+
return result.state;
|
|
164
|
+
}
|
|
165
|
+
if (result.state === "available") {
|
|
166
|
+
setLatestVersion(result.version);
|
|
167
|
+
setLatestTier?.(result.tier);
|
|
168
|
+
pendingUpdate = { handleId: result.handleId, tier: result.tier };
|
|
169
|
+
setUpdateState("available");
|
|
170
|
+
return "available";
|
|
171
|
+
}
|
|
172
|
+
if (result.state === "license-required") {
|
|
173
|
+
setLatestVersion(result.version);
|
|
174
|
+
setLatestTier?.(result.tier);
|
|
175
|
+
setUpdateState("license-required");
|
|
176
|
+
return "license-required";
|
|
177
|
+
}
|
|
178
|
+
if (result.state === "current") {
|
|
179
|
+
setLatestTier?.(null);
|
|
180
|
+
setUpdateState("current");
|
|
181
|
+
return "current";
|
|
182
|
+
}
|
|
183
|
+
setUpdateState("failed");
|
|
184
|
+
return "failed";
|
|
185
|
+
}
|
|
186
|
+
async function checkPublicReleaseFallback(setLatestVersion, setUpdateState, setLatestTier) {
|
|
187
|
+
try {
|
|
188
|
+
const status = await fetchCurrentReleaseStatus();
|
|
189
|
+
const version = status.patchVersion?.trim() ?? "";
|
|
190
|
+
if (!version || !isNewerVersion(version, APP_VERSION)) {
|
|
191
|
+
if (status.updateVersion && isNewerVersion(status.updateVersion, APP_VERSION)) {
|
|
192
|
+
setLatestVersion(status.updateVersion);
|
|
193
|
+
setLatestTier?.("update");
|
|
194
|
+
setUpdateState("license-required");
|
|
195
|
+
return "license-required";
|
|
196
|
+
}
|
|
197
|
+
setUpdateState("current");
|
|
198
|
+
return "current";
|
|
199
|
+
}
|
|
200
|
+
pendingExternalUpdateUrl = publicInstallerUrl();
|
|
201
|
+
setLatestVersion(version);
|
|
202
|
+
setLatestTier?.(null);
|
|
203
|
+
setUpdateState("available-external");
|
|
204
|
+
await updateCheckCache.run(async () => ({ state: "available-external", tier: null, version }), { force: true });
|
|
205
|
+
return "available-external";
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
setUpdateState("failed");
|
|
209
|
+
return "failed";
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async function relaunchAfterInstall() {
|
|
213
|
+
try {
|
|
214
|
+
const { relaunch } = await import("@tauri-apps/plugin-process");
|
|
215
|
+
await relaunch();
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
/* the host may already be restarting; the install itself succeeded */
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Step 2: explicit download + install of the update found by checkForUpdate(), then relaunch.
|
|
222
|
+
export async function installPendingUpdate(setUpdateState, setInstallError) {
|
|
223
|
+
if (!pendingUpdate)
|
|
224
|
+
return "idle";
|
|
225
|
+
const { handleId, tier } = pendingUpdate;
|
|
226
|
+
pendingUpdate = null;
|
|
227
|
+
setUpdateState("installing");
|
|
228
|
+
let failure = UPDATE_MESSAGES.updateFailed;
|
|
229
|
+
try {
|
|
230
|
+
const downloaded = await updates().download(handleId);
|
|
231
|
+
if (downloaded.state === "downloaded") {
|
|
232
|
+
const installed = await updates().install(handleId);
|
|
233
|
+
if (installed.state === "installing") {
|
|
234
|
+
await relaunchAfterInstall();
|
|
235
|
+
return "installing";
|
|
236
|
+
}
|
|
237
|
+
if (installed.state === "refused" && installed.reason && LICENSE_REFUSALS.has(installed.reason)) {
|
|
238
|
+
setUpdateState("license-required");
|
|
239
|
+
return "license-required";
|
|
240
|
+
}
|
|
241
|
+
failure = UPDATE_MESSAGES[installed.message] || failure;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
if (downloaded.state === "refused" && downloaded.reason && LICENSE_REFUSALS.has(downloaded.reason)) {
|
|
245
|
+
setUpdateState("license-required");
|
|
246
|
+
return "license-required";
|
|
247
|
+
}
|
|
248
|
+
failure = UPDATE_MESSAGES[downloaded.message] || failure;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
// NativeUpdateClientError text is a fixed, closed message; native detail never crosses IPC.
|
|
253
|
+
if (error instanceof Error && error.message)
|
|
254
|
+
failure = error.message;
|
|
255
|
+
}
|
|
256
|
+
// Surface the failure two ways: setInstallError feeds the UI (ephemeral) and logError lands it as
|
|
257
|
+
// renderer_error in the diagnostics export (durable). On a patch, also stage the public installer
|
|
258
|
+
// URL so the user can recover via a manual download.
|
|
259
|
+
if (tier === "patch")
|
|
260
|
+
pendingExternalUpdateUrl = publicInstallerUrl();
|
|
261
|
+
setInstallError?.(failure);
|
|
262
|
+
logError("update:install-failed");
|
|
263
|
+
setUpdateState("install-failed");
|
|
264
|
+
return "install-failed";
|
|
265
|
+
}
|
|
266
|
+
/** True while a manual-download installer URL is staged (public fallback or failed patch install). */
|
|
267
|
+
export function hasPendingExternalUpdate() {
|
|
268
|
+
return pendingExternalUpdateUrl !== null;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* the host app update flow as the function-style client `@rightkit/settings-ui` `updatesSection`
|
|
272
|
+
* expects (`UpdatesAdapter`): check()/install() resolve to an `AutoUpdateStatus`. The explicit
|
|
273
|
+
* check -> install split, the last-known-good cache and the public-release fallback stay in
|
|
274
|
+
* checkForUpdate()/installPendingUpdate(); this only maps their UpdateState into the shared status.
|
|
275
|
+
* `onChange` fires after each call so UI outside the section can re-read hasPendingExternalUpdate().
|
|
276
|
+
*/
|
|
277
|
+
export function createHostUpdatesAdapter(onChange) {
|
|
278
|
+
let version = "";
|
|
279
|
+
let tier = null;
|
|
280
|
+
const toStatus = (state, error = "") => {
|
|
281
|
+
switch (state) {
|
|
282
|
+
case "current":
|
|
283
|
+
return { kind: "up_to_date" };
|
|
284
|
+
case "available":
|
|
285
|
+
return { kind: "available", version, tier, eligible: true };
|
|
286
|
+
case "license-required":
|
|
287
|
+
return { kind: "available", version, tier, eligible: false, reason: "pro_required" };
|
|
288
|
+
case "available-external":
|
|
289
|
+
return { kind: "deferred", version, tier: null, reason: "manual_download" };
|
|
290
|
+
case "installing":
|
|
291
|
+
return { kind: "ready", version, tier };
|
|
292
|
+
case "install-failed":
|
|
293
|
+
return { kind: "error", message: error || "The updater could not finish installing this release." };
|
|
294
|
+
case "failed":
|
|
295
|
+
return { kind: "error", message: "Couldn't check releases." };
|
|
296
|
+
default:
|
|
297
|
+
return { kind: "idle" };
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
return {
|
|
301
|
+
async check() {
|
|
302
|
+
try {
|
|
303
|
+
const state = await checkForUpdate((v) => (version = v), () => { }, (t) => (tier = t));
|
|
304
|
+
return toStatus(state);
|
|
305
|
+
}
|
|
306
|
+
finally {
|
|
307
|
+
onChange?.();
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
async install() {
|
|
311
|
+
let error = "";
|
|
312
|
+
try {
|
|
313
|
+
const state = await installPendingUpdate(() => { }, (m) => (error = m));
|
|
314
|
+
return state === "idle"
|
|
315
|
+
? { kind: "error", message: "No update is ready to install. Check for updates first." }
|
|
316
|
+
: toStatus(state, error);
|
|
317
|
+
}
|
|
318
|
+
finally {
|
|
319
|
+
onChange?.();
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
/** Startup check through the native host. The host reads the licence record, so a paid update is
|
|
325
|
+
* announced for a licensed user; a failure is advisory and returns null. */
|
|
326
|
+
export async function checkForBackgroundUpdate() {
|
|
327
|
+
const view = await updates().check();
|
|
328
|
+
return view.available && view.eligible && view.version
|
|
329
|
+
? { version: view.version, tier: view.kind ?? null }
|
|
330
|
+
: null;
|
|
331
|
+
}
|
|
332
|
+
/** Package semver compare, but an unparseable version never counts as newer (it throws on garbage). */
|
|
333
|
+
function isNewerVersion(candidate, current) {
|
|
334
|
+
try {
|
|
335
|
+
return semverIsNewer(candidate, current);
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/* Explorer sidebar (src/app/sidebar/explorer/) — collapsible sections, lazy tree rows, ellipsis
|
|
2
|
+
context menus. Rendered inside the sidebar's .vr-chrome scope, so the shared tokens already map
|
|
3
|
+
to the CHROME palette (index.css .vr-chrome: --ink = --chrome-hover, --panel-2 = --chrome-2,
|
|
4
|
+
--muted = --chrome-muted, --line = --chrome-line, --paper = --chrome-paper; --copper = accent).
|
|
5
|
+
Visual reference: docs/design/viewright-tabs-explorer.html (.sec/.sec-h/.tree/.row). */
|
|
6
|
+
|
|
7
|
+
.vr-explorer {
|
|
8
|
+
padding: 2px 6px 12px 4px;
|
|
9
|
+
white-space: nowrap;
|
|
10
|
+
font-size: var(--vr-text-sm);
|
|
11
|
+
line-height: 1.35;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* ── Section header (mockup .sec-h: 10.5px, uppercase, tracked) ───────────── */
|
|
15
|
+
.vr-x-sec {
|
|
16
|
+
margin-top: 10px;
|
|
17
|
+
}
|
|
18
|
+
.vr-x-sec-h {
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: 4px;
|
|
22
|
+
width: 100%;
|
|
23
|
+
padding: 4px 6px;
|
|
24
|
+
border: 0;
|
|
25
|
+
border-radius: 6px;
|
|
26
|
+
background: none;
|
|
27
|
+
font-size: var(--vr-text-xs);
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
letter-spacing: 0.09em;
|
|
30
|
+
text-transform: uppercase;
|
|
31
|
+
color: var(--muted);
|
|
32
|
+
text-align: left;
|
|
33
|
+
cursor: default;
|
|
34
|
+
}
|
|
35
|
+
.vr-x-sec-h:hover {
|
|
36
|
+
color: var(--paper);
|
|
37
|
+
}
|
|
38
|
+
.vr-x-sec-h:focus-visible {
|
|
39
|
+
outline: none;
|
|
40
|
+
box-shadow: 0 0 0 2px var(--copper);
|
|
41
|
+
}
|
|
42
|
+
.vr-x-sec-caret {
|
|
43
|
+
flex: none;
|
|
44
|
+
color: var(--muted);
|
|
45
|
+
transition: transform 0.15s ease;
|
|
46
|
+
}
|
|
47
|
+
.vr-x-sec.closed .vr-x-sec-caret {
|
|
48
|
+
transform: rotate(-90deg);
|
|
49
|
+
}
|
|
50
|
+
.vr-x-sec-count {
|
|
51
|
+
flex: none;
|
|
52
|
+
margin-left: auto;
|
|
53
|
+
padding: 0 6px;
|
|
54
|
+
border-radius: 999px;
|
|
55
|
+
background: var(--panel-2);
|
|
56
|
+
color: var(--muted);
|
|
57
|
+
font-size: var(--vr-text-xs);
|
|
58
|
+
font-weight: 600;
|
|
59
|
+
letter-spacing: 0;
|
|
60
|
+
}
|
|
61
|
+
.vr-x-sec.closed .vr-x-sec-b {
|
|
62
|
+
display: none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ── Rows (mockup .row): one height for tree rows and leaf rows alike ─────── */
|
|
66
|
+
.vr-x-row {
|
|
67
|
+
position: relative;
|
|
68
|
+
display: flex;
|
|
69
|
+
align-items: center;
|
|
70
|
+
gap: 6px;
|
|
71
|
+
width: 100%;
|
|
72
|
+
height: 26px;
|
|
73
|
+
padding: 0 6px;
|
|
74
|
+
border: 0;
|
|
75
|
+
border-radius: 7px;
|
|
76
|
+
background: none;
|
|
77
|
+
font-size: var(--vr-text-sm);
|
|
78
|
+
color: var(--paper);
|
|
79
|
+
text-align: left;
|
|
80
|
+
cursor: default;
|
|
81
|
+
}
|
|
82
|
+
.vr-x-row:hover {
|
|
83
|
+
background: color-mix(in srgb, var(--ink) 55%, transparent);
|
|
84
|
+
}
|
|
85
|
+
/* Current file: quiet chromeHover fill + semibold, held even without tree focus (mockup .row.sel). */
|
|
86
|
+
.vr-x-row[aria-selected="true"],
|
|
87
|
+
.vr-x-row.vr-x-sel,
|
|
88
|
+
.vr-x-row[aria-current="true"] {
|
|
89
|
+
background: var(--ink);
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
}
|
|
92
|
+
.vr-x-row:focus-visible {
|
|
93
|
+
outline: none;
|
|
94
|
+
box-shadow: 0 0 0 2px var(--copper);
|
|
95
|
+
}
|
|
96
|
+
/* Unsupported files: real path but no broker grant — dimmed, inert. */
|
|
97
|
+
.vr-x-row.vr-x-dim {
|
|
98
|
+
opacity: 0.5;
|
|
99
|
+
}
|
|
100
|
+
/* .vr-x-lrow kept as the leaf-row marker; heights are uniform now. */
|
|
101
|
+
|
|
102
|
+
.vr-x-caret {
|
|
103
|
+
width: 12px;
|
|
104
|
+
flex: none;
|
|
105
|
+
display: inline-flex;
|
|
106
|
+
align-items: center;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
color: var(--muted);
|
|
109
|
+
}
|
|
110
|
+
.vr-x-icn {
|
|
111
|
+
flex: none;
|
|
112
|
+
width: 16px;
|
|
113
|
+
display: inline-flex;
|
|
114
|
+
align-items: center;
|
|
115
|
+
justify-content: center;
|
|
116
|
+
color: var(--muted);
|
|
117
|
+
}
|
|
118
|
+
.vr-x-name {
|
|
119
|
+
flex: 1;
|
|
120
|
+
min-width: 0;
|
|
121
|
+
overflow: hidden;
|
|
122
|
+
text-overflow: ellipsis;
|
|
123
|
+
}
|
|
124
|
+
/* "In a tab" indicator for files that are already open (not the active one). */
|
|
125
|
+
.vr-x-open {
|
|
126
|
+
flex: none;
|
|
127
|
+
width: 6px;
|
|
128
|
+
height: 6px;
|
|
129
|
+
box-sizing: border-box;
|
|
130
|
+
border-radius: 50%;
|
|
131
|
+
border: 1.5px solid var(--muted);
|
|
132
|
+
background: transparent;
|
|
133
|
+
}
|
|
134
|
+
/* Hover "…" action (mockup .row .dots): overlays the row end on hover/focus only. */
|
|
135
|
+
.vr-x-dots {
|
|
136
|
+
position: absolute;
|
|
137
|
+
right: 4px;
|
|
138
|
+
top: 50%;
|
|
139
|
+
transform: translateY(-50%);
|
|
140
|
+
display: none;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: center;
|
|
143
|
+
width: 20px;
|
|
144
|
+
height: 18px;
|
|
145
|
+
padding: 0;
|
|
146
|
+
border: 0;
|
|
147
|
+
border-radius: 5px;
|
|
148
|
+
background: var(--panel-2);
|
|
149
|
+
color: var(--muted);
|
|
150
|
+
}
|
|
151
|
+
.vr-x-row:hover .vr-x-dots,
|
|
152
|
+
.vr-x-row:focus-within .vr-x-dots {
|
|
153
|
+
display: inline-flex;
|
|
154
|
+
}
|
|
155
|
+
.vr-x-dots:hover {
|
|
156
|
+
color: var(--paper);
|
|
157
|
+
}
|
|
158
|
+
.vr-x-dots:focus-visible {
|
|
159
|
+
outline: none;
|
|
160
|
+
box-shadow: 0 0 0 2px var(--copper);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* ── Quiet lines (empty sections/folders, notes, truncation, "show more") ─── */
|
|
164
|
+
.vr-x-empty {
|
|
165
|
+
padding: 3px 8px 3px 24px;
|
|
166
|
+
font-size: var(--vr-text-sm);
|
|
167
|
+
color: var(--muted);
|
|
168
|
+
}
|
|
169
|
+
/* Permission/inline errors get real message text and may wrap. */
|
|
170
|
+
.vr-x-note {
|
|
171
|
+
padding: 4px 8px 4px 24px;
|
|
172
|
+
font-size: var(--vr-text-sm);
|
|
173
|
+
line-height: 1.45;
|
|
174
|
+
color: var(--muted);
|
|
175
|
+
white-space: normal;
|
|
176
|
+
}
|
|
177
|
+
.vr-x-more {
|
|
178
|
+
display: block;
|
|
179
|
+
width: 100%;
|
|
180
|
+
padding: 3px 8px 3px 24px;
|
|
181
|
+
border: 0;
|
|
182
|
+
background: none;
|
|
183
|
+
font-size: var(--vr-text-sm);
|
|
184
|
+
color: var(--muted);
|
|
185
|
+
text-align: left;
|
|
186
|
+
cursor: default;
|
|
187
|
+
}
|
|
188
|
+
.vr-x-more:hover {
|
|
189
|
+
color: var(--paper);
|
|
190
|
+
}
|
|
191
|
+
.vr-x-more:focus-visible {
|
|
192
|
+
outline: none;
|
|
193
|
+
box-shadow: 0 0 0 2px var(--copper);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* ── Slim action row under the sidebar titlebar (mockup .s-actions) ────────── */
|
|
197
|
+
.vr-x-actions {
|
|
198
|
+
display: flex;
|
|
199
|
+
align-items: center;
|
|
200
|
+
gap: 4px;
|
|
201
|
+
padding: 0 10px 4px;
|
|
202
|
+
}
|
|
203
|
+
.vr-x-new {
|
|
204
|
+
display: inline-flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
gap: 4px;
|
|
207
|
+
height: 24px;
|
|
208
|
+
padding: 0 10px;
|
|
209
|
+
border: 0.5px solid var(--line);
|
|
210
|
+
border-radius: 999px;
|
|
211
|
+
background: var(--panel-2);
|
|
212
|
+
color: var(--paper);
|
|
213
|
+
font-size: var(--vr-text-sm);
|
|
214
|
+
font-weight: 600;
|
|
215
|
+
cursor: default;
|
|
216
|
+
}
|
|
217
|
+
.vr-x-new:hover {
|
|
218
|
+
border-color: var(--muted);
|
|
219
|
+
}
|