@tailor-platform/sdk 1.68.0 → 1.70.0
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 +105 -0
- package/dist/application-BakHtldG.mjs +4 -0
- package/dist/application-Df5_I83n.mjs +6432 -0
- package/dist/application-Df5_I83n.mjs.map +1 -0
- package/dist/cli/erd-viewer-assets/app.js +279 -36
- package/dist/cli/erd-viewer-assets/index.html +4 -0
- package/dist/cli/erd-viewer-assets/styles.css +252 -5
- package/dist/cli/index.mjs +650 -98
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +247 -160
- package/dist/cli/lib.mjs +3 -3
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/skills.mjs +1 -1
- package/dist/completion/zsh-worker.zsh +175 -24
- package/dist/configure/index.d.mts +5 -5
- package/dist/configure/index.mjs +12 -6
- package/dist/configure/index.mjs.map +1 -1
- package/dist/{crashreport-u9y2npiy.mjs → crashreport-BqyvFk-_.mjs} +2 -2
- package/dist/{crashreport-u9y2npiy.mjs.map → crashreport-BqyvFk-_.mjs.map} +1 -1
- package/dist/{crashreport-6jpCceOF.mjs → crashreport-BwF8cHF0.mjs} +1 -1
- package/dist/enum-constants-C7DaWeQo.mjs.map +1 -1
- package/dist/field-C4zdJLW5.mjs.map +1 -1
- package/dist/file-utils-BHPxPXmn.mjs.map +1 -1
- package/dist/{idp-BlBPtXJ-.d.mts → idp-BmYwCXnJ.d.mts} +30 -3
- package/dist/{idp-BZPqpcYY.mjs → idp-ynUfzwpz.mjs} +9 -1
- package/dist/idp-ynUfzwpz.mjs.map +1 -0
- package/dist/{index-DvEUb3pX.d.mts → index-BAEaAqmz.d.mts} +112 -53
- package/dist/{index-CklcVeMG.d.mts → index-C-vsbx27.d.mts} +2 -2
- package/dist/{index-hXoO-AOC.d.mts → index-CKI0eZP6.d.mts} +2 -2
- package/dist/{index-DYhnxXYR.d.mts → index-CrqOgUF2.d.mts} +2 -2
- package/dist/{index-DlDRSzFZ.d.mts → index-DESLU9kI.d.mts} +2 -2
- package/dist/{index-DRhMpdnA.d.mts → index-dKNk8hjo.d.mts} +2 -2
- package/dist/job-BpsFXPbi.mjs.map +1 -1
- package/dist/{kysely-type-D1e0Vwkd.mjs → kysely-type-CSoZxVKN.mjs} +2 -2
- package/dist/{kysely-type-D1e0Vwkd.mjs.map → kysely-type-CSoZxVKN.mjs.map} +1 -1
- package/dist/{logger-DpJyJvNz.mjs → logger-DKF-JsAK.mjs} +3 -3
- package/dist/{logger-DpJyJvNz.mjs.map → logger-DKF-JsAK.mjs.map} +1 -1
- package/dist/{mock-DMgIygjE.mjs → mock-wf5qeZLi.mjs} +19 -9
- package/dist/mock-wf5qeZLi.mjs.map +1 -0
- package/dist/plugin/builtin/enum-constants/index.d.mts +1 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +1 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/index.d.mts +1 -1
- package/dist/plugin/index.d.mts +1 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/registry-D0uB0OrK.mjs.map +1 -1
- package/dist/{repl-editor-CJG3sz7A.mjs → repl-editor-DD5YP5mt.mjs} +4 -4
- package/dist/{repl-editor-CJG3sz7A.mjs.map → repl-editor-DD5YP5mt.mjs.map} +1 -1
- package/dist/runtime/globals.d.mts +3 -2
- package/dist/runtime/idp.d.mts +2 -2
- package/dist/runtime/idp.mjs +1 -1
- package/dist/runtime/index.d.mts +2 -2
- package/dist/runtime/index.mjs +1 -1
- package/dist/{runtime-DxaBq6U8.mjs → runtime-CSY0eD4_.mjs} +411 -221
- package/dist/runtime-CSY0eD4_.mjs.map +1 -0
- package/dist/{schema-1msIhXwA.mjs → schema-C4fkpWV_.mjs} +9 -15
- package/dist/schema-C4fkpWV_.mjs.map +1 -0
- package/dist/seed-YAbtMy65.mjs.map +1 -1
- package/dist/{service-wI3Hvrgx.mjs → service-B2Jd9CxS.mjs} +2 -2
- package/dist/service-B2Jd9CxS.mjs.map +1 -0
- package/dist/service-CRaa4Joe.mjs +4 -0
- package/dist/{service-DMohAx8a.mjs → service-DDWgZL_L2.mjs} +2 -2
- package/dist/service-DDWgZL_L2.mjs.map +1 -0
- package/dist/service_pb-DGSmn-aF.mjs +4 -0
- package/dist/{application-WpWwTyk9.mjs → service_pb-DSNjrcbW.mjs} +22 -6176
- package/dist/service_pb-DSNjrcbW.mjs.map +1 -0
- package/dist/telemetry-BQbbVo2t.mjs.map +1 -1
- package/dist/{types-2Be3wSMc.mjs → types-32lUMToj.mjs} +1 -1
- package/dist/{types-CmzfQP_m.mjs → types-D4QMmNWh.mjs} +1 -12
- package/dist/types-D4QMmNWh.mjs.map +1 -0
- package/dist/{types-Bzr0RQME.d.mts → types-Dynq4AJv.d.mts} +2 -2
- package/dist/{types-DZrtN6-H.d.mts → types-rj8YJcEe.d.mts} +5 -2
- package/dist/utils/test/index.d.mts +2 -2
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/environment.mjs +1 -1
- package/dist/vitest/environment.mjs.map +1 -1
- package/dist/vitest/index.mjs +4 -4
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/setup.mjs +1 -1
- package/dist/{workflow.generated-1S50BhEb.d.mts → workflow.generated-DJULCuRr.d.mts} +274 -174
- package/docs/cli/application.md +39 -201
- package/docs/cli/auth.md +12 -256
- package/docs/cli/completion.md +0 -24
- package/docs/cli/crashreport.md +0 -58
- package/docs/cli/executor.md +2 -166
- package/docs/cli/function.md +2 -118
- package/docs/cli/organization.md +1 -211
- package/docs/cli/query.md +0 -20
- package/docs/cli/secret.md +70 -250
- package/docs/cli/setup.md +2 -41
- package/docs/cli/skills.md +0 -39
- package/docs/cli/staticwebsite.md +24 -172
- package/docs/cli/tailordb.md +25 -251
- package/docs/cli/upgrade.md +0 -20
- package/docs/cli/user.md +41 -246
- package/docs/cli/workflow.md +30 -189
- package/docs/cli/workspace.md +164 -537
- package/docs/cli-reference.md +61 -37
- package/docs/configuration.md +7 -1
- package/docs/github-actions.md +27 -0
- package/docs/multi-environment.md +22 -0
- package/docs/services/aigateway.md +4 -2
- package/docs/services/http-adapter.md +16 -1
- package/docs/services/idp.md +55 -2
- package/docs/services/staticwebsite.md +7 -1
- package/package.json +23 -18
- package/dist/application-Djeezk3m.mjs +0 -4
- package/dist/application-WpWwTyk9.mjs.map +0 -1
- package/dist/idp-BZPqpcYY.mjs.map +0 -1
- package/dist/mock-DMgIygjE.mjs.map +0 -1
- package/dist/runtime-DxaBq6U8.mjs.map +0 -1
- package/dist/schema-1msIhXwA.mjs.map +0 -1
- package/dist/service-BHQIerYh.mjs +0 -4
- package/dist/service-DMohAx8a.mjs.map +0 -1
- package/dist/service-wI3Hvrgx.mjs.map +0 -1
- package/dist/types-CmzfQP_m.mjs.map +0 -1
|
@@ -13,6 +13,7 @@ const FIT_PADDING = 80;
|
|
|
13
13
|
const MIN_ZOOM = 0.25;
|
|
14
14
|
const MAX_ZOOM = 2.2;
|
|
15
15
|
const DEFAULT_SHOW_MODE = "TABLE_NAME";
|
|
16
|
+
const DEFAULT_VIEW_MODE = "diff";
|
|
16
17
|
const SHOW_MODE_OPTIONS = [
|
|
17
18
|
{ value: "ALL_FIELDS", label: "All Fields" },
|
|
18
19
|
{ value: "TABLE_NAME", label: "Table Name" },
|
|
@@ -40,10 +41,17 @@ const elements = {
|
|
|
40
41
|
fitView: document.getElementById("fit-view"),
|
|
41
42
|
showMode: document.getElementById("show-mode"),
|
|
42
43
|
showModeMenu: document.getElementById("show-mode-menu"),
|
|
44
|
+
viewModeControl: document.getElementById("view-mode-control"),
|
|
45
|
+
viewModeCurrent: document.getElementById("view-mode-current"),
|
|
46
|
+
viewModeDiff: document.getElementById("view-mode-diff"),
|
|
43
47
|
copyLink: document.getElementById("copy-link"),
|
|
44
48
|
};
|
|
45
49
|
|
|
46
50
|
let schema;
|
|
51
|
+
let diffViewSchema;
|
|
52
|
+
let currentViewSchema;
|
|
53
|
+
let diffMetadata;
|
|
54
|
+
let erdDiff;
|
|
47
55
|
let layout;
|
|
48
56
|
let selectedTable;
|
|
49
57
|
let searchText = "";
|
|
@@ -56,8 +64,29 @@ let activeCardDrag;
|
|
|
56
64
|
let activeCanvasPan;
|
|
57
65
|
let activeViewportAnimation;
|
|
58
66
|
let suppressNextCanvasClick = false;
|
|
67
|
+
let viewMode = DEFAULT_VIEW_MODE;
|
|
59
68
|
const manualNodePositions = new Map();
|
|
60
69
|
const hiddenTableNames = new Set();
|
|
70
|
+
let diffIndex = new Map();
|
|
71
|
+
let tableDiffIndex = new Map();
|
|
72
|
+
|
|
73
|
+
const DIFF_LABELS = {
|
|
74
|
+
added: "Added",
|
|
75
|
+
changed: "Changed",
|
|
76
|
+
removed: "Removed",
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const DIFF_MARKS = {
|
|
80
|
+
added: "+",
|
|
81
|
+
changed: "~",
|
|
82
|
+
removed: "-",
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const DIFF_ACTION_RANK = {
|
|
86
|
+
added: 2,
|
|
87
|
+
changed: 1,
|
|
88
|
+
removed: 3,
|
|
89
|
+
};
|
|
61
90
|
|
|
62
91
|
function escapeHtml(value) {
|
|
63
92
|
return String(value ?? "")
|
|
@@ -75,6 +104,102 @@ function tableByName(name) {
|
|
|
75
104
|
return schema?.tables.find((table) => table.name === name);
|
|
76
105
|
}
|
|
77
106
|
|
|
107
|
+
function strongestDiffAction(current, next) {
|
|
108
|
+
if (!current) return next;
|
|
109
|
+
if (!next) return current;
|
|
110
|
+
return DIFF_ACTION_RANK[next] > DIFF_ACTION_RANK[current] ? next : current;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function diffKey(entity, path) {
|
|
114
|
+
return `${entity}:${path}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function diffChange(entity, path) {
|
|
118
|
+
return diffIndex.get(diffKey(entity, path));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function setTableDiffAction(tableName, action) {
|
|
122
|
+
if (!tableName || !action) return;
|
|
123
|
+
tableDiffIndex.set(tableName, strongestDiffAction(tableDiffIndex.get(tableName), action));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function tableNameFromEntityPath(path) {
|
|
127
|
+
return path.split(".")[0];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function tableNamesFromRelationChange(change) {
|
|
131
|
+
const relation = schema?.relations.find((item) => item.name === change.path);
|
|
132
|
+
if (relation) return [relation.sourceTable, relation.targetTable];
|
|
133
|
+
|
|
134
|
+
const [source, target] = change.path.split("->");
|
|
135
|
+
return [tableNameFromEntityPath(source || ""), tableNameFromEntityPath(target || "")].filter(
|
|
136
|
+
Boolean,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function setDiff(nextDiff) {
|
|
141
|
+
erdDiff = nextDiff;
|
|
142
|
+
diffIndex = new Map();
|
|
143
|
+
tableDiffIndex = new Map();
|
|
144
|
+
if (!nextDiff?.changes) return;
|
|
145
|
+
|
|
146
|
+
for (const change of nextDiff.changes) {
|
|
147
|
+
diffIndex.set(diffKey(change.entity, change.path), change);
|
|
148
|
+
if (change.entity === "table") {
|
|
149
|
+
setTableDiffAction(change.path, change.action);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (change.entity === "column" || change.entity === "index") {
|
|
153
|
+
setTableDiffAction(tableNameFromEntityPath(change.path), "changed");
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (change.entity === "relation") {
|
|
157
|
+
for (const tableName of tableNamesFromRelationChange(change)) {
|
|
158
|
+
setTableDiffAction(tableName, "changed");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function diffClass(action) {
|
|
165
|
+
return action ? `is-diff-${action}` : "";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function diffBadge(action, detail) {
|
|
169
|
+
if (!action) return "";
|
|
170
|
+
const title = detail ? `${DIFF_LABELS[action]}: ${detail}` : DIFF_LABELS[action];
|
|
171
|
+
return `<span class="diff-badge diff-badge-${action}" title="${escapeHtml(title)}">${DIFF_MARKS[action]}</span>`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function diffDetail(change) {
|
|
175
|
+
if (!change?.detail) return "";
|
|
176
|
+
return `<span class="diff-detail">${escapeHtml(change.detail)}</span>`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function tableDiffChange(tableName) {
|
|
180
|
+
return diffChange("table", tableName);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function tableDiffAction(tableName) {
|
|
184
|
+
return tableDiffIndex.get(tableName);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function columnDiffChange(tableName, columnName) {
|
|
188
|
+
return diffChange("column", `${tableName}.${columnName}`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function indexDiffChange(tableName, indexName) {
|
|
192
|
+
return diffChange("index", `${tableName}.${indexName}`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function relationDiffChange(relation) {
|
|
196
|
+
return diffChange("relation", relation.name);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function relationDiffAction(relation) {
|
|
200
|
+
return relationDiffChange(relation)?.action;
|
|
201
|
+
}
|
|
202
|
+
|
|
78
203
|
function showModeOption(value) {
|
|
79
204
|
return SHOW_MODE_OPTIONS.find((option) => option.value === value);
|
|
80
205
|
}
|
|
@@ -98,6 +223,10 @@ function readHashState() {
|
|
|
98
223
|
if (showModeOption(nextShowMode)) {
|
|
99
224
|
showMode = nextShowMode;
|
|
100
225
|
}
|
|
226
|
+
const nextViewMode = params.get("view");
|
|
227
|
+
if (nextViewMode === "current" || nextViewMode === "diff") {
|
|
228
|
+
viewMode = nextViewMode;
|
|
229
|
+
}
|
|
101
230
|
hiddenTableNames.clear();
|
|
102
231
|
for (const tableName of (params.get("hidden") || "").split(",")) {
|
|
103
232
|
if (tableName) hiddenTableNames.add(tableName);
|
|
@@ -117,6 +246,9 @@ function writeHashState() {
|
|
|
117
246
|
if (hiddenTableNames.size > 0) {
|
|
118
247
|
params.set("hidden", [...hiddenTableNames].toSorted((a, b) => a.localeCompare(b)).join(","));
|
|
119
248
|
}
|
|
249
|
+
if (canSwitchViewMode() && viewMode !== DEFAULT_VIEW_MODE) {
|
|
250
|
+
params.set("view", viewMode);
|
|
251
|
+
}
|
|
120
252
|
params.set("z", viewport.z.toFixed(3));
|
|
121
253
|
try {
|
|
122
254
|
history.replaceState(null, "", `#${params.toString()}`);
|
|
@@ -130,11 +262,9 @@ function writeHashState() {
|
|
|
130
262
|
const SCHEMA_BLOCK_PATTERN =
|
|
131
263
|
/<script type="application\/json" id="erd-schema">([\s\S]*?)<\/script>/;
|
|
132
264
|
|
|
133
|
-
|
|
134
|
-
// document (the viewer is always a self-contained HTML).
|
|
135
|
-
function embeddedSchema() {
|
|
265
|
+
function embeddedJson(id) {
|
|
136
266
|
if (typeof document === "undefined") return undefined;
|
|
137
|
-
const element = document.getElementById(
|
|
267
|
+
const element = document.getElementById(id);
|
|
138
268
|
if (!element) return undefined;
|
|
139
269
|
try {
|
|
140
270
|
return JSON.parse(element.textContent);
|
|
@@ -143,6 +273,20 @@ function embeddedSchema() {
|
|
|
143
273
|
}
|
|
144
274
|
}
|
|
145
275
|
|
|
276
|
+
// Read the schema from the embedded `#erd-schema` data block in the current
|
|
277
|
+
// document (the viewer is always a self-contained HTML).
|
|
278
|
+
function embeddedSchema() {
|
|
279
|
+
return embeddedJson("erd-schema");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function embeddedDiff() {
|
|
283
|
+
return embeddedJson("erd-diff");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function embeddedCurrentSchema() {
|
|
287
|
+
return embeddedJson("erd-current-schema");
|
|
288
|
+
}
|
|
289
|
+
|
|
146
290
|
// Re-fetch the served HTML and extract its embedded schema. Used by watch mode
|
|
147
291
|
// to pick up rebuilds without a separate schema.json.
|
|
148
292
|
async function fetchServedSchema() {
|
|
@@ -297,8 +441,10 @@ function eyeIcon(hidden) {
|
|
|
297
441
|
}
|
|
298
442
|
|
|
299
443
|
function renderHeader() {
|
|
300
|
-
elements.namespace.textContent = schema.namespace;
|
|
301
|
-
elements.revision.textContent =
|
|
444
|
+
elements.namespace.textContent = erdDiff ? `${schema.namespace} diff` : schema.namespace;
|
|
445
|
+
elements.revision.textContent = erdDiff
|
|
446
|
+
? `${schema.tables.length} tables / ${schema.relations.length} relations / +${erdDiff.summary.added} ~${erdDiff.summary.changed} -${erdDiff.summary.removed} / ${erdDiff.baseRevision} -> ${erdDiff.headRevision}`
|
|
447
|
+
: `${schema.tables.length} tables / ${schema.relations.length} relations / ${schema.revision}`;
|
|
302
448
|
const visibleCount = visibleTables().length;
|
|
303
449
|
elements.tableSummary.textContent =
|
|
304
450
|
visibleCount === schema.tables.length
|
|
@@ -318,8 +464,10 @@ function renderTableList() {
|
|
|
318
464
|
.map((table) => {
|
|
319
465
|
const hidden = isTableHidden(table.name);
|
|
320
466
|
const visibilityLabel = hidden ? "Show" : "Hide";
|
|
467
|
+
const change = tableDiffChange(table.name);
|
|
468
|
+
const action = tableDiffAction(table.name);
|
|
321
469
|
return `
|
|
322
|
-
<div class="table-list-row ${hidden ? "is-hidden" : ""}">
|
|
470
|
+
<div class="table-list-row ${hidden ? "is-hidden" : ""} ${diffClass(action)}">
|
|
323
471
|
<button
|
|
324
472
|
type="button"
|
|
325
473
|
class="table-select"
|
|
@@ -327,7 +475,10 @@ function renderTableList() {
|
|
|
327
475
|
aria-current="${table.name === selectedTable}"
|
|
328
476
|
>
|
|
329
477
|
<span class="table-list-icon" aria-hidden="true"></span>
|
|
330
|
-
<span
|
|
478
|
+
<span class="table-list-label">
|
|
479
|
+
<span class="table-list-name">${escapeHtml(table.name)}</span>
|
|
480
|
+
${diffBadge(action, change?.detail)}
|
|
481
|
+
</span>
|
|
331
482
|
</button>
|
|
332
483
|
<button
|
|
333
484
|
type="button"
|
|
@@ -363,14 +514,19 @@ function tableFieldRows(table) {
|
|
|
363
514
|
return `
|
|
364
515
|
<div class="table-fields">
|
|
365
516
|
${columns
|
|
366
|
-
.map(
|
|
367
|
-
(column)
|
|
368
|
-
|
|
369
|
-
|
|
517
|
+
.map((column) => {
|
|
518
|
+
const change = columnDiffChange(table.name, column.name);
|
|
519
|
+
const action = change?.action;
|
|
520
|
+
return `
|
|
521
|
+
<div class="table-field ${isKeyColumn(column) ? "is-key" : ""} ${diffClass(action)}">
|
|
522
|
+
<span class="field-name">
|
|
523
|
+
<span class="field-name-text">${escapeHtml(column.name)}</span>
|
|
524
|
+
${diffBadge(action, change?.detail)}
|
|
525
|
+
</span>
|
|
370
526
|
<span class="field-type">${escapeHtml(column.type)}${column.array ? "[]" : ""}</span>
|
|
371
527
|
</div>
|
|
372
|
-
|
|
373
|
-
)
|
|
528
|
+
`;
|
|
529
|
+
})
|
|
374
530
|
.join("")}
|
|
375
531
|
</div>
|
|
376
532
|
`;
|
|
@@ -383,10 +539,12 @@ function renderNodes() {
|
|
|
383
539
|
const node = layout.nodes.get(table.name);
|
|
384
540
|
const related = isTableRelatedToSelection(table.name);
|
|
385
541
|
const muted = !matchesSearch(table) || !related;
|
|
542
|
+
const change = tableDiffChange(table.name);
|
|
543
|
+
const action = tableDiffAction(table.name);
|
|
386
544
|
return `
|
|
387
545
|
<button
|
|
388
546
|
type="button"
|
|
389
|
-
class="table-card ${table.name === selectedTable ? "is-selected" : ""} ${related ? "is-related" : ""} ${muted ? "is-muted" : ""}"
|
|
547
|
+
class="table-card ${table.name === selectedTable ? "is-selected" : ""} ${related ? "is-related" : ""} ${muted ? "is-muted" : ""} ${diffClass(action)}"
|
|
390
548
|
data-table="${escapeHtml(table.name)}"
|
|
391
549
|
aria-label="Focus table ${escapeHtml(table.name)}"
|
|
392
550
|
aria-pressed="${table.name === selectedTable}"
|
|
@@ -394,7 +552,10 @@ function renderNodes() {
|
|
|
394
552
|
>
|
|
395
553
|
<div class="table-head">
|
|
396
554
|
<span class="table-icon" aria-hidden="true"></span>
|
|
397
|
-
<div class="table-name"
|
|
555
|
+
<div class="table-name-wrap">
|
|
556
|
+
<div class="table-name">${escapeHtml(table.name)}</div>
|
|
557
|
+
${diffBadge(action, change?.detail)}
|
|
558
|
+
</div>
|
|
398
559
|
</div>
|
|
399
560
|
${tableFieldRows(table)}
|
|
400
561
|
</button>
|
|
@@ -547,7 +708,7 @@ function oneMarker(x, y) {
|
|
|
547
708
|
`;
|
|
548
709
|
}
|
|
549
710
|
|
|
550
|
-
function cardinalityMarker(cardinality, point, sideSign, selected) {
|
|
711
|
+
function cardinalityMarker(cardinality, point, sideSign, selected, action) {
|
|
551
712
|
const crowFootTip = CROW_FOOT_TIP_OFFSET;
|
|
552
713
|
const crowFootJoin = CROW_FOOT_JOIN_OFFSET;
|
|
553
714
|
const outer = CARDINALITY_OUTER_OFFSET;
|
|
@@ -578,7 +739,7 @@ function cardinalityMarker(cardinality, point, sideSign, selected) {
|
|
|
578
739
|
}
|
|
579
740
|
|
|
580
741
|
return `
|
|
581
|
-
<g class="edge-cardinality ${selected ? "is-selected" : ""}">
|
|
742
|
+
<g class="edge-cardinality ${selected ? "is-selected" : ""} ${diffClass(action)}">
|
|
582
743
|
${parts.join("")}
|
|
583
744
|
</g>
|
|
584
745
|
`;
|
|
@@ -599,10 +760,11 @@ function renderEdges() {
|
|
|
599
760
|
const geometry = edgeGeometry(source, target);
|
|
600
761
|
const cardinality = relationCardinality(relation);
|
|
601
762
|
const direction = geometry.sourceRight ? 1 : -1;
|
|
763
|
+
const action = relationDiffAction(relation);
|
|
602
764
|
return `
|
|
603
|
-
<path class="edge ${selected ? "is-selected" : ""}" d="${geometry.d}"></path>
|
|
604
|
-
${cardinalityMarker(cardinality.source, geometry.sourceNodePoint, direction, selected)}
|
|
605
|
-
${cardinalityMarker(cardinality.target, geometry.targetNodePoint, -direction, selected)}
|
|
765
|
+
<path class="edge ${selected ? "is-selected" : ""} ${diffClass(action)}" d="${geometry.d}"></path>
|
|
766
|
+
${cardinalityMarker(cardinality.source, geometry.sourceNodePoint, direction, selected, action)}
|
|
767
|
+
${cardinalityMarker(cardinality.target, geometry.targetNodePoint, -direction, selected, action)}
|
|
606
768
|
`;
|
|
607
769
|
})
|
|
608
770
|
.join("");
|
|
@@ -621,7 +783,18 @@ function relationRows(table, direction) {
|
|
|
621
783
|
direction === "out"
|
|
622
784
|
? `${relation.sourceColumns.join(", ")} -> ${relation.targetTable}.${relation.targetColumns.join(", ")}`
|
|
623
785
|
: `${relation.sourceTable}.${relation.sourceColumns.join(", ")} -> ${relation.targetColumns.join(", ")}`;
|
|
624
|
-
|
|
786
|
+
const change = relationDiffChange(relation);
|
|
787
|
+
const action = change?.action;
|
|
788
|
+
return `<div class="detail-row ${diffClass(action)}">
|
|
789
|
+
<div>
|
|
790
|
+
<span class="detail-name">
|
|
791
|
+
<strong>${escapeHtml(label)}</strong>
|
|
792
|
+
${diffBadge(action, change?.detail)}
|
|
793
|
+
</span>
|
|
794
|
+
${diffDetail(change)}
|
|
795
|
+
</div>
|
|
796
|
+
<code>${escapeHtml(relation.kind)}</code>
|
|
797
|
+
</div>`;
|
|
625
798
|
})
|
|
626
799
|
.join("")}
|
|
627
800
|
</div>
|
|
@@ -654,13 +827,22 @@ function renderDetails() {
|
|
|
654
827
|
return;
|
|
655
828
|
}
|
|
656
829
|
|
|
830
|
+
const tableChange = tableDiffChange(table.name);
|
|
831
|
+
const tableAction = tableDiffAction(table.name);
|
|
657
832
|
elements.details.hidden = false;
|
|
658
833
|
elements.main.classList.remove("is-details-collapsed");
|
|
659
834
|
elements.details.innerHTML = `
|
|
660
835
|
<div class="details-inner">
|
|
661
836
|
<section>
|
|
662
|
-
<h2
|
|
837
|
+
<h2>
|
|
838
|
+
<span class="table-icon" aria-hidden="true"></span>
|
|
839
|
+
<span class="detail-name">
|
|
840
|
+
<span>${escapeHtml(table.name)}</span>
|
|
841
|
+
${diffBadge(tableAction, tableChange?.detail)}
|
|
842
|
+
</span>
|
|
843
|
+
</h2>
|
|
663
844
|
<p>${escapeHtml(table.description || table.pluralForm)}</p>
|
|
845
|
+
${diffDetail(tableChange)}
|
|
664
846
|
</section>
|
|
665
847
|
<section class="details-section">
|
|
666
848
|
<h3>Outgoing Relations</h3>
|
|
@@ -674,18 +856,24 @@ function renderDetails() {
|
|
|
674
856
|
<h3>Columns</h3>
|
|
675
857
|
<div class="detail-list">
|
|
676
858
|
${table.columns
|
|
677
|
-
.map(
|
|
678
|
-
(column)
|
|
679
|
-
|
|
859
|
+
.map((column) => {
|
|
860
|
+
const change = columnDiffChange(table.name, column.name);
|
|
861
|
+
const action = change?.action;
|
|
862
|
+
return `
|
|
863
|
+
<div class="detail-row ${diffClass(action)}">
|
|
680
864
|
<div>
|
|
681
|
-
<
|
|
865
|
+
<span class="detail-name">
|
|
866
|
+
<strong>${escapeHtml(column.name)}</strong>
|
|
867
|
+
${diffBadge(action, change?.detail)}
|
|
868
|
+
</span>
|
|
869
|
+
${diffDetail(change)}
|
|
682
870
|
${column.description ? `<p>${escapeHtml(column.description)}</p>` : ""}
|
|
683
871
|
${columnPills(column)}
|
|
684
872
|
</div>
|
|
685
873
|
<code>${escapeHtml(column.type)}${column.array ? "[]" : ""}</code>
|
|
686
874
|
</div>
|
|
687
|
-
|
|
688
|
-
)
|
|
875
|
+
`;
|
|
876
|
+
})
|
|
689
877
|
.join("")}
|
|
690
878
|
</div>
|
|
691
879
|
</section>
|
|
@@ -695,14 +883,22 @@ function renderDetails() {
|
|
|
695
883
|
<h3>Indexes</h3>
|
|
696
884
|
<div class="detail-list">
|
|
697
885
|
${table.indexes
|
|
698
|
-
.map(
|
|
699
|
-
(index)
|
|
700
|
-
|
|
701
|
-
|
|
886
|
+
.map((index) => {
|
|
887
|
+
const change = indexDiffChange(table.name, index.name);
|
|
888
|
+
const action = change?.action;
|
|
889
|
+
return `
|
|
890
|
+
<div class="detail-row ${diffClass(action)}">
|
|
891
|
+
<div>
|
|
892
|
+
<span class="detail-name">
|
|
893
|
+
<strong>${escapeHtml(index.name)}</strong>
|
|
894
|
+
${diffBadge(action, change?.detail)}
|
|
895
|
+
</span>
|
|
896
|
+
${diffDetail(change)}
|
|
897
|
+
</div>
|
|
702
898
|
<code>${escapeHtml(index.fields.join(", "))}${index.unique ? " unique" : ""}</code>
|
|
703
899
|
</div>
|
|
704
|
-
|
|
705
|
-
)
|
|
900
|
+
`;
|
|
901
|
+
})
|
|
706
902
|
.join("")}
|
|
707
903
|
</div>
|
|
708
904
|
</section>`
|
|
@@ -760,6 +956,43 @@ function renderShowModeControls() {
|
|
|
760
956
|
});
|
|
761
957
|
}
|
|
762
958
|
|
|
959
|
+
function canSwitchViewMode() {
|
|
960
|
+
return Boolean(diffViewSchema && currentViewSchema && diffMetadata);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
function renderViewModeControls() {
|
|
964
|
+
const enabled = canSwitchViewMode();
|
|
965
|
+
elements.viewModeControl.hidden = !enabled;
|
|
966
|
+
if (!enabled) return;
|
|
967
|
+
|
|
968
|
+
elements.viewModeCurrent.setAttribute("aria-pressed", String(viewMode === "current"));
|
|
969
|
+
elements.viewModeDiff.setAttribute("aria-pressed", String(viewMode === "diff"));
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function activateViewMode(nextViewMode) {
|
|
973
|
+
if (nextViewMode === "current" && canSwitchViewMode()) {
|
|
974
|
+
viewMode = "current";
|
|
975
|
+
schema = currentViewSchema;
|
|
976
|
+
setDiff(undefined);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
viewMode = DEFAULT_VIEW_MODE;
|
|
981
|
+
schema = diffViewSchema;
|
|
982
|
+
setDiff(diffMetadata);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
function setViewMode(nextViewMode) {
|
|
986
|
+
if (!canSwitchViewMode() || nextViewMode === viewMode) return;
|
|
987
|
+
|
|
988
|
+
activateViewMode(nextViewMode);
|
|
989
|
+
if (selectedTable && !tableByName(selectedTable)) {
|
|
990
|
+
selectedTable = undefined;
|
|
991
|
+
}
|
|
992
|
+
clearSelectionIfHidden();
|
|
993
|
+
renderAll({ center: false });
|
|
994
|
+
}
|
|
995
|
+
|
|
763
996
|
function setShowModeMenuOpen(open) {
|
|
764
997
|
elements.showMode.setAttribute("aria-expanded", String(open));
|
|
765
998
|
elements.showModeMenu.hidden = !open;
|
|
@@ -932,6 +1165,7 @@ function renderAll(options = {}) {
|
|
|
932
1165
|
renderHeader();
|
|
933
1166
|
renderTableList();
|
|
934
1167
|
renderShowModeControls();
|
|
1168
|
+
renderViewModeControls();
|
|
935
1169
|
renderEdges();
|
|
936
1170
|
renderNodes();
|
|
937
1171
|
renderDetails();
|
|
@@ -1071,6 +1305,8 @@ function wireInteractions() {
|
|
|
1071
1305
|
elements.showMode.addEventListener("click", () => {
|
|
1072
1306
|
setShowModeMenuOpen(elements.showModeMenu.hidden);
|
|
1073
1307
|
});
|
|
1308
|
+
elements.viewModeCurrent.addEventListener("click", () => setViewMode("current"));
|
|
1309
|
+
elements.viewModeDiff.addEventListener("click", () => setViewMode("diff"));
|
|
1074
1310
|
elements.copyLink.addEventListener("click", async () => {
|
|
1075
1311
|
try {
|
|
1076
1312
|
await navigator.clipboard.writeText(location.href);
|
|
@@ -1146,6 +1382,10 @@ function startPolling() {
|
|
|
1146
1382
|
const nextSchema = await fetchServedSchema();
|
|
1147
1383
|
if (nextSchema.revision !== schema.revision) {
|
|
1148
1384
|
schema = nextSchema;
|
|
1385
|
+
diffViewSchema = nextSchema;
|
|
1386
|
+
currentViewSchema = undefined;
|
|
1387
|
+
diffMetadata = undefined;
|
|
1388
|
+
setDiff(undefined);
|
|
1149
1389
|
if (selectedTable && !tableByName(selectedTable)) {
|
|
1150
1390
|
selectedTable = undefined;
|
|
1151
1391
|
}
|
|
@@ -1163,7 +1403,10 @@ async function main() {
|
|
|
1163
1403
|
readHashState();
|
|
1164
1404
|
wireInteractions();
|
|
1165
1405
|
try {
|
|
1166
|
-
|
|
1406
|
+
diffViewSchema = embeddedSchema() ?? (await fetchServedSchema());
|
|
1407
|
+
currentViewSchema = embeddedCurrentSchema();
|
|
1408
|
+
diffMetadata = embeddedDiff();
|
|
1409
|
+
activateViewMode(viewMode);
|
|
1167
1410
|
if (selectedTable && !tableByName(selectedTable)) {
|
|
1168
1411
|
selectedTable = undefined;
|
|
1169
1412
|
}
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
<input id="search" type="search" autocomplete="off" placeholder="Search" />
|
|
21
21
|
</div>
|
|
22
22
|
<div class="toolbar-actions">
|
|
23
|
+
<div id="view-mode-control" class="view-mode-control" aria-label="ERD view mode" hidden>
|
|
24
|
+
<button id="view-mode-current" class="view-mode-button" type="button">Current</button>
|
|
25
|
+
<button id="view-mode-diff" class="view-mode-button" type="button">Diff</button>
|
|
26
|
+
</div>
|
|
23
27
|
<button id="copy-link" class="primary-action" type="button">Copy Link</button>
|
|
24
28
|
</div>
|
|
25
29
|
</header>
|