@trops/dash-core 0.1.356 → 0.1.358

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.
@@ -650,6 +650,9 @@ function requireDashboardConfigEvents () {
650
650
  const DASHBOARD_CONFIG_PUBLISH_PREVIEW = "dashboard-config-publish-preview";
651
651
  const DASHBOARD_CONFIG_SELECT_FILE = "dashboard-config-select-file";
652
652
  const DASHBOARD_CONFIG_INSTALL_PROGRESS = "dashboard-config-install-progress";
653
+ const DASHBOARD_CONFIG_COLLECT_DEPENDENCIES =
654
+ "dashboard-config-collect-dependencies";
655
+ const DASHBOARD_CONFIG_PUBLISH_PLAN = "dashboard-config-publish-plan";
653
656
 
654
657
  dashboardConfigEvents$1 = {
655
658
  DASHBOARD_CONFIG_EXPORT,
@@ -663,6 +666,8 @@ function requireDashboardConfigEvents () {
663
666
  DASHBOARD_CONFIG_PUBLISH_PREVIEW,
664
667
  DASHBOARD_CONFIG_SELECT_FILE,
665
668
  DASHBOARD_CONFIG_INSTALL_PROGRESS,
669
+ DASHBOARD_CONFIG_COLLECT_DEPENDENCIES,
670
+ DASHBOARD_CONFIG_PUBLISH_PLAN,
666
671
  };
667
672
  return dashboardConfigEvents$1;
668
673
  }
@@ -62999,8 +63004,34 @@ function checkApiCompatibility(providers = [], appCapabilities = []) {
62999
63004
  };
63000
63005
  }
63001
63006
 
63007
+ /**
63008
+ * Collect unique component names across a workspace's main layout, every
63009
+ * page layout, and the sidebar layout. Matches what a user actually sees
63010
+ * on screen — `collectComponentNames` only walks a single layout array
63011
+ * and misses widgets placed on non-active pages or in the sidebar.
63012
+ *
63013
+ * @param {Object} workspace - Workspace object ({layout, pages, sidebarLayout})
63014
+ * @returns {string[]} Unique component names
63015
+ */
63016
+ function collectComponentNamesFromWorkspace$1(workspace) {
63017
+ const names = new Set();
63018
+ const pushAll = (layout) => {
63019
+ if (!Array.isArray(layout)) return;
63020
+ for (const n of collectComponentNames$1(layout)) names.add(n);
63021
+ };
63022
+
63023
+ pushAll(workspace?.layout);
63024
+ pushAll(workspace?.sidebarLayout);
63025
+ if (Array.isArray(workspace?.pages)) {
63026
+ for (const page of workspace.pages) pushAll(page?.layout);
63027
+ }
63028
+
63029
+ return Array.from(names);
63030
+ }
63031
+
63002
63032
  var dashboardConfigUtils$1 = {
63003
63033
  collectComponentNames: collectComponentNames$1,
63034
+ collectComponentNamesFromWorkspace: collectComponentNamesFromWorkspace$1,
63004
63035
  extractEventWiring: extractEventWiring$1,
63005
63036
  buildWidgetDependencies: buildWidgetDependencies$1,
63006
63037
  buildProviderRequirements: buildProviderRequirements$1,
@@ -63094,6 +63125,55 @@ async function publishToRegistry$1(zipPath, manifest) {
63094
63125
  }
63095
63126
  }
63096
63127
 
