@trops/dash-core 0.1.88 → 0.1.90

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.
@@ -590,12 +590,16 @@ const DASHBOARD_CONFIG_EXPORT$1 = "dashboard-config-export";
590
590
  const DASHBOARD_CONFIG_IMPORT$1 = "dashboard-config-import";
591
591
  const DASHBOARD_CONFIG_INSTALL$1 = "dashboard-config-install";
592
592
  const DASHBOARD_CONFIG_COMPATIBILITY$1 = "dashboard-config-compatibility";
593
+ const DASHBOARD_CONFIG_PUBLISH$1 = "dashboard-config-publish";
594
+ const DASHBOARD_CONFIG_PREVIEW$1 = "dashboard-config-preview";
593
595
 
594
596
  var dashboardConfigEvents$1 = {
595
597
  DASHBOARD_CONFIG_EXPORT: DASHBOARD_CONFIG_EXPORT$1,
596
598
  DASHBOARD_CONFIG_IMPORT: DASHBOARD_CONFIG_IMPORT$1,
597
599
  DASHBOARD_CONFIG_INSTALL: DASHBOARD_CONFIG_INSTALL$1,
598
600
  DASHBOARD_CONFIG_COMPATIBILITY: DASHBOARD_CONFIG_COMPATIBILITY$1,
601
+ DASHBOARD_CONFIG_PUBLISH: DASHBOARD_CONFIG_PUBLISH$1,
602
+ DASHBOARD_CONFIG_PREVIEW: DASHBOARD_CONFIG_PREVIEW$1,
599
603
  };
600
604
 
