pandorga 1.4.4 → 1.4.6

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.
data/studio/index.html CHANGED
@@ -18,7 +18,7 @@
18
18
  rel="stylesheet"
19
19
  href="https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css"
20
20
  />
21
- <script type="module" crossorigin src="/studio/assets/index-Cf9OPjQU.js"></script>
21
+ <script type="module" crossorigin src="/studio/assets/index-CMVzh8F1.js"></script>
22
22
  <link rel="stylesheet" crossorigin href="/studio/assets/index-Cd1mlY_H.css">
23
23
  </head>
24
24
  <body>
@@ -73,10 +73,12 @@ export const studioApi = {
73
73
  method: "POST",
74
74
  body: JSON.stringify(payload),
75
75
  }),
76
- /** Content-pipeline run for a commit SHA (production). */
77
- pipelineStatus: (sha, workflow = null) => {
78
- const params = new URLSearchParams({ sha: String(sha || "") });
76
+ /** Content-pipeline run for a commit SHA, or latest on the branch when omitted. */
77
+ pipelineStatus: (sha = null, workflow = null) => {
78
+ const params = new URLSearchParams();
79
+ if (sha) params.set("sha", String(sha));
79
80
  if (workflow) params.set("workflow", String(workflow));
80
- return api(`pipeline-status?${params.toString()}`);
81
+ const q = params.toString();
82
+ return api(q ? `pipeline-status?${q}` : "pipeline-status");
81
83
  },
82
84
  };
@@ -892,7 +892,9 @@ function pipelineChipMeta(pipelineState) {
892
892
  icon: "cloud_off",
893
893
  className: "pipeline-chip pipeline-idle",
894
894
  spinning: false,
895
- title: "STUDIO_CONTENT_WORKFLOW is not set on the Studio API",
895
+ title:
896
+ state.pipeline.message ||
897
+ "Set pandorga.content.workflow in _config.yml (e.g. content-pipeline.yml)",
896
898
  };
897
899
  default:
898
900
  return {
@@ -940,6 +942,38 @@ function renderPipelineChip() {
940
942
  );
941
943
  }
942
944
 
945
+ function applyPipelinePayload(data) {
946
+ state.pipeline.runUrl = data.run?.html_url || state.pipeline.runUrl || "";
947
+ if (data.sha) state.pipeline.sha = String(data.sha).toLowerCase();
948
+ state.pipeline.message = "";
949
+ if (data.state === "unconfigured") {
950
+ state.pipeline.state = "unconfigured";
951
+ state.pipeline.message =
952
+ data.message ||
953
+ "Set pandorga.content.workflow in _config.yml (e.g. content-pipeline.yml)";
954
+ return;
955
+ }
956
+ state.pipeline.state = data.state || "idle";
957
+ if (data.state === "error") {
958
+ state.pipeline.message =
959
+ data.message || "Content pipeline failed for this commit.";
960
+ }
961
+ }
962
+
963
+ /** Hydrate the always-visible chip from the latest workflow run (or a SHA). */
964
+ async function refreshPipelineStatus(sha = null) {
965
+ if (isLocalDevHost()) return;
966
+ try {
967
+ const data = await studioApi.pipelineStatus(sha || null);
968
+ applyPipelinePayload(data);
969
+ renderShell();
970
+ } catch (err) {
971
+ state.pipeline.state = "error";
972
+ state.pipeline.message = String(err.message || err);
973
+ renderShell();
974
+ }
975
+ }
976
+
943
977
  /**
944
978
  * After a production Save, poll Actions for the content-pipeline run on this SHA.
945
979
  */