63128
+ /**
63129
+ * Bulk-resolve package refs to their registry state. Used by the
63130
+ * batch-publish dialog to decorate dependency rows with ownership +
63131
+ * latest version + visibility.
63132
+ *
63133
+ * Sends token if available (authenticated callers see their private
63134
+ * packages too). Anonymous calls still work — only public data is
63135
+ * returned.
63136
+ *
63137
+ * @param {Array<{scope: string, name: string}>} refs
63138
+ * @returns {Promise<Object>} { success, resolved: [...], error? }
63139
+ */
63140
+ async function resolvePackages(refs) {
63141
+ if (!Array.isArray(refs) || refs.length === 0) {
63142
+ return { success: true, resolved: [] };
63143
+ }
63144
+
63145
+ try {
63146
+ const headers = { "Content-Type": "application/json" };
63147
+ const auth = getStoredToken$2();
63148
+ if (auth?.token) {
63149
+ headers.Authorization = `Bearer ${auth.token}`;
63150
+ }
63151
+
63152
+ const response = await fetch(`${REGISTRY_BASE_URL}/api/packages/resolve`, {
63153
+ method: "POST",
63154
+ headers,
63155
+ body: JSON.stringify({ refs }),
63156
+ });
63157
+
63158
+ const data = await response.json().catch(() => null);
63159
+
63160
+ if (!response.ok) {
63161
+ return {
63162
+ success: false,
63163
+ error: data?.error || `Resolve failed: ${response.status}`,
63164
+ };
63165
+ }
63166
+
63167
+ return { success: true, resolved: Array.isArray(data) ? data : [] };
63168
+ } catch (err) {
63169
+ console.error("[RegistryApiController] Resolve error:", err);
63170
+ return {
63171
+ success: false,
63172
+ error: err.message || "Failed to resolve packages",
63173
+ };
63174
+ }
63175
+ }
63176
+
63097
63177
  /**
63098
63178
  * Get the registry URL for a published package.
63099
63179
  *
@@ -63107,6 +63187,7 @@ function getRegistryUrl$1(scope, name) {
63107
63187
 
63108
63188
  var registryApiController$2 = {
63109
63189
  publishToRegistry: publishToRegistry$1,
63190
+ resolvePackages,
63110
63191
  getRegistryUrl: getRegistryUrl$1,
63111
63192
  REGISTRY_BASE_URL,
63112
63193
  };
@@ -63700,6 +63781,7 @@ const {
63700
63781
  } = dashboardConfigValidator$1;
63701
63782
  const {
63702
63783
  collectComponentNames,
63784
+ collectComponentNamesFromWorkspace,
63703
63785
  extractEventWiring,
63704
63786
  buildWidgetDependencies,
63705
63787
  buildProviderRequirements,
@@ -64711,6 +64793,214 @@ async function checkCompatibility$1(dashboardWidgets, widgetRegistry = null) {
64711
64793
  );
64712
64794
  }
64713
64795
 
64796
+ /**
64797
+ * Collect enriched dependency info for a workspace — widgets + theme.
64798
+ *
64799
+ * Read-only. Used by the batch-publish dialog to build its dependency
64800
+ * table. Resolves local state (scope, name, version from each widget's
64801
+ * package.json, and packageDir for later zipping). Does NOT query the
64802
+ * registry — that's the caller's job (see registry resolve endpoint).
64803
+ *
64804
+ * @param {string} appId - Application identifier
64805
+ * @param {number|string} workspaceId - Workspace ID
64806
+ * @param {Object} widgetRegistry - WidgetRegistry instance
64807
+ * @param {Object} options - { componentConfigs?: Object }
64808
+ * @returns {Promise<Object>} { success, widgets, theme }
64809
+ */
64810
+ async function collectDashboardDependencies$1(
64811
+ appId,
64812
+ workspaceId,
64813
+ widgetRegistry = null,
64814
+ options = {},
64815
+ ) {
64816
+ try {
64817
+ // 1. Read workspace
64818
+ const filename = path$1.join(
64819
+ app$1.getPath("userData"),
64820
+ appName$1,
64821
+ appId,
64822
+ configFilename,
64823
+ );
64824
+ const workspacesArray = getFileContents$1(filename);
64825
+ const workspace = workspacesArray.find(
64826
+ (w) => w.id === workspaceId || w.id === Number(workspaceId),
64827
+ );
64828
+
64829
+ if (!workspace) {
64830
+ return {
64831
+ success: false,
64832
+ error: `Workspace not found: ${workspaceId}`,
64833
+ };
64834
+ }
64835
+
64836
+ // 2. Collect component names from main + pages + sidebar layouts
64837
+ const componentNames = collectComponentNamesFromWorkspace(workspace);
64838
+
64839
+ // 3. Resolve widget refs (scope, packageName, widgetName, version)
64840
+ const deps = buildWidgetDependencies(
64841
+ componentNames,
64842
+ widgetRegistry,
64843
+ options.componentConfigs || null,
64844
+ );
64845
+
64846
+ // 4. Enrich with packageDir + componentNames-in-package (from registry)
64847
+ // so the caller can zip and publish each widget.
64848
+ const installedWidgets = widgetRegistry ? widgetRegistry.getWidgets() : [];
64849
+
64850
+ const widgets = deps.map((dep) => {
64851
+ // Find the installed widget whose componentNames contains this dep's widgetName
64852
+ const match = installedWidgets.find(
64853
+ (w) =>
64854
+ (w.componentNames && w.componentNames.includes(dep.widgetName)) ||
64855
+ (w.scope === dep.scope &&
64856
+ (w.name === dep.packageName ||
64857
+ w.packageId === `${dep.scope}/${dep.packageName}`)),
64858
+ );
64859
+
64860
+ return {
64861
+ scope: dep.scope || null,
64862
+ packageName: dep.packageName,
64863
+ widgetName: dep.widgetName,
64864
+ component: dep.widgetName,
64865
+ localVersion: dep.version,
64866
+ packageDir: match?.path || null,
64867
+ packageId: match?.packageId || null,
64868
+ author: dep.author || "",
64869
+ hasLocalPackage: !!match?.path,
64870
+ };
64871
+ });
64872
+
64873
+ // 5. Resolve theme (if workspace has one)
64874
+ let theme = null;
64875
+ if (workspace.themeKey) {
64876
+ try {
64877
+ const themeResult = themeController$2.listThemesForApplication(
64878
+ null,
64879
+ appId,
64880
+ );
64881
+ const themeData = themeResult?.themes?.[workspace.themeKey];
64882
+ if (themeData) {
64883
+ const registryMeta = themeData._registryMeta || {};
64884
+ theme = {
64885
+ themeKey: workspace.themeKey,
64886
+ scope: registryMeta.scope || null,
64887
+ name: registryMeta.name || workspace.themeKey,
64888
+ localVersion: registryMeta.version || null,
64889
+ hasRegistryMeta: !!themeData._registryMeta,
64890
+ };
64891
+ }
64892
+ } catch (err) {
64893
+ console.warn(
64894
+ "[dashboardConfig] Could not resolve theme for dependencies:",
64895
+ err.message,
64896
+ );
64897
+ }
64898
+ }
64899
+
64900
+ return { success: true, widgets, theme };
64901
+ } catch (error) {
64902
+ console.error(
64903
+ "[dashboardConfig] collectDashboardDependencies failed:",
64904
+ error,
64905
+ );
64906
+ return { success: false, error: error.message };
64907
+ }
64908
+ }
64909
+
64910
+ /**
64911
+ * Build an enriched dependency plan for batch-publishing a dashboard.
64912
+ *
64913
+ * Combines local dependency info (collectDashboardDependencies) with the
64914
+ * registry's current state (POST /api/packages/resolve) so the batch-
64915
+ * publish UI can decorate each widget + theme row with "already in
64916
+ * registry at vX.Y.Z", "owned by you", "public/private", etc.
64917
+ *
64918
+ * Each returned widget has a `registry` sub-object that is either null
64919
+ * (registry call failed or the package didn't exist) or the resolved
64920
+ * entry from the API. Never throws on registry failures — the UI can
64921
+ * still fall back to local-only info.
64922
+ *
64923
+ * @param {string} appId - Application identifier
64924
+ * @param {number|string} workspaceId - Workspace ID
64925
+ * @param {Object} widgetRegistry - WidgetRegistry instance
64926
+ * @param {Object} options - { componentConfigs?: Object }
64927
+ * @returns {Promise<Object>} { success, widgets, theme, registryError? }
64928
+ */
64929
+ async function getDashboardPublishPlan$1(
64930
+ appId,
64931
+ workspaceId,
64932
+ widgetRegistry = null,
64933
+ options = {},
64934
+ ) {
64935
+ try {
64936
+ const { resolvePackages } = registryApiController$2;
64937
+
64938
+ const deps = await collectDashboardDependencies$1(
64939
+ appId,
64940
+ workspaceId,
64941
+ widgetRegistry,
64942
+ options,
64943
+ );
64944
+ if (!deps.success) {
64945
+ return { success: false, error: deps.error };
64946
+ }
64947
+
64948
+ const refs = [];
64949
+ for (const w of deps.widgets) {
64950
+ if (w.scope && w.packageName) {
64951
+ refs.push({ scope: w.scope, name: w.packageName });
64952
+ }
64953
+ }
64954
+ if (deps.theme && deps.theme.scope && deps.theme.name) {
64955
+ refs.push({ scope: deps.theme.scope, name: deps.theme.name });
64956
+ }
64957
+
64958
+ let registryError = null;
64959
+ const resolvedByKey = new Map();
64960
+ if (refs.length > 0) {
64961
+ const res = await resolvePackages(refs);
64962
+ if (res.success && Array.isArray(res.resolved)) {
64963
+ for (const r of res.resolved) {
64964
+ resolvedByKey.set(`${r.scope}/${r.name}`, r);
64965
+ }
64966
+ } else {
64967
+ registryError = res.error || "Registry lookup failed";
64968
+ }
64969
+ }
64970
+
64971
+ const widgets = deps.widgets.map((w) => {
64972
+ const key =
64973
+ w.scope && w.packageName ? `${w.scope}/${w.packageName}` : null;
64974
+ return {
64975
+ ...w,
64976
+ registry: key ? resolvedByKey.get(key) || null : null,
64977
+ };
64978
+ });
64979
+
64980
+ let theme = null;
64981
+ if (deps.theme) {
64982
+ const key =
64983
+ deps.theme.scope && deps.theme.name
64984
+ ? `${deps.theme.scope}/${deps.theme.name}`
64985
+ : null;
64986
+ theme = {
64987
+ ...deps.theme,
64988
+ registry: key ? resolvedByKey.get(key) || null : null,
64989
+ };
64990
+ }
64991
+
64992
+ return {
64993
+ success: true,
64994
+ widgets,
64995
+ theme,
64996
+ ...(registryError ? { registryError } : {}),
64997
+ };
64998
+ } catch (error) {
64999
+ console.error("[dashboardConfig] getDashboardPublishPlan failed:", error);
65000
+ return { success: false, error: error.message };
65001
+ }
65002
+ }
65003
+
64714
65004
  /**
64715
65005
  * Prepare a dashboard for publishing to the registry.
64716
65006
  *
@@ -65179,6 +65469,8 @@ var dashboardConfigController$1 = {
65179
65469
  installDashboardFromRegistry: installDashboardFromRegistry$1,
65180
65470
  checkCompatibility: checkCompatibility$1,
65181
65471
  prepareDashboardForPublish: prepareDashboardForPublish$1,
65472
+ collectDashboardDependencies: collectDashboardDependencies$1,
65473
+ getDashboardPublishPlan: getDashboardPublishPlan$1,
65182
65474
  getDashboardPreview: getDashboardPreview$1,
65183
65475
  checkDashboardUpdatesForApp: checkDashboardUpdatesForApp$1,
65184
65476
  getProviderSetupManifest: getProviderSetupManifest$1,
@@ -71497,6 +71789,8 @@ const {
71497
71789
  installDashboardFromRegistry,
71498
71790
  checkCompatibility,
71499
71791
  prepareDashboardForPublish,
71792
+ collectDashboardDependencies,
71793
+ getDashboardPublishPlan,
71500
71794
  getDashboardPreview,
71501
71795
  checkDashboardUpdatesForApp,
71502
71796
  getProviderSetupManifest,
@@ -71593,6 +71887,8 @@ var controller = {
71593
71887
  installDashboardFromRegistry,
71594
71888
  checkCompatibility,
71595
71889
  prepareDashboardForPublish,
71890
+ collectDashboardDependencies,
71891
+ getDashboardPublishPlan,
71596
71892
  getDashboardPreview,
71597
71893
  checkDashboardUpdatesForApp,
71598
71894
  getProviderSetupManifest,
@@ -73128,6 +73424,8 @@ const {
73128
73424
  DASHBOARD_CONFIG_PROVIDER_SETUP,
73129
73425
  DASHBOARD_CONFIG_PUBLISH_PREVIEW,
73130
73426
  DASHBOARD_CONFIG_INSTALL_PROGRESS,
73427
+ DASHBOARD_CONFIG_COLLECT_DEPENDENCIES,
73428
+ DASHBOARD_CONFIG_PUBLISH_PLAN,
73131
73429
  } = events$8;
73132
73430
 
73133
73431
  const dashboardConfigApi$2 = {
@@ -73212,6 +73510,42 @@ const dashboardConfigApi$2 = {
73212
73510
  options,
73213
73511
  }),
73214
73512
 
73513
+ /**
73514
+ * Collect enriched widget + theme dependency info for a workspace.
73515
+ * Used by the batch-publish dialog to build its dependency table.
73516
+ *
73517
+ * Returns local state only — the caller is responsible for enriching
73518
+ * with registry state (ownership, latest published version, visibility).
73519
+ *
73520
+ * @param {string} appId - Application identifier
73521
+ * @param {number|string} workspaceId - Workspace ID
73522
+ * @param {Object} options - { componentConfigs?: Object }
73523
+ * @returns {Promise<Object>} { success, widgets, theme }
73524
+ */
73525
+ collectDashboardDependencies: (appId, workspaceId, options = {}) =>
73526
+ ipcRenderer$9.invoke(DASHBOARD_CONFIG_COLLECT_DEPENDENCIES, {
73527
+ appId,
73528
+ workspaceId,
73529
+ options,
73530
+ }),
73531
+
73532
+ /**
73533
+ * Build an enriched dependency plan for batch-publishing a dashboard.
73534
+ * Merges local dep info with registry state (existence, version,
73535
+ * visibility, ownership) so the UI can decorate each row.
73536
+ *
73537
+ * @param {string} appId - Application identifier
73538
+ * @param {number|string} workspaceId - Workspace ID
73539
+ * @param {Object} options - { componentConfigs?: Object }
73540
+ * @returns {Promise<Object>} { success, widgets, theme, registryError? }
73541
+ */
73542
+ getDashboardPublishPlan: (appId, workspaceId, options = {}) =>
73543
+ ipcRenderer$9.invoke(DASHBOARD_CONFIG_PUBLISH_PLAN, {
73544
+ appId,
73545
+ workspaceId,
73546
+ options,
73547
+ }),
73548
+
73215
73549
  /**
73216
73550
  * Get a preview of a dashboard package from the registry.
73217
73551
  * Returns structured preview data and compatibility report.