601
605
  /**
@@ -8443,6 +8447,110 @@ function checkDashboardCompatibility(
8443
8447
  };
8444
8448
  }
8445
8449
 
8450
+ /**
8451
+ * Generate a registry manifest from a dashboard config.
8452
+ * Converts the internal .dashboard.json format into the registry
8453
+ * manifest.json format used by dash-registry.
8454
+ *
8455
+ * @param {Object} dashboardConfig - Validated dashboard config object
8456
+ * @param {Object} options - Publishing options
8457
+ * @param {string} options.githubUser - GitHub username / org for the package scope
8458
+ * @param {string} options.category - Registry category (default: "general")
8459
+ * @param {string} options.repository - Repository URL (optional)
8460
+ * @returns {Object} Registry manifest object
8461
+ */
8462
+ function generateRegistryManifest(dashboardConfig, options = {}) {
8463
+ const name = (dashboardConfig.name || "dashboard")
8464
+ .replace(/[^a-zA-Z0-9-_ ]/g, "")
8465
+ .replace(/\s+/g, "-")
8466
+ .toLowerCase();
8467
+
8468
+ const githubUser = options.githubUser || "";
8469
+ const version = dashboardConfig.workspace?.version
8470
+ ? `1.0.${dashboardConfig.workspace.version}`
8471
+ : "1.0.0";
8472
+
8473
+ const manifest = {
8474
+ githubUser,
8475
+ name,
8476
+ displayName: dashboardConfig.name || "Dashboard",
8477
+ author: dashboardConfig.author?.name || "",
8478
+ description: dashboardConfig.description || "",
8479
+ version,
8480
+ type: "dashboard",
8481
+ category: options.category || "general",
8482
+ tags: dashboardConfig.tags || [],
8483
+ icon: dashboardConfig.icon || "grip",
8484
+ downloadUrl: `https://github.com/${githubUser}/dash-registry/releases/download/${githubUser}--${name}--v{version}/${name}-v{version}.zip`,
8485
+ repository: options.repository || "",
8486
+ publishedAt: new Date().toISOString(),
8487
+ widgets: (dashboardConfig.widgets || []).map((w) => ({
8488
+ id: w.id,
8489
+ name: w.id ? w.id.split(".").pop() : w.package,
8490
+ package: w.package,
8491
+ version: w.version || "*",
8492
+ required: w.required !== false,
8493
+ author: w.author || "",
8494
+ })),
8495
+ providers: dashboardConfig.providers || [],
8496
+ eventWiring: dashboardConfig.eventWiring || [],
8497
+ };
8498
+
8499
+ return manifest;
8500
+ }
8501
+
8502
+ /**
8503
+ * Build a structured preview object from a dashboard registry package
8504
+ * or dashboard config. Provides all data needed for a rich preview UI.
8505
+ *
8506
+ * @param {Object} source - Registry package manifest or dashboard config
8507
+ * @returns {Object} Structured preview with metadata, widgets, wiring, providers
8508
+ */
8509
+ function buildDashboardPreview(source) {
8510
+ const preview = {
8511
+ name: source.displayName || source.name || "Dashboard",
8512
+ description: source.description || "",
8513
+ author: typeof source.author === "object"
8514
+ ? source.author.name || ""
8515
+ : source.author || "",
8516
+ authorId: typeof source.author === "object"
8517
+ ? source.author.id || ""
8518
+ : "",
8519
+ version: source.version || "",
8520
+ icon: source.icon || "grip",
8521
+ tags: source.tags || [],
8522
+ screenshots: source.screenshots || [],
8523
+ publishedAt: source.publishedAt || null,
8524
+ category: source.category || "general",
8525
+ widgets: (source.widgets || []).map((w) => ({
8526
+ name: w.name || w.id || w.package || "",
8527
+ package: w.package || "",
8528
+ version: w.version || "*",
8529
+ required: w.required !== false,
8530
+ author: w.author || "",
8531
+ })),
8532
+ eventWiring: (source.eventWiring || []).map((wire) => ({
8533
+ raw: wire,
8534
+ summary: `${wire.source?.widget || "?"}.${wire.source?.event || "?"} → ${wire.target?.widget || "?"}.${wire.target?.handler || wire.source?.event || "?"}`,
8535
+ })),
8536
+ providers: (source.providers || []).map((p) => ({
8537
+ type: p.type || "",
8538
+ providerClass: p.providerClass || "",
8539
+ required: p.required !== false,
8540
+ usedBy: p.usedBy || [],
8541
+ })),
8542
+ summary: {
8543
+ widgetCount: (source.widgets || []).length,
8544
+ eventCount: (source.eventWiring || []).length,
8545
+ providerCount: (source.providers || []).length,
8546
+ requiredWidgets: (source.widgets || []).filter((w) => w.required !== false).length,
8547
+ optionalWidgets: (source.widgets || []).filter((w) => w.required === false).length,
8548
+ },
8549
+ };
8550
+
8551
+ return preview;
8552
+ }
8553
+
8446
8554
  var dashboardConfigUtils$1 = {
8447
8555
  collectComponentNames: collectComponentNames$1,
8448
8556
  extractEventWiring: extractEventWiring$1,
@@ -8450,6 +8558,8 @@ var dashboardConfigUtils$1 = {
8450
8558
  buildProviderRequirements: buildProviderRequirements$1,
8451
8559
  applyEventWiringToLayout: applyEventWiringToLayout$1,
8452
8560
  checkDashboardCompatibility,
8561
+ generateRegistryManifest,
8562
+ buildDashboardPreview,
8453
8563
  };
8454
8564
 
8455
8565
  var widgetRegistry$1 = {exports: {}};
@@ -10391,11 +10501,238 @@ async function checkCompatibility$1(dashboardWidgets, widgetRegistry = null) {
10391
10501
  );
10392
10502
  }
10393
10503
 
