@lapis-notes/workspace 0.2.0 → 0.2.1

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # @lapis-notes/workspace
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#15](https://github.com/lapismd/lapis-notes/pull/15) [`57996c6`](https://github.com/lapismd/lapis-notes/commit/57996c6d26c1e7ed723df1291b415ee94d3a58e5) Thanks [@stevejuma](https://github.com/stevejuma)! - Retain selected plugin releases in navigation and persisted Plugins views so
8
+ application links can open a specific version. Fail closed for unavailable
9
+ versions and keep historical installation bound to the selected release.
10
+
3
11
  ## 0.2.0
4
12
 
5
13
  ### Minor Changes
@@ -94,7 +94,9 @@
94
94
  sidebarMaxWidth: 440,
95
95
  }),
96
96
  );
97
- let selectedVersion = $state<string>();
97
+ const selectedVersion = $derived(
98
+ navigation.route.page === "plugin" ? navigation.route.version : undefined,
99
+ );
98
100
  const resolved = $derived(
99
101
  selected && session.detail
100
102
  ? communityDetail(selected, session.detail)
@@ -128,12 +130,30 @@
128
130
  return { state: "rejected", reason: feedback.message };
129
131
  if (bundledIds.has(selected.id))
130
132
  return { state: "installed", label: "Bundled" };
131
- if (update?.canUpdate) return { state: "available", label: "Update" };
132
- if (installedIds.has(selected.id)) return { state: "installed" };
133
+ const installed = registry.installed.find(
134
+ (record) => record.pluginId === selected.id,
135
+ );
136
+ const requestedVersion = selectedVersion ?? selected.latestVersion;
137
+ if (installed?.installedVersion === requestedVersion)
138
+ return {
139
+ state: "installed",
140
+ installedVersion: installed.installedVersion,
141
+ };
142
+ if (update?.canUpdate && requestedVersion === selected.latestVersion)
143
+ return {
144
+ state: "available",
145
+ label: "Update",
146
+ installedVersion: installed?.installedVersion,
147
+ };
148
+ if (installed && requestedVersion === selected.latestVersion)
149
+ return {
150
+ state: "installed",
151
+ installedVersion: installed.installedVersion,
152
+ };
133
153
  const disabled = reason(selected);
134
154
  return disabled
135
155
  ? { state: "disabled", reason: disabled }
136
- : { state: "available" };
156
+ : { state: "available", installedVersion: installed?.installedVersion };
137
157
  });
138
158
  const downloads = (id: string) =>
139
159
  registry.downloadStats?.periods["30d"].plugins[id]?.total ?? 0;