@@ -976,32 +1010,17 @@ async function pollPipelineStatus(gen, sha) {
976
1010
  const data = await studioApi.pipelineStatus(sha);
977
1011
  if (gen !== state.pipeline.pollGen) return;
978
1012
  softFails = 0;
979
- state.pipeline.runUrl = data.run?.html_url || state.pipeline.runUrl || "";
980
- state.pipeline.message = "";
1013
+ applyPipelinePayload(data);
981
1014
 
982
- if (data.state === "unconfigured") {
983
- state.pipeline.state = "unconfigured";
1015
+ if (data.state === "unconfigured" || data.state === "ok" || data.state === "error") {
984
1016
  renderShell();
985
1017
  return;
986
1018
  }
987
- if (data.state === "ok" || data.state === "error") {
988
- state.pipeline.state = data.state;
989
- if (data.state === "error") {
990
- state.pipeline.message = "Content pipeline failed for this commit.";
991
- }
1019
+ if (data.state === "awaiting_run" && elapsed > STALL_MS) {
1020
+ state.pipeline.state = "stalled";
992
1021
  renderShell();
993
1022
  return;
994
1023
  }
995
- if (data.state === "running") {
996
- state.pipeline.state = "running";
997
- } else if (data.state === "awaiting_run") {
998
- if (elapsed > STALL_MS) {
999
- state.pipeline.state = "stalled";
1000
- renderShell();
1001
- return;
1002
- }
1003
- state.pipeline.state = "awaiting_run";
1004
- }
1005
1024
  renderShell();
1006
1025
  } catch (err) {
1007
1026
  if (gen !== state.pipeline.pollGen) return;
@@ -1114,8 +1133,35 @@ function renderStudioToolbar({ brand = null, menuToggle = null } = {}) {
1114
1133
  : null,
1115
1134
  ]);
1116
1135
 
1117
- const actions = [
1118
- renderThemeMenu(),
1136
+ const actions = [renderThemeMenu()];
1137
+
1138
+ // Theme → pipeline/Export → Revert → Save. Pipeline chip is always present.
1139
+ if (isLocalDevHost()) {
1140
+ const exportBusy = state.reexporting || state.pipeline.state === "syncing";
1141
+ actions.push(
1142
+ toolbarActionButton({
1143
+ className:
1144
+ "btn btn-tool btn-reexport" +
1145
+ (exportBusy ? " pipeline-running" : "") +
1146
+ (state.pipeline.state === "ok" && !exportBusy ? " pipeline-ok" : "") +
1147
+ (state.pipeline.state === "error" && !exportBusy ? " pipeline-error" : ""),
1148
+ title: exportBusy
1149
+ ? "Exporting content JSON locally"
1150
+ : "Export content JSON locally and reload",
1151
+ ariaLabel: exportBusy ? "Exporting locally" : "Export locally",
1152
+ action: "reexport",
1153
+ disabled: exportBusy,
1154
+ onClick: () => reexportLocalContent(),
1155
+ icon: exportBusy ? "progress_activity" : "sync",
1156
+ label: exportBusy ? "Exporting…" : "Export",
1157
+ spinning: exportBusy,
1158
+ })
1159
+ );
1160
+ } else {
1161
+ actions.push(renderPipelineChip());
1162
+ }
1163
+
1164
+ actions.push(
1119
1165
  toolbarActionButton({
1120
1166
  className: "btn btn-tool",
1121
1167
  title: "Revert all edits to the last loaded or saved version",
@@ -1140,45 +1186,8 @@ function renderStudioToolbar({ brand = null, menuToggle = null } = {}) {
1140
1186
  icon: saveIcon,
1141
1187
  label: saveLabel,
1142
1188
  spinning: state.saving,
1143
- }),
1144
- ];
1145
- if (state.file && collectionAllowsDelete()) {
1146
- actions.push(
1147
- toolbarActionButton({
1148
- className: "btn btn-tool btn-danger",
1149
- title: "Delete this entry from the repository",
1150
- ariaLabel: "Delete entry",
1151
- action: "delete",
1152
- onClick: () => deleteCurrentEntry(),
1153
- icon: "delete",
1154
- label: "Delete",
1155
- })
1156
- );
1157
- }
1158
- if (isLocalDevHost()) {
1159
- const exportBusy = state.reexporting || state.pipeline.state === "syncing";
1160
- actions.push(
1161
- toolbarActionButton({
1162
- className:
1163
- "btn btn-tool btn-reexport" +
1164
- (exportBusy ? " pipeline-running" : "") +
1165
- (state.pipeline.state === "ok" && !exportBusy ? " pipeline-ok" : "") +
1166
- (state.pipeline.state === "error" && !exportBusy ? " pipeline-error" : ""),
1167
- title: exportBusy
1168
- ? "Exporting content JSON locally"
1169
- : "Export content JSON locally and reload",
1170
- ariaLabel: exportBusy ? "Exporting locally" : "Export locally",
1171
- action: "reexport",
1172
- disabled: exportBusy,
1173
- onClick: () => reexportLocalContent(),
1174
- icon: exportBusy ? "progress_activity" : "sync",
1175
- label: exportBusy ? "Exporting…" : "Export",
1176
- spinning: exportBusy,
1177
- })
1178
- );
1179
- } else if (state.pipeline.state !== "idle") {
1180
- actions.push(renderPipelineChip());
1181
- }
1189
+ })
1190
+ );
1182
1191
 
1183
1192
  const kids = [
1184
1193
  brandCluster,
@@ -4257,6 +4266,7 @@ async function bootApp(clerk) {
4257
4266
  }
4258
4267
 
4259
4268
  renderShell();
4269
+ void refreshPipelineStatus();
4260
4270
 
4261
4271
  scheduleTreePrefetch();
4262
4272
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pandorga
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.4
4
+ version: 1.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Pandorga contributors
@@ -412,6 +412,7 @@ files:
412
412
  - scripts/test/test-studio-api-contract.rb
413
413
  - scripts/test/test-studio-content-files.rb
414
414
  - scripts/test/test-studio-liquid-roundtrip.mjs
415
+ - scripts/test/test-studio-pipeline-config.mjs
415
416
  - scripts/test/test-studio-rate-limit.mjs
416
417
  - scripts/test/test-studio-rewrite-api-contract.rb
417
418
  - scripts/test/test-studio-rewrite-sanitize.mjs
@@ -449,8 +450,8 @@ files:
449
450
  - studio-app/src/preview/render.js
450
451
  - studio-app/src/styles/studio.css
451
452
  - studio-app/vite.config.js
453
+ - studio/assets/index-CMVzh8F1.js
452
454
  - studio/assets/index-Cd1mlY_H.css
453
- - studio/assets/index-Cf9OPjQU.js
454
455
  - studio/index.html
455
456
  - studio/schema.yml
456
457
  - templates/articles/README.md