10504
+ /**
10505
+ * Prepare a dashboard for publishing to the registry.
10506
+ *
10507
+ * Validates that the workspace is shareable, builds the dashboard config,
10508
+ * checks that all widgets exist in the registry, generates a registry
10509
+ * manifest, and creates a ZIP containing both the manifest and
10510
+ * .dashboard.json config.
10511
+ *
10512
+ * @param {BrowserWindow} win - The main window (for save dialog)
10513
+ * @param {string} appId - Application identifier
10514
+ * @param {number|string} workspaceId - ID of the workspace to publish
10515
+ * @param {Object} options - Publishing options
10516
+ * @param {string} options.authorName - Author name
10517
+ * @param {string} options.authorId - Author ID
10518
+ * @param {string} options.description - Dashboard description
10519
+ * @param {string[]} options.tags - Tags
10520
+ * @param {string} options.icon - Icon name
10521
+ * @param {string} options.githubUser - GitHub user/org for registry scope
10522
+ * @param {string} options.category - Registry category
10523
+ * @param {Object} widgetRegistry - WidgetRegistry instance
10524
+ * @returns {Promise<Object>} Result with success, manifest, and filePath
10525
+ */
10526
+ async function prepareDashboardForPublish$1(
10527
+ win,
10528
+ appId,
10529
+ workspaceId,
10530
+ options = {},
10531
+ widgetRegistry = null,
10532
+ ) {
10533
+ try {
10534
+ const { generateRegistryManifest } = dashboardConfigUtils$1;
10535
+
10536
+ // 1. Read workspace
10537
+ const filename = path.join(
10538
+ app.getPath("userData"),
10539
+ appName,
10540
+ appId,
10541
+ configFilename,
10542
+ );
10543
+ const workspacesArray = getFileContents(filename);
10544
+ const workspace = workspacesArray.find(
10545
+ (w) => w.id === workspaceId || w.id === Number(workspaceId),
10546
+ );
10547
+
10548
+ if (!workspace) {
10549
+ return {
10550
+ success: false,
10551
+ error: `Workspace not found: ${workspaceId}`,
10552
+ };
10553
+ }
10554
+
10555
+ // 2. Check shareable flag — imported dashboards cannot be published
10556
+ if (workspace._dashboardConfig && workspace._dashboardConfig.shareable === false) {
10557
+ return {
10558
+ success: false,
10559
+ error: "This dashboard was imported and cannot be published. Only dashboards you created can be shared.",
10560
+ };
10561
+ }
10562
+
10563
+ const layout = workspace.layout || [];
10564
+
10565
+ // 3. Build the dashboard config (reuse export logic)
10566
+ const componentNames = collectComponentNames(layout);
10567
+ const eventWiring = extractEventWiring(layout);
10568
+ const widgets = buildWidgetDependencies(componentNames, widgetRegistry);
10569
+ const providers = buildProviderRequirements(componentNames, widgetRegistry);
10570
+
10571
+ const dashboardConfig = applyDefaults({
10572
+ schemaVersion: CURRENT_SCHEMA_VERSION,
10573
+ name: workspace.name || workspace.label || "Dashboard",
10574
+ description: options.description || "",
10575
+ author: {
10576
+ name: options.authorName || "",
10577
+ id: options.authorId || "",
10578
+ },
10579
+ shareable: true,
10580
+ tags: options.tags || [],
10581
+ icon: options.icon || "grip",
10582
+ workspace: {
10583
+ id: workspace.id,
10584
+ name: workspace.name,
10585
+ type: workspace.type || "workspace",
10586
+ label: workspace.label || workspace.name,
10587
+ version: workspace.version || 1,
10588
+ layout,
10589
+ menuId: workspace.menuId || 1,
10590
+ },
10591
+ widgets,
10592
+ providers,
10593
+ eventWiring,
10594
+ });
10595
+
10596
+ // 4. Validate the config
10597
+ const validation = validateDashboardConfig(dashboardConfig);
10598
+ if (!validation.valid) {
10599
+ return {
10600
+ success: false,
10601
+ error: `Generated config is invalid: ${validation.errors.join(", ")}`,
10602
+ };
10603
+ }
10604
+
10605
+ // 5. Verify all widgets exist in the registry
10606
+ const { fetchRegistryIndex } = registryController$1;
10607
+ let registryPackages = [];
10608
+ try {
10609
+ const index = await fetchRegistryIndex();
10610
+ registryPackages = index.packages || [];
10611
+ } catch (err) {
10612
+ return {
10613
+ success: false,
10614
+ error: `Cannot verify widgets in registry: ${err.message}`,
10615
+ };
10616
+ }
10617
+
10618
+ const registryNames = new Set(registryPackages.map((p) => p.name));
10619
+ const missingFromRegistry = widgets
10620
+ .filter((w) => w.required !== false && !registryNames.has(w.package))
10621
+ .map((w) => w.package);
10622
+
10623
+ if (missingFromRegistry.length > 0) {
10624
+ return {
10625
+ success: false,
10626
+ error: `Required widgets not found in registry: ${missingFromRegistry.join(", ")}. Publish them first.`,
10627
+ };
10628
+ }
10629
+
10630
+ // 6. Generate registry manifest
10631
+ const manifest = generateRegistryManifest(dashboardConfig, {
10632
+ githubUser: options.githubUser || options.authorId || "",
10633
+ category: options.category || "general",
10634
+ repository: options.repository || "",
10635
+ });
10636
+
10637
+ // 7. Show save dialog for the publish package
10638
+ const sanitizedName = manifest.name;
10639
+ const { canceled, filePath } = await dialog.showSaveDialog(win, {
10640
+ title: "Save Dashboard Package for Registry",
10641
+ defaultPath: path.join(
10642
+ app.getPath("desktop"),
10643
+ `${sanitizedName}-v${manifest.version}.zip`,
10644
+ ),
10645
+ filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
10646
+ });
10647
+
10648
+ if (canceled || !filePath) {
10649
+ return { success: false, canceled: true };
10650
+ }
10651
+
10652
+ // 8. Create ZIP with manifest and dashboard config
10653
+ const zip = new AdmZip();
10654
+ zip.addFile("manifest.json", Buffer.from(JSON.stringify(manifest, null, 2), "utf-8"));
10655
+ zip.addFile(
10656
+ `${sanitizedName}.dashboard.json`,
10657
+ Buffer.from(JSON.stringify(dashboardConfig, null, 2), "utf-8"),
10658
+ );
10659
+ zip.writeZip(filePath);
10660
+
10661
+ console.log(
10662
+ `[DashboardConfigController] Prepared publish package: ${filePath}`,
10663
+ );
10664
+
10665
+ return {
10666
+ success: true,
10667
+ filePath,
10668
+ manifest,
10669
+ config: dashboardConfig,
10670
+ };
10671
+ } catch (error) {
10672
+ console.error(
10673
+ "[DashboardConfigController] Error preparing dashboard for publish:",
10674
+ error,
10675
+ );
10676
+ return {
10677
+ success: false,
10678
+ error: error.message,
10679
+ };
10680
+ }
10681
+ }
10682
+
10683
+ /**
10684
+ * Get a full preview of a dashboard package from the registry.
10685
+ * Combines the structured preview data with a compatibility check.
10686
+ *
10687
+ * @param {string} packageName - Registry package name
10688
+ * @param {Object} widgetRegistry - WidgetRegistry instance
10689
+ * @returns {Promise<Object>} Preview data with compatibility report
10690
+ */
10691
+ async function getDashboardPreview$1(packageName, widgetRegistry = null) {
10692
+ const { buildDashboardPreview, checkDashboardCompatibility } =
10693
+ dashboardConfigUtils$1;
10694
+ const { getPackage, fetchRegistryIndex } = registryController$1;
10695
+
10696
+ const pkg = await getPackage(packageName);
10697
+ if (!pkg) {
10698
+ return {
10699
+ success: false,
10700
+ error: `Dashboard package not found: ${packageName}`,
10701
+ };
10702
+ }
10703
+
10704
+ const preview = buildDashboardPreview(pkg);
10705
+
10706
+ // Get compatibility report
10707
+ const installedWidgets = widgetRegistry ? widgetRegistry.getWidgets() : [];
10708
+ let registryPackages = [];
10709
+ try {
10710
+ const index = await fetchRegistryIndex();
10711
+ registryPackages = index.packages || [];
10712
+ } catch (err) {
10713
+ // Non-fatal — preview still works without compatibility
10714
+ }
10715
+
10716
+ const compatibility = checkDashboardCompatibility(
10717
+ pkg.widgets || [],
10718
+ installedWidgets,
10719
+ registryPackages,
10720
+ );
10721
+
10722
+ return {
10723
+ success: true,
10724
+ preview,
10725
+ compatibility,
10726
+ };
10727
+ }
10728
+
10394
10729
  var dashboardConfigController$1 = {
10395
10730
  exportDashboardConfig: exportDashboardConfig$1,
10396
10731
  importDashboardConfig: importDashboardConfig$1,
10397
10732
  installDashboardFromRegistry: installDashboardFromRegistry$1,
10398
10733
  checkCompatibility: checkCompatibility$1,
10734
+ prepareDashboardForPublish: prepareDashboardForPublish$1,
10735
+ getDashboardPreview: getDashboardPreview$1,
10399
10736
  };