@@ -171,7 +191,6 @@
171
191
  $effect(() => {
172
192
  if (selected && previousDetail !== selected.id) {
173
193
  previousDetail = selected.id;
174
- selectedVersion = undefined;
175
194
  void session.select(selected);
176
195
  }
177
196
  if (navigation.route.page !== "plugin") {
@@ -412,6 +431,19 @@
412
431
  onOpenPlugin={open}
413
432
  onOpenCategory={(category) => go("directory", category)}
414
433
  />
434
+ {:else if selected && resolved && selectedVersion !== undefined && !Object.hasOwn(resolved.detail.versions, selectedVersion)}<PluginRegistryContentState
435
+ kind="empty"
436
+ heading="Plugin version unavailable"
437
+ description={`Version ${selectedVersion} is not available from your enabled registry.`}
438
+ actionLabel="View latest release"
439
+ onaction={() => {
440
+ navigation.route = {
441
+ page: "plugin",
442
+ pluginId: selected.id,
443
+ };
444
+ persist();
445
+ }}
446
+ />
415
447
  {:else if selected && resolved}<PluginBrowserDetail
416
448
  {resolved}
417
449
  downloadSummary={registry.downloadStats
@@ -430,14 +462,23 @@
430
462
  ? changelogContent
431
463
  : undefined}
432
464
  onInstall={(request) =>
433
- update?.canUpdate
465
+ update?.canUpdate &&
466
+ request.version === update.targetVersion &&
467
+ request.version === selected.latestVersion
434
468
  ? registry.update(update)
435
469
  : registry.install(selected, request.version)}
436
470
  onOpenPlugin={open}
437
471
  onOpenCategory={(category) => go("directory", category)}
438
472
  onOpenPlatform={(platform) =>
439
473
  go("directory", undefined, platform)}
440
- onSelectVersion={(version) => (selectedVersion = version)}
474
+ onSelectVersion={(version) => {
475
+ navigation.route = {
476
+ page: "plugin",
477
+ pluginId: selected.id,
478
+ version,
479
+ };
480
+ persist();
481
+ }}
441
482
  />
442
483
  {:else if selected && session.loading}<PluginRegistryContentState
443
484
  kind="loading"
@@ -4,6 +4,7 @@ export type PluginBrowserRoute = {
4
4
  } | {
5
5
  page: "plugin";
6
6
  pluginId: string;
7
+ version?: string;
7
8
  };
8
9
  export interface PluginDirectoryState {
9
10
  query: string;
@@ -67,8 +67,17 @@ export function restoreBrowserState(value) {
67
67
  const routeValue = value.route;
68
68
  const route = routeValue?.page === "plugin" &&
69
69
  typeof routeValue.pluginId === "string" &&
70
- routeValue.pluginId.length > 0
71
- ? { page: "plugin", pluginId: routeValue.pluginId }
70
+ routeValue.pluginId.length > 0 &&
71
+ (routeValue.version === undefined ||
72
+ (typeof routeValue.version === "string" &&
73
+ /^[A-Za-z0-9][A-Za-z0-9.+-]{0,127}$/u.test(routeValue.version)))
74
+ ? {
75
+ page: "plugin",
76
+ pluginId: routeValue.pluginId,
77
+ ...(routeValue.version !== undefined
78
+ ? { version: routeValue.version }
79
+ : {}),
80
+ }
72
81
  : { page: routeValue?.page === "directory" ? "directory" : "landing" };
73
82
  const directory = defaultDirectoryState();
74
83
  const input = value.directory;
@@ -1,3 +1,3 @@
1
1
  import type { App } from "@lapis-notes/api";
2
2
  /** Reveal the registered singleton browser, preserving its workspace placement. */
3
- export declare function openPluginBrowser(app: App, pluginId?: string, isActive?: () => boolean): Promise<void>;
3
+ export declare function openPluginBrowser(app: App, pluginId?: string, isActive?: () => boolean, version?: string): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  import { PluginsView } from "./plugins-view.svelte";
2
2
  const pending = new WeakMap();
3
3
  /** Reveal the registered singleton browser, preserving its workspace placement. */
4
- export function openPluginBrowser(app, pluginId, isActive = () => true) {
4
+ export function openPluginBrowser(app, pluginId, isActive = () => true, version) {
5
5
  const previous = pending.get(app) ?? Promise.resolve();
6
6
  const next = previous
7
7
  .catch(() => { })
@@ -19,7 +19,9 @@ export function openPluginBrowser(app, pluginId, isActive = () => true) {
19
19
  return;
20
20
  if (!(leaf.view instanceof PluginsView))
21
21
  throw new Error("The Plugins view is not registered in this workspace.");
22
- if (pluginId)
22
+ if (pluginId && version !== undefined)
23
+ leaf.view.showPlugin(pluginId, version);
24
+ else if (pluginId)
23
25
  leaf.view.showPlugin(pluginId);
24
26
  else
25
27
  leaf.view.home();
@@ -15,6 +15,7 @@ export declare class PluginsView extends ItemView {
15
15
  } | {
16
16
  page: "plugin";
17
17
  pluginId: string;
18
+ version?: string;
18
19
  };
19
20
  directory: {
20
21
  query: string;
@@ -31,7 +32,7 @@ export declare class PluginsView extends ItemView {
31
32
  scrollTop: number;
32
33
  };
33
34
  setState(state: Record<string, unknown>): Promise<void>;
34
- showPlugin(pluginId: string): void;
35
+ showPlugin(pluginId: string, version?: string): void;
35
36
  home(): void;
36
37
  load(): void;
37
38
  unload(): void;
@@ -61,10 +61,14 @@ export class PluginsView extends ItemView {
61
61
  ? Math.max(0, state.scrollTop)
62
62
  : 0;
63
63
  }
64
- showPlugin(pluginId) {
64
+ showPlugin(pluginId, version) {
65
65
  if (this.navigation.route.page !== "plugin")
66
66
  this.navigation.returnPage = this.navigation.route.page;
67
- this.navigation.route = { page: "plugin", pluginId };
67
+ this.navigation.route = {
68
+ page: "plugin",
69
+ pluginId,
70
+ ...(version !== undefined ? { version } : {}),
71
+ };
68
72
  this.app.workspace.requestSaveLayout();
69
73
  }
70
74
  home() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lapis-notes/workspace",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Lapis Notes workspace shell backed by design-core",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {