@trops/dash-core 0.1.86 → 0.1.88

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.
@@ -588,10 +588,14 @@ var clientCacheEvents$1 = {
588
588
 
589
589
  const DASHBOARD_CONFIG_EXPORT$1 = "dashboard-config-export";
590
590
  const DASHBOARD_CONFIG_IMPORT$1 = "dashboard-config-import";
591
+ const DASHBOARD_CONFIG_INSTALL$1 = "dashboard-config-install";
592
+ const DASHBOARD_CONFIG_COMPATIBILITY$1 = "dashboard-config-compatibility";
591
593
 
592
594
  var dashboardConfigEvents$1 = {
593
- DASHBOARD_CONFIG_EXPORT: DASHBOARD_CONFIG_EXPORT$1,
594
- DASHBOARD_CONFIG_IMPORT: DASHBOARD_CONFIG_IMPORT$1,
595
+ DASHBOARD_CONFIG_EXPORT: DASHBOARD_CONFIG_EXPORT$1,
596
+ DASHBOARD_CONFIG_IMPORT: DASHBOARD_CONFIG_IMPORT$1,
597
+ DASHBOARD_CONFIG_INSTALL: DASHBOARD_CONFIG_INSTALL$1,
598
+ DASHBOARD_CONFIG_COMPATIBILITY: DASHBOARD_CONFIG_COMPATIBILITY$1,
595
599
  };
596
600
 
597
601
  /**
@@ -8354,12 +8358,98 @@ function applyEventWiringToLayout$1(layout, eventWiring) {
8354
8358
  return layout;
8355
8359
  }
8356
8360
 
8361
+ /**
8362
+ * Check compatibility of a dashboard config against installed widgets.
8363
+ * Returns a per-widget status report indicating what's installed,
8364
+ * what needs to be installed, and what's unavailable.
8365
+ *
8366
+ * @param {Array} dashboardWidgets - Widget deps from dashboard config (widgets array)
8367
+ * @param {Array} installedWidgets - Currently installed widget metadata (from widgetRegistry.getWidgets())
8368
+ * @param {Array} registryPackages - Available packages from registry index (optional)
8369
+ * @returns {Object} Compatibility report
8370
+ */
8371
+ function checkDashboardCompatibility(
8372
+ dashboardWidgets = [],
8373
+ installedWidgets = [],
8374
+ registryPackages = [],
8375
+ ) {
8376
+ const installedByName = new Map();
8377
+ for (const w of installedWidgets) {
8378
+ if (w.name) {
8379
+ installedByName.set(w.name, w);
8380
+ }
8381
+ }
8382
+
8383
+ const registryByName = new Map();
8384
+ for (const p of registryPackages) {
8385
+ if (p.name) {
8386
+ registryByName.set(p.name, p);
8387
+ }
8388
+ }
8389
+
8390
+ const widgets = [];
8391
+ let installedCount = 0;
8392
+ let toInstallCount = 0;
8393
+ let unavailableCount = 0;
8394
+
8395
+ for (const dep of dashboardWidgets) {
8396
+ const packageName = dep.package;
8397
+ const required = dep.required !== false;
8398
+ const installed = installedByName.get(packageName);
8399
+
8400
+ if (installed) {
8401
+ installedCount++;
8402
+ widgets.push({
8403
+ package: packageName,
8404
+ required,
8405
+ status: "installed",
8406
+ installedVersion: installed.version || null,
8407
+ requiredVersion: dep.version || "*",
8408
+ });
8409
+ } else if (registryByName.has(packageName)) {
8410
+ toInstallCount++;
8411
+ const registryPkg = registryByName.get(packageName);
8412
+ widgets.push({
8413
+ package: packageName,
8414
+ required,
8415
+ status: "to-install",
8416
+ availableVersion: registryPkg.version || null,
8417
+ requiredVersion: dep.version || "*",
8418
+ });
8419
+ } else {
8420
+ unavailableCount++;
8421
+ widgets.push({
8422
+ package: packageName,
8423
+ required,
8424
+ status: "unavailable",
8425
+ requiredVersion: dep.version || "*",
8426
+ });
8427
+ }
8428
+ }
8429
+
8430
+ const hasUnavailableRequired = widgets.some(
8431
+ (w) => w.status === "unavailable" && w.required,
8432
+ );
8433
+
8434
+ return {
8435
+ compatible: !hasUnavailableRequired,
8436
+ summary: {
8437
+ total: dashboardWidgets.length,
8438
+ installed: installedCount,
8439
+ toInstall: toInstallCount,
8440
+ unavailable: unavailableCount,
8441
+ },
8442
+ widgets,
8443
+ };
8444
+ }
8445
+
8357
8446
  var dashboardConfigUtils$1 = {
8358
8447
  collectComponentNames: collectComponentNames$1,
8359
8448
  extractEventWiring: extractEventWiring$1,
8360
8449
  buildWidgetDependencies: buildWidgetDependencies$1,
8361
8450
  buildProviderRequirements: buildProviderRequirements$1,
8362
8451
  applyEventWiringToLayout: applyEventWiringToLayout$1,
8452
+ checkDashboardCompatibility,
8363
8453
  };
8364
8454
 
8365
8455
  var widgetRegistry$1 = {exports: {}};
@@ -9974,134 +10064,292 @@ async function importDashboardConfig$1(win, appId, widgetRegistry = null) {
9974
10064
  // Apply defaults to fill in optional fields
9975
10065
  dashboardConfig = applyDefaults(dashboardConfig);
9976
10066
 
9977
- // 3. Auto-install missing widgets from registry
9978
- const installSummary = {
9979
- installed: [],
9980
- alreadyInstalled: [],
9981
- failed: [],
10067
+ // Delegate to shared import pipeline
10068
+ return await processDashboardConfig(
10069
+ win,
10070
+ appId,
10071
+ dashboardConfig,
10072
+ widgetRegistry,
10073
+ );
10074
+ } catch (error) {
10075
+ console.error(
10076
+ "[DashboardConfigController] Error importing dashboard:",
10077
+ error,
10078
+ );
10079
+ return {
10080
+ success: false,
10081
+ error: error.message,
9982
10082
  };
10083
+ }
10084
+ }
9983
10085
 
9984
- if (
9985
- widgetRegistry &&
9986
- dashboardConfig.widgets &&
9987
- dashboardConfig.widgets.length
9988
- ) {
9989
- const installedWidgets = widgetRegistry.getWidgets();
9990
- const installedPackages = new Set(installedWidgets.map((w) => w.name));
10086
+ /**
10087
+ * Shared import pipeline: install widgets, create workspace, wire events.
10088
+ * Used by both importDashboardConfig (ZIP) and installDashboardFromRegistry.
10089
+ *
10090
+ * @param {BrowserWindow} win - The main window
10091
+ * @param {string} appId - Application identifier
10092
+ * @param {Object} dashboardConfig - Validated dashboard config object
10093
+ * @param {Object} widgetRegistry - WidgetRegistry instance
10094
+ * @param {Object} options - Additional options
10095
+ * @param {string} options.source - Source label ("zip" or "registry")
10096
+ * @returns {Promise<Object>} Result with success, workspace, and summary
10097
+ */
10098
+ async function processDashboardConfig(
10099
+ win,
10100
+ appId,
10101
+ dashboardConfig,
10102
+ widgetRegistry = null,
10103
+ options = {},
10104
+ ) {
10105
+ const source = options.source || "zip";
9991
10106
 
9992
- for (const widgetDep of dashboardConfig.widgets) {
9993
- const packageName = widgetDep.package;
10107
+ // 1. Auto-install missing widgets from registry
10108
+ const installSummary = {
10109
+ installed: [],
10110
+ alreadyInstalled: [],
10111
+ failed: [],
10112
+ };
9994
10113
 
9995
- if (installedPackages.has(packageName)) {
9996
- installSummary.alreadyInstalled.push(packageName);
9997
- continue;
9998
- }
10114
+ if (
10115
+ widgetRegistry &&
10116
+ dashboardConfig.widgets &&
10117
+ dashboardConfig.widgets.length
10118
+ ) {
10119
+ const installedWidgets = widgetRegistry.getWidgets();
10120
+ const installedPackages = new Set(installedWidgets.map((w) => w.name));
9999
10121
 
10000
- // Try to find the widget in the registry and install it
10001
- try {
10002
- const registryPkg = await getPackage(packageName);
10003
- if (registryPkg && registryPkg.downloadUrl) {
10004
- await widgetRegistry.downloadWidget(
10005
- packageName,
10006
- registryPkg.downloadUrl,
10007
- registryPkg.dashConfigUrl || null,
10008
- );
10009
- installSummary.installed.push(packageName);
10010
- installedPackages.add(packageName);
10011
- } else {
10012
- installSummary.failed.push({
10013
- package: packageName,
10014
- reason: "Not found in registry",
10015
- });
10016
- }
10017
- } catch (installError) {
10122
+ for (const widgetDep of dashboardConfig.widgets) {
10123
+ const packageName = widgetDep.package;
10124
+
10125
+ if (installedPackages.has(packageName)) {
10126
+ installSummary.alreadyInstalled.push(packageName);
10127
+ continue;
10128
+ }
10129
+
10130
+ // Try to find the widget in the registry and install it
10131
+ try {
10132
+ const registryPkg = await getPackage(packageName);
10133
+ if (registryPkg && registryPkg.downloadUrl) {
10134
+ await widgetRegistry.downloadWidget(
10135
+ packageName,
10136
+ registryPkg.downloadUrl,
10137
+ registryPkg.dashConfigUrl || null,
10138
+ );
10139
+ installSummary.installed.push(packageName);
10140
+ installedPackages.add(packageName);
10141
+ } else {
10018
10142
  installSummary.failed.push({
10019
10143
  package: packageName,
10020
- reason: installError.message,
10144
+ reason: "Not found in registry",
10021
10145
  });
10022
10146
  }
10147
+ } catch (installError) {
10148
+ installSummary.failed.push({
10149
+ package: packageName,
10150
+ reason: installError.message,
10151
+ });
10023
10152
  }
10024
10153
  }
10154
+ }
10025
10155
 
10026
- // 4. Build workspace from config
10027
- const workspace = dashboardConfig.workspace;
10156
+ // 2. Build workspace from config
10157
+ const workspace = { ...dashboardConfig.workspace };
10028
10158
 
10029
- if (!workspace) {
10159
+ if (!workspace || !workspace.layout) {
10160
+ return {
10161
+ success: false,
10162
+ error: "Dashboard config has no workspace data",
10163
+ };
10164
+ }
10165
+
10166
+ // Generate a unique ID for the imported workspace
10167
+ workspace.id = Date.now();
10168
+
10169
+ // 3. Apply event wiring to layout
10170
+ const eventWiringSummary = [];
10171
+ if (
10172
+ dashboardConfig.eventWiring &&
10173
+ dashboardConfig.eventWiring.length &&
10174
+ workspace.layout
10175
+ ) {
10176
+ applyEventWiringToLayout(workspace.layout, dashboardConfig.eventWiring);
10177
+ for (const wire of dashboardConfig.eventWiring) {
10178
+ eventWiringSummary.push(
10179
+ `${wire.source?.widget}.${wire.source?.event} → ${wire.target?.widget}.${wire.target?.handler}`,
10180
+ );
10181
+ }
10182
+ }
10183
+
10184
+ // 4. Mark as not shareable (imported dashboards cannot be re-published)
10185
+ workspace._dashboardConfig = {
10186
+ shareable: false,
10187
+ source,
10188
+ importedFrom: dashboardConfig.name,
10189
+ importedAt: new Date().toISOString(),
10190
+ originalAuthor: dashboardConfig.author,
10191
+ schemaVersion: dashboardConfig.schemaVersion,
10192
+ };
10193
+
10194
+ // Save workspace to workspaces.json
10195
+ const workspaceController = workspaceController_1;
10196
+ const saveResult = workspaceController.saveWorkspaceForApplication(
10197
+ win,
10198
+ appId,
10199
+ workspace,
10200
+ );
10201
+
10202
+ if (saveResult.error) {
10203
+ return {
10204
+ success: false,
10205
+ error: `Failed to save workspace: ${saveResult.message}`,
10206
+ };
10207
+ }
10208
+
10209
+ // Build provider requirements summary
10210
+ const providerSummary = (dashboardConfig.providers || []).map((p) => ({
10211
+ type: p.type,
10212
+ providerClass: p.providerClass,
10213
+ required: p.required,
10214
+ usedBy: p.usedBy,
10215
+ }));
10216
+
10217
+ console.log(
10218
+ `[DashboardConfigController] Imported dashboard "${dashboardConfig.name}" (${source}) as workspace ${workspace.id}`,
10219
+ );
10220
+
10221
+ return {
10222
+ success: true,
10223
+ workspace,
10224
+ summary: {
10225
+ name: dashboardConfig.name,
10226
+ description: dashboardConfig.description || "",
10227
+ author: dashboardConfig.author,
10228
+ widgets: installSummary,
10229
+ eventsWired: eventWiringSummary,
10230
+ providersRequired: providerSummary,
10231
+ },
10232
+ };
10233
+ }
10234
+
10235
+ /**
10236
+ * Install a dashboard from the registry by package name.
10237
+ *
10238
+ * Fetches the dashboard ZIP from the registry, extracts the .dashboard.json,
10239
+ * validates it, and delegates to the shared import pipeline.
10240
+ *
10241
+ * @param {BrowserWindow} win - The main window
10242
+ * @param {string} appId - Application identifier
10243
+ * @param {string} packageName - Registry package name for the dashboard
10244
+ * @param {Object} widgetRegistry - WidgetRegistry instance
10245
+ * @returns {Promise<Object>} Result with success, workspace, and summary
10246
+ */
10247
+ async function installDashboardFromRegistry$1(
10248
+ win,
10249
+ appId,
10250
+ packageName,
10251
+ widgetRegistry = null,
10252
+ ) {
10253
+ try {
10254
+ // 1. Look up the dashboard package in the registry
10255
+ const registryPkg = await getPackage(packageName);
10256
+ if (!registryPkg) {
10030
10257
  return {
10031
10258
  success: false,
10032
- error: "Dashboard config has no workspace data",
10259
+ error: `Dashboard package not found in registry: ${packageName}`,
10033
10260
  };
10034
10261
  }
10035
10262
 
10036
- // Generate a unique ID for the imported workspace
10037
- workspace.id = Date.now();
10038
-
10039
- // 5. Apply event wiring to layout
10040
- const eventWiringSummary = [];
10041
- if (
10042
- dashboardConfig.eventWiring &&
10043
- dashboardConfig.eventWiring.length &&
10044
- workspace.layout
10045
- ) {
10046
- applyEventWiringToLayout(workspace.layout, dashboardConfig.eventWiring);
10047
- for (const wire of dashboardConfig.eventWiring) {
10048
- eventWiringSummary.push(
10049
- `${wire.source?.widget}.${wire.source?.event} → ${wire.target?.widget}.${wire.target?.handler}`,
10050
- );
10051
- }
10263
+ if (!registryPkg.downloadUrl) {
10264
+ return {
10265
+ success: false,
10266
+ error: `Dashboard package has no download URL: ${packageName}`,
10267
+ };
10052
10268
  }
10053
10269
 
10054
- // 6. Mark as not shareable (imported dashboards cannot be re-published)
10055
- workspace._dashboardConfig = {
10056
- shareable: false,
10057
- importedFrom: dashboardConfig.name,
10058
- importedAt: new Date().toISOString(),
10059
- originalAuthor: dashboardConfig.author,
10060
- schemaVersion: dashboardConfig.schemaVersion,
10061
- };
10270
+ // 2. Resolve the download URL and fetch the ZIP
10271
+ const version = registryPkg.version || "1.0.0";
10272
+ let downloadUrl = registryPkg.downloadUrl;
10273
+ downloadUrl = downloadUrl.replace("{version}", version);
10274
+ downloadUrl = downloadUrl.replace("{name}", packageName);
10062
10275
 
10063
- // Save workspace to workspaces.json
10064
- const workspaceController = workspaceController_1;
10065
- const saveResult = workspaceController.saveWorkspaceForApplication(
10066
- win,
10067
- appId,
10068
- workspace,
10276
+ // Enforce HTTPS
10277
+ const parsedUrl = new URL(downloadUrl);
10278
+ if (parsedUrl.protocol !== "https:") {
10279
+ return {
10280
+ success: false,
10281
+ error: `Dashboard downloads must use HTTPS. Refusing: ${downloadUrl}`,
10282
+ };
10283
+ }
10284
+
10285
+ console.log(
10286
+ `[DashboardConfigController] Fetching dashboard from: ${downloadUrl}`,
10069
10287
  );
10070
10288
 
10071
- if (saveResult.error) {
10289
+ const response = await fetch(downloadUrl);
10290
+ if (!response.ok) {
10072
10291
  return {
10073
10292
  success: false,
10074
- error: `Failed to save workspace: ${saveResult.message}`,
10293
+ error: `Failed to download dashboard: ${response.status} ${response.statusText}`,
10075
10294
  };
10076
10295
  }
10077
10296
 
10078
- // Build provider requirements summary
10079
- const providerSummary = (dashboardConfig.providers || []).map((p) => ({
10080
- type: p.type,
10081
- providerClass: p.providerClass,
10082
- required: p.required,
10083
- usedBy: p.usedBy,
10084
- }));
10297
+ const buffer = await response.arrayBuffer();
10298
+ const zip = new AdmZip(Buffer.from(buffer));
10085
10299
 
10086
- console.log(
10087
- `[DashboardConfigController] Imported dashboard "${dashboardConfig.name}" as workspace ${workspace.id}`,
10300
+ // 3. Validate ZIP entries
10301
+ const tempDir = path.join(app.getPath("temp"), "dash-registry-import");
10302
+ const { validateZipEntries } = widgetRegistryExports;
10303
+ validateZipEntries(zip, tempDir);
10304
+
10305
+ // 4. Find and parse .dashboard.json
10306
+ const entries = zip.getEntries();
10307
+ const configEntry = entries.find((e) =>
10308
+ e.entryName.endsWith(".dashboard.json"),
10088
10309
  );
10089
10310
 
10090
- return {
10091
- success: true,
10092
- workspace,
10093
- summary: {
10094
- name: dashboardConfig.name,
10095
- description: dashboardConfig.description || "",
10096
- author: dashboardConfig.author,
10097
- widgets: installSummary,
10098
- eventsWired: eventWiringSummary,
10099
- providersRequired: providerSummary,
10311
+ if (!configEntry) {
10312
+ return {
10313
+ success: false,
10314
+ error: "No .dashboard.json file found in downloaded archive",
10315
+ };
10316
+ }
10317
+
10318
+ const configJson = configEntry.getData().toString("utf-8");
10319
+ let dashboardConfig;
10320
+ try {
10321
+ dashboardConfig = JSON.parse(configJson);
10322
+ } catch (parseError) {
10323
+ return {
10324
+ success: false,
10325
+ error: `Invalid JSON in dashboard config: ${parseError.message}`,
10326
+ };
10327
+ }
10328
+
10329
+ // 5. Validate against schema
10330
+ const validation = validateDashboardConfig(dashboardConfig);
10331
+ if (!validation.valid) {
10332
+ return {
10333
+ success: false,
10334
+ error: `Invalid dashboard config: ${validation.errors.join(", ")}`,
10335
+ };
10336
+ }
10337
+
10338
+ dashboardConfig = applyDefaults(dashboardConfig);
10339
+
10340
+ // 6. Delegate to shared import pipeline
10341
+ return await processDashboardConfig(
10342
+ win,
10343
+ appId,
10344
+ dashboardConfig,
10345
+ widgetRegistry,
10346
+ {
10347
+ source: "registry",
10100
10348
  },
10101
- };
10349
+ );
10102
10350
  } catch (error) {
10103
10351
  console.error(
10104
- "[DashboardConfigController] Error importing dashboard:",
10352
+ "[DashboardConfigController] Error installing dashboard from registry:",
10105
10353
  error,
10106
10354
  );
10107
10355
  return {
@@ -10111,9 +10359,43 @@ async function importDashboardConfig$1(win, appId, widgetRegistry = null) {
10111
10359
  }
10112
10360
  }
10113
10361
 
10362
+ /**
10363
+ * Check compatibility of a dashboard's widget dependencies against
10364
+ * installed widgets and registry availability.
10365
+ *
10366
+ * @param {Array} dashboardWidgets - Widget deps from dashboard config
10367
+ * @param {Object} widgetRegistry - WidgetRegistry instance (needs getWidgets())
10368
+ * @returns {Promise<Object>} Compatibility report
10369
+ */
10370
+ async function checkCompatibility$1(dashboardWidgets, widgetRegistry = null) {
10371
+ const { checkDashboardCompatibility } = dashboardConfigUtils$1;
10372
+ const { fetchRegistryIndex } = registryController$1;
10373
+
10374
+ const installedWidgets = widgetRegistry ? widgetRegistry.getWidgets() : [];
10375
+
10376
+ let registryPackages = [];
10377
+ try {
10378
+ const index = await fetchRegistryIndex();
10379
+ registryPackages = index.packages || [];
10380
+ } catch (err) {
10381
+ console.warn(
10382
+ "[DashboardConfigController] Could not fetch registry index for compatibility check:",
10383
+ err.message,
10384
+ );
10385
+ }
10386
+
10387
+ return checkDashboardCompatibility(
10388
+ dashboardWidgets,
10389
+ installedWidgets,
10390
+ registryPackages,
10391
+ );
10392
+ }
10393
+
10114
10394
  var dashboardConfigController$1 = {
10115
10395
  exportDashboardConfig: exportDashboardConfig$1,
10116
10396
  importDashboardConfig: importDashboardConfig$1,
10397
+ installDashboardFromRegistry: installDashboardFromRegistry$1,
10398
+ checkCompatibility: checkCompatibility$1,
10117
10399
  };
10118
10400
 
10119
10401
  /**
@@ -10205,6 +10487,8 @@ const { install: pluginInstall } = pluginController_1;
10205
10487
  const {
10206
10488
  exportDashboardConfig,
10207
10489
  importDashboardConfig,
10490
+ installDashboardFromRegistry,
10491
+ checkCompatibility,
10208
10492
  } = dashboardConfigController$1;
10209
10493
 
10210
10494
  var controller = {
@@ -10250,6 +10534,8 @@ var controller = {
10250
10534
  searchIndex,
10251
10535
  exportDashboardConfig,
10252
10536
  importDashboardConfig,
10537
+ installDashboardFromRegistry,
10538
+ checkCompatibility,
10253
10539
  };
10254
10540
 
10255
10541
  const { ipcRenderer: ipcRenderer$i } = require$$0$1;
@@ -11626,36 +11912,66 @@ var clientCacheApi_1 = clientCacheApi$2;
11626
11912
 
11627
11913
  const { ipcRenderer: ipcRenderer$1 } = require$$0$1;
11628
11914
  const {
11629
- DASHBOARD_CONFIG_EXPORT,
11630
- DASHBOARD_CONFIG_IMPORT,
11915
+ DASHBOARD_CONFIG_EXPORT,
11916
+ DASHBOARD_CONFIG_IMPORT,
11917
+ DASHBOARD_CONFIG_INSTALL,
11918
+ DASHBOARD_CONFIG_COMPATIBILITY,
11631
11919
  } = events$8;
11632
11920
 
11633
11921
  const dashboardConfigApi$2 = {
11634
- /**
11635
- * Export a workspace as a dashboard config ZIP file.
11636
- *
11637
- * @param {string} appId - Application identifier
11638
- * @param {number|string} workspaceId - ID of the workspace to export
11639
- * @param {Object} options - Export options (authorName, authorId, description, tags, icon)
11640
- * @returns {Promise<Object>} Result with success, filePath, and config
11641
- */
11642
- exportDashboardConfig: (appId, workspaceId, options = {}) =>
11643
- ipcRenderer$1.invoke(DASHBOARD_CONFIG_EXPORT, {
11644
- appId,
11645
- workspaceId,
11646
- options,
11647
- }),
11648
-
11649
- /**
11650
- * Import a dashboard config from a ZIP file.
11651
- * Shows a file picker, validates the config, installs missing widgets,
11652
- * creates the workspace, and applies event wiring.
11653
- *
11654
- * @param {string} appId - Application identifier
11655
- * @returns {Promise<Object>} Result with success, workspace, and summary
11656
- */
11657
- importDashboardConfig: (appId) =>
11658
- ipcRenderer$1.invoke(DASHBOARD_CONFIG_IMPORT, { appId }),
11922
+ /**
11923
+ * Export a workspace as a dashboard config ZIP file.
11924
+ *
11925
+ * @param {string} appId - Application identifier
11926
+ * @param {number|string} workspaceId - ID of the workspace to export
11927
+ * @param {Object} options - Export options (authorName, authorId, description, tags, icon)
11928
+ * @returns {Promise<Object>} Result with success, filePath, and config
11929
+ */
11930
+ exportDashboardConfig: (appId, workspaceId, options = {}) =>
11931
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_EXPORT, {
11932
+ appId,
11933
+ workspaceId,
11934
+ options,
11935
+ }),
11936
+
11937
+ /**
11938
+ * Import a dashboard config from a ZIP file.
11939
+ * Shows a file picker, validates the config, installs missing widgets,
11940
+ * creates the workspace, and applies event wiring.
11941
+ *
11942
+ * @param {string} appId - Application identifier
11943
+ * @returns {Promise<Object>} Result with success, workspace, and summary
11944
+ */
11945
+ importDashboardConfig: (appId) =>
11946
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_IMPORT, { appId }),
11947
+
11948
+ /**
11949
+ * Install a dashboard from the registry by package name.
11950
+ * Fetches the dashboard ZIP, validates config, installs widgets,
11951
+ * creates workspace, and applies event wiring.
11952
+ *
11953
+ * @param {string} appId - Application identifier
11954
+ * @param {string} packageName - Registry package name
11955
+ * @returns {Promise<Object>} Result with success, workspace, and summary
11956
+ */
11957
+ installDashboardFromRegistry: (appId, packageName) =>
11958
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_INSTALL, {
11959
+ appId,
11960
+ packageName,
11961
+ }),
11962
+
11963
+ /**
11964
+ * Check compatibility of a dashboard config against installed widgets.
11965
+ *
11966
+ * @param {string} appId - Application identifier
11967
+ * @param {Array} dashboardWidgets - Widget dependencies from dashboard config
11968
+ * @returns {Promise<Object>} Compatibility report with per-widget status
11969
+ */
11970
+ checkDashboardCompatibility: (appId, dashboardWidgets) =>
11971
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_COMPATIBILITY, {
11972
+ appId,
11973
+ dashboardWidgets,
11974
+ }),
11659
11975
  };
11660
11976
 
11661
11977
  var dashboardConfigApi_1 = dashboardConfigApi$2;