10400
10737
 
10401
10738
  /**
@@ -10489,6 +10826,8 @@ const {
10489
10826
  importDashboardConfig,
10490
10827
  installDashboardFromRegistry,
10491
10828
  checkCompatibility,
10829
+ prepareDashboardForPublish,
10830
+ getDashboardPreview,
10492
10831
  } = dashboardConfigController$1;
10493
10832
 
10494
10833
  var controller = {
@@ -10536,6 +10875,8 @@ var controller = {
10536
10875
  importDashboardConfig,
10537
10876
  installDashboardFromRegistry,
10538
10877
  checkCompatibility,
10878
+ prepareDashboardForPublish,
10879
+ getDashboardPreview,
10539
10880
  };
10540
10881
 
10541
10882
  const { ipcRenderer: ipcRenderer$i } = require$$0$1;
@@ -11916,6 +12257,8 @@ const {
11916
12257
  DASHBOARD_CONFIG_IMPORT,
11917
12258
  DASHBOARD_CONFIG_INSTALL,
11918
12259
  DASHBOARD_CONFIG_COMPATIBILITY,
12260
+ DASHBOARD_CONFIG_PUBLISH,
12261
+ DASHBOARD_CONFIG_PREVIEW,
11919
12262
  } = events$8;
11920
12263
 
11921
12264
  const dashboardConfigApi$2 = {
@@ -11972,6 +12315,33 @@ const dashboardConfigApi$2 = {
11972
12315
  appId,
11973
12316
  dashboardWidgets,
11974
12317
  }),
12318
+
12319
+ /**
12320
+ * Prepare a dashboard for publishing to the registry.
12321
+ * Validates shareable status, checks widgets exist in registry,
12322
+ * generates manifest, and saves a publish-ready ZIP.
12323
+ *
12324
+ * @param {string} appId - Application identifier
12325
+ * @param {number|string} workspaceId - Workspace to publish
12326
+ * @param {Object} options - Publishing options (authorName, authorId, description, tags, icon, githubUser, category)
12327
+ * @returns {Promise<Object>} Result with success, manifest, filePath
12328
+ */
12329
+ prepareDashboardForPublish: (appId, workspaceId, options = {}) =>
12330
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_PUBLISH, {
12331
+ appId,
12332
+ workspaceId,
12333
+ options,
12334
+ }),
12335
+
12336
+ /**
12337
+ * Get a preview of a dashboard package from the registry.
12338
+ * Returns structured preview data and compatibility report.
12339
+ *
12340
+ * @param {string} packageName - Registry package name
12341
+ * @returns {Promise<Object>} Preview with metadata, widgets, wiring, compatibility
12342
+ */
12343
+ getDashboardPreview: (packageName) =>
12344
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_PREVIEW, { packageName }),
11975
12345
  };
11976
12346
 
11977
12347
  var dashboardConfigApi_1 = dashboardConfigApi$2;