@hotstaq/admin-panel 0.3.17 → 0.4.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/.gitlab-ci.yml +4 -1
- package/assets/css/freelight-panel.css +174 -0
- package/build/WebExport.d.ts.map +1 -1
- package/build/WebExport.js +7 -1
- package/build/WebExport.js.map +1 -1
- package/build/components/admin-add-panel.d.ts +62 -0
- package/build/components/admin-add-panel.d.ts.map +1 -0
- package/build/components/admin-add-panel.js +191 -0
- package/build/components/admin-add-panel.js.map +1 -0
- package/build/components/admin-card-table.d.ts +55 -0
- package/build/components/admin-card-table.d.ts.map +1 -0
- package/build/components/admin-card-table.js +149 -0
- package/build/components/admin-card-table.js.map +1 -0
- package/build/components/admin-detail-page.d.ts +68 -0
- package/build/components/admin-detail-page.d.ts.map +1 -0
- package/build/components/admin-detail-page.js +247 -0
- package/build/components/admin-detail-page.js.map +1 -0
- package/build/components/admin-disclaimer.d.ts +21 -0
- package/build/components/admin-disclaimer.d.ts.map +1 -0
- package/build/components/admin-disclaimer.js +37 -0
- package/build/components/admin-disclaimer.js.map +1 -0
- package/build/components/admin-eyebrow-heading.d.ts +23 -0
- package/build/components/admin-eyebrow-heading.d.ts.map +1 -0
- package/build/components/admin-eyebrow-heading.js +40 -0
- package/build/components/admin-eyebrow-heading.js.map +1 -0
- package/build/components/admin-form-field.d.ts +69 -0
- package/build/components/admin-form-field.d.ts.map +1 -0
- package/build/components/admin-form-field.js +117 -0
- package/build/components/admin-form-field.js.map +1 -0
- package/build/components/admin-table.d.ts +1 -1
- package/build/components/admin-table.d.ts.map +1 -1
- package/build/components/admin-table.js +13 -12
- package/build/components/admin-table.js.map +1 -1
- package/build/index.d.ts +7 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +16 -1
- package/build/index.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build-web/AdminPanelComponents.js +2 -2
- package/package.json +3 -3
- package/src/WebExport.ts +7 -1
- package/src/components/admin-add-panel.ts +232 -0
- package/src/components/admin-card-table.ts +183 -0
- package/src/components/admin-detail-page.ts +270 -0
- package/src/components/admin-disclaimer.ts +43 -0
- package/src/components/admin-eyebrow-heading.ts +50 -0
- package/src/components/admin-form-field.ts +166 -0
- package/src/components/admin-table.ts +15 -15
- package/src/index.ts +18 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AdminCardTable = void 0;
|
|
13
|
+
const hotstaq_1 = require("hotstaq");
|
|
14
|
+
/**
|
|
15
|
+
* Freelight-style card list. Renders campaign / project / member rows
|
|
16
|
+
* as cards on every viewport, with optional inline action buttons and
|
|
17
|
+
* a sub-line below the primary label.
|
|
18
|
+
*
|
|
19
|
+
* Replaces the click-row-opens-modal flow of <admin-table> + <admin-edit>:
|
|
20
|
+
* when `hot-detail-route` is set, the whole row becomes a link to the
|
|
21
|
+
* configured detail URL (e.g. "/budget/:id"). When `hot-detail-route` is
|
|
22
|
+
* empty, the row renders without navigation — the caller is expected to
|
|
23
|
+
* provide their own inline action buttons via `hot-row-actions`.
|
|
24
|
+
*
|
|
25
|
+
* Usage:
|
|
26
|
+
* <admin-card-table id="bankAccountsList" hot-list-url="/v1/bank_accounts/list"
|
|
27
|
+
* hot-detail-route="/bankAccount/:id"
|
|
28
|
+
* hot-primary-field="name" hot-subline-field="bankSyncAPIType"
|
|
29
|
+
* hot-empty-text="No bank accounts yet.">
|
|
30
|
+
* </admin-card-table>
|
|
31
|
+
*
|
|
32
|
+
* The component exposes a `.refreshList()` method on the rendered DOM
|
|
33
|
+
* element so callers (the paired admin-add-panel, an edit-save callback,
|
|
34
|
+
* etc.) can re-fetch without a page reload.
|
|
35
|
+
*/
|
|
36
|
+
class AdminCardTable extends hotstaq_1.HotComponent {
|
|
37
|
+
constructor(copy, api) {
|
|
38
|
+
super(copy, api);
|
|
39
|
+
this.tag = "admin-card-table";
|
|
40
|
+
this.title = "";
|
|
41
|
+
this.list_url = "";
|
|
42
|
+
this.jwt = "";
|
|
43
|
+
this.list_params = "{}";
|
|
44
|
+
this.primary_field = "name";
|
|
45
|
+
this.subline_field = "";
|
|
46
|
+
this.detail_route = "";
|
|
47
|
+
this.empty_text = "No items yet.";
|
|
48
|
+
this.loading_text = "Loading…";
|
|
49
|
+
this.row_actions = "";
|
|
50
|
+
this.add_slot = "";
|
|
51
|
+
}
|
|
52
|
+
onPostPlace(parentHtmlElement, htmlElement) {
|
|
53
|
+
const self = this;
|
|
54
|
+
const container = document.getElementById(this.name);
|
|
55
|
+
if (container == null)
|
|
56
|
+
return (null);
|
|
57
|
+
// Expose a refreshList() method on the rendered element so the
|
|
58
|
+
// partner add-panel (and any other caller) can re-fetch when a
|
|
59
|
+
// row changes.
|
|
60
|
+
container.refreshList = function () { return self.fetchAndRender(); };
|
|
61
|
+
// Initial load.
|
|
62
|
+
self.fetchAndRender();
|
|
63
|
+
return (null);
|
|
64
|
+
}
|
|
65
|
+
fetchAndRender() {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
const container = document.getElementById(this.name);
|
|
68
|
+
const list = container ? container.querySelector(".fl-card-list") : null;
|
|
69
|
+
if (list == null)
|
|
70
|
+
return;
|
|
71
|
+
try {
|
|
72
|
+
let payload = {};
|
|
73
|
+
try {
|
|
74
|
+
payload = JSON.parse(this.list_params || "{}");
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
payload = {};
|
|
78
|
+
}
|
|
79
|
+
const headers = { "Content-Type": "application/json" };
|
|
80
|
+
if (this.jwt)
|
|
81
|
+
headers["Authorization"] = "Bearer " + this.jwt;
|
|
82
|
+
const res = yield fetch(this.list_url, {
|
|
83
|
+
method: "POST", headers: headers, body: JSON.stringify(payload)
|
|
84
|
+
});
|
|
85
|
+
if (!res.ok) {
|
|
86
|
+
list.innerHTML = `<div class="text-danger small p-3">Could not load: HTTP ${res.status}</div>`;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const result = yield res.json();
|
|
90
|
+
const rows = (result && Array.isArray(result.data)) ? result.data : (Array.isArray(result) ? result : []);
|
|
91
|
+
if (rows.length === 0) {
|
|
92
|
+
list.innerHTML = `<div class="text-muted small text-center py-4">${this.empty_text}</div>`;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
list.innerHTML = rows.map((row) => this.renderRow(row)).join("");
|
|
96
|
+
}
|
|
97
|
+
catch (ex) {
|
|
98
|
+
list.innerHTML = `<div class="text-danger small p-3">Could not load: ${ex.message}</div>`;
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
escapeHtml(s) {
|
|
103
|
+
return String(s == null ? "" : s)
|
|
104
|
+
.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
|
105
|
+
.replace(/"/g, """).replace(/'/g, "'");
|
|
106
|
+
}
|
|
107
|
+
interpolate(template, row) {
|
|
108
|
+
if (!template)
|
|
109
|
+
return "";
|
|
110
|
+
return template.replace(/:(\w+)/g, (_m, key) => this.escapeHtml(row[key] || ""));
|
|
111
|
+
}
|
|
112
|
+
renderRow(row) {
|
|
113
|
+
const primaryRaw = row[this.primary_field];
|
|
114
|
+
const primary = this.escapeHtml(primaryRaw != null && primaryRaw !== "" ? primaryRaw : (row.id || ""));
|
|
115
|
+
const sublineRaw = this.subline_field ? row[this.subline_field] : "";
|
|
116
|
+
const subline = sublineRaw ? `<div class="fl-card-row-sub text-muted small">${this.escapeHtml(sublineRaw)}</div>` : "";
|
|
117
|
+
const inner = `
|
|
118
|
+
<div class="fl-card-row-main">
|
|
119
|
+
<div class="fl-card-row-label">${primary}</div>
|
|
120
|
+
${subline}
|
|
121
|
+
</div>
|
|
122
|
+
<div class="fl-card-row-actions">${this.interpolate(this.row_actions, row)}</div>`;
|
|
123
|
+
if (this.detail_route) {
|
|
124
|
+
const href = this.interpolate(this.detail_route, row);
|
|
125
|
+
return `<a href="${href}" class="fl-card-row fl-card-row-link list-group-item list-group-item-action">${inner}</a>`;
|
|
126
|
+
}
|
|
127
|
+
return `<div class="fl-card-row list-group-item">${inner}</div>`;
|
|
128
|
+
}
|
|
129
|
+
output() {
|
|
130
|
+
if (this.name === "")
|
|
131
|
+
throw new Error("admin-card-table: id (name) is required");
|
|
132
|
+
if (this.list_url === "")
|
|
133
|
+
throw new Error("admin-card-table: hot-list-url is required");
|
|
134
|
+
const titleHtml = this.title ? `<strong>${this.title}</strong>` : "";
|
|
135
|
+
const addSlotAttr = this.add_slot ? ` data-card-table-add-slot="${this.add_slot}"` : ` data-card-table-add-slot="${this.name}"`;
|
|
136
|
+
return (`
|
|
137
|
+
<div id="${this.name}" class="card fl-card-table mb-4">
|
|
138
|
+
<div class="card-header d-flex justify-content-between align-items-center">
|
|
139
|
+
${titleHtml}
|
|
140
|
+
<div class="fl-card-table-actions"${addSlotAttr}></div>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="fl-card-list list-group list-group-flush">
|
|
143
|
+
<div class="text-muted small text-center py-4">${this.loading_text}</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.AdminCardTable = AdminCardTable;
|
|
149
|
+
//# sourceMappingURL=admin-card-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-card-table.js","sourceRoot":"","sources":["../../src/components/admin-card-table.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { HotStaq, HotAPI, HotComponent, HotComponentOutput } from "hotstaq";
|
|
2
|
+
/**
|
|
3
|
+
* Full-page detail chrome for an entity. Replaces the modal opened by
|
|
4
|
+
* <admin-edit hot-type="edit"> with a dedicated page (e.g. /budget/:id)
|
|
5
|
+
* that has its own back link, sections, and a sticky save bar at the
|
|
6
|
+
* bottom.
|
|
7
|
+
*
|
|
8
|
+
* The page is responsible for placing <admin-form-field>s inside the
|
|
9
|
+
* `<hot-place-here name="detailBody">` slot. This component handles:
|
|
10
|
+
* - reading ?id from the URL
|
|
11
|
+
* - GET'ing the entity via hot-get-url and populating form fields by
|
|
12
|
+
* matching hot-field names against the response keys
|
|
13
|
+
* - POST'ing values to hot-save-url on Save click
|
|
14
|
+
* - DELETE'ing via hot-delete-url on Delete click (with confirm)
|
|
15
|
+
* - showing a back link to hot-back-url
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* <admin-detail-page name="budgetDetail"
|
|
19
|
+
* hot-title="Budget"
|
|
20
|
+
* hot-back-url="/budgets"
|
|
21
|
+
* hot-back-text="← All budgets"
|
|
22
|
+
* hot-get-url="/v1/budgets/get"
|
|
23
|
+
* hot-save-url="/v1/budgets/edit"
|
|
24
|
+
* hot-delete-url="/v1/budgets/delete"
|
|
25
|
+
* hot-payload-key="budget"
|
|
26
|
+
* hot-jwt="${jwtToken}">
|
|
27
|
+
* <admin-form-field hot-field="name" hot-label="Name" hot-required="1"></admin-form-field>
|
|
28
|
+
* ...
|
|
29
|
+
* </admin-detail-page>
|
|
30
|
+
*/
|
|
31
|
+
export declare class AdminDetailPage extends HotComponent {
|
|
32
|
+
/** Heading shown at the top of the page. */
|
|
33
|
+
title: string;
|
|
34
|
+
/** URL the back link points at. */
|
|
35
|
+
back_url: string;
|
|
36
|
+
/** Text on the back link. */
|
|
37
|
+
back_text: string;
|
|
38
|
+
/** GET-by-id endpoint. POSTed with { id: <id> }. */
|
|
39
|
+
get_url: string;
|
|
40
|
+
/** Edit/save endpoint. POSTed with { [payload_key]: { id, ...fields } }. */
|
|
41
|
+
save_url: string;
|
|
42
|
+
/** Optional delete endpoint. Hides the Delete button when blank. */
|
|
43
|
+
delete_url: string;
|
|
44
|
+
/** Wrapper key in the save payload (most DAO routes expect { budget: {...} } / { issue: {...} } etc). */
|
|
45
|
+
payload_key: string;
|
|
46
|
+
/** JWT bearer for the API calls. */
|
|
47
|
+
jwt: string;
|
|
48
|
+
/** URL query param that holds the entity id (default: "id"). */
|
|
49
|
+
id_param: string;
|
|
50
|
+
/** Save button text. */
|
|
51
|
+
save_text: string;
|
|
52
|
+
/** Delete button text. */
|
|
53
|
+
delete_text: string;
|
|
54
|
+
/** Confirmation prompt for delete. */
|
|
55
|
+
delete_confirm: string;
|
|
56
|
+
constructor(copy: HotComponent | HotStaq, api: HotAPI);
|
|
57
|
+
onPostPlace(parentHtmlElement: HTMLElement, htmlElement: HTMLElement): HTMLElement;
|
|
58
|
+
protected readIdFromUrl(): string;
|
|
59
|
+
protected showError(page: HTMLElement, msg: string): void;
|
|
60
|
+
protected showSuccess(page: HTMLElement, msg: string): void;
|
|
61
|
+
protected fetchAndFill(page: HTMLElement, id: string): Promise<void>;
|
|
62
|
+
protected populateFields(page: HTMLElement, obj: any): void;
|
|
63
|
+
protected collectValues(page: HTMLElement): any;
|
|
64
|
+
protected handleSave(page: HTMLElement, id: string): Promise<void>;
|
|
65
|
+
protected handleDelete(id: string): Promise<void>;
|
|
66
|
+
output(): string | HotComponentOutput[];
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=admin-detail-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/admin-detail-page.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAO,MAAM,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,eAAgB,SAAQ,YAAY;IAEhD,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,yGAAyG;IACzG,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,YAAY,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM;IAmBtD,WAAW,CAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW;IA6BnF,SAAS,CAAC,aAAa,IAAK,MAAM;IAMlC,SAAS,CAAC,SAAS,CAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAM1D,SAAS,CAAC,WAAW,CAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;cAW5C,YAAY,CAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB3E,SAAS,CAAC,cAAc,CAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,GAAG,IAAI;IAiB5D,SAAS,CAAC,aAAa,CAAE,IAAI,EAAE,WAAW,GAAG,GAAG;cAmBhC,UAAU,CAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;cAkCzD,YAAY,CAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxD,MAAM,IAAK,MAAM,GAAG,kBAAkB,EAAE;CA+BxC"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AdminDetailPage = void 0;
|
|
13
|
+
const hotstaq_1 = require("hotstaq");
|
|
14
|
+
/**
|
|
15
|
+
* Full-page detail chrome for an entity. Replaces the modal opened by
|
|
16
|
+
* <admin-edit hot-type="edit"> with a dedicated page (e.g. /budget/:id)
|
|
17
|
+
* that has its own back link, sections, and a sticky save bar at the
|
|
18
|
+
* bottom.
|
|
19
|
+
*
|
|
20
|
+
* The page is responsible for placing <admin-form-field>s inside the
|
|
21
|
+
* `<hot-place-here name="detailBody">` slot. This component handles:
|
|
22
|
+
* - reading ?id from the URL
|
|
23
|
+
* - GET'ing the entity via hot-get-url and populating form fields by
|
|
24
|
+
* matching hot-field names against the response keys
|
|
25
|
+
* - POST'ing values to hot-save-url on Save click
|
|
26
|
+
* - DELETE'ing via hot-delete-url on Delete click (with confirm)
|
|
27
|
+
* - showing a back link to hot-back-url
|
|
28
|
+
*
|
|
29
|
+
* Usage:
|
|
30
|
+
* <admin-detail-page name="budgetDetail"
|
|
31
|
+
* hot-title="Budget"
|
|
32
|
+
* hot-back-url="/budgets"
|
|
33
|
+
* hot-back-text="← All budgets"
|
|
34
|
+
* hot-get-url="/v1/budgets/get"
|
|
35
|
+
* hot-save-url="/v1/budgets/edit"
|
|
36
|
+
* hot-delete-url="/v1/budgets/delete"
|
|
37
|
+
* hot-payload-key="budget"
|
|
38
|
+
* hot-jwt="${jwtToken}">
|
|
39
|
+
* <admin-form-field hot-field="name" hot-label="Name" hot-required="1"></admin-form-field>
|
|
40
|
+
* ...
|
|
41
|
+
* </admin-detail-page>
|
|
42
|
+
*/
|
|
43
|
+
class AdminDetailPage extends hotstaq_1.HotComponent {
|
|
44
|
+
constructor(copy, api) {
|
|
45
|
+
super(copy, api);
|
|
46
|
+
this.tag = "admin-detail-page";
|
|
47
|
+
this.title = "";
|
|
48
|
+
this.back_url = "/";
|
|
49
|
+
this.back_text = "← Back";
|
|
50
|
+
this.get_url = "";
|
|
51
|
+
this.save_url = "";
|
|
52
|
+
this.delete_url = "";
|
|
53
|
+
this.payload_key = "";
|
|
54
|
+
this.jwt = "";
|
|
55
|
+
this.id_param = "id";
|
|
56
|
+
this.save_text = "Save";
|
|
57
|
+
this.delete_text = "Delete";
|
|
58
|
+
this.delete_confirm = "Are you sure you want to delete this?";
|
|
59
|
+
}
|
|
60
|
+
onPostPlace(parentHtmlElement, htmlElement) {
|
|
61
|
+
const self = this;
|
|
62
|
+
const page = document.getElementById(this.name);
|
|
63
|
+
if (page == null)
|
|
64
|
+
return (null);
|
|
65
|
+
const id = self.readIdFromUrl();
|
|
66
|
+
if (!id) {
|
|
67
|
+
self.showError(page, "No id provided in the URL.");
|
|
68
|
+
return (null);
|
|
69
|
+
}
|
|
70
|
+
// Wire buttons.
|
|
71
|
+
const saveBtn = page.querySelector(".fl-detail-save");
|
|
72
|
+
const deleteBtn = page.querySelector(".fl-detail-delete");
|
|
73
|
+
if (saveBtn != null)
|
|
74
|
+
saveBtn.addEventListener("click", (e) => { e.preventDefault(); self.handleSave(page, id); });
|
|
75
|
+
if (deleteBtn != null)
|
|
76
|
+
deleteBtn.addEventListener("click", (e) => { e.preventDefault(); self.handleDelete(id); });
|
|
77
|
+
// Load existing record.
|
|
78
|
+
self.fetchAndFill(page, id);
|
|
79
|
+
return (null);
|
|
80
|
+
}
|
|
81
|
+
readIdFromUrl() {
|
|
82
|
+
const params = new URLSearchParams(window.location.search);
|
|
83
|
+
return params.get(this.id_param) || "";
|
|
84
|
+
}
|
|
85
|
+
showError(page, msg) {
|
|
86
|
+
const fb = page.querySelector(".fl-detail-feedback");
|
|
87
|
+
if (fb) {
|
|
88
|
+
fb.className = "fl-detail-feedback alert alert-danger";
|
|
89
|
+
fb.textContent = msg;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
showSuccess(page, msg) {
|
|
93
|
+
const fb = page.querySelector(".fl-detail-feedback");
|
|
94
|
+
if (fb) {
|
|
95
|
+
fb.className = "fl-detail-feedback alert alert-success";
|
|
96
|
+
fb.textContent = msg;
|
|
97
|
+
setTimeout(() => { fb.className = "fl-detail-feedback d-none"; fb.textContent = ""; }, 2500);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
fetchAndFill(page, id) {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
try {
|
|
103
|
+
const headers = { "Content-Type": "application/json" };
|
|
104
|
+
if (this.jwt)
|
|
105
|
+
headers["Authorization"] = "Bearer " + this.jwt;
|
|
106
|
+
const res = yield fetch(this.get_url, {
|
|
107
|
+
method: "POST", headers: headers, body: JSON.stringify({ id: id })
|
|
108
|
+
});
|
|
109
|
+
if (!res.ok) {
|
|
110
|
+
this.showError(page, "Could not load: HTTP " + res.status);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const obj = yield res.json();
|
|
114
|
+
if (obj == null) {
|
|
115
|
+
this.showError(page, "Record not found.");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.populateFields(page, obj);
|
|
119
|
+
}
|
|
120
|
+
catch (ex) {
|
|
121
|
+
this.showError(page, "Could not load: " + ex.message);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
populateFields(page, obj) {
|
|
126
|
+
const nodes = page.querySelectorAll("[hot-field]");
|
|
127
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
128
|
+
const el = nodes[i];
|
|
129
|
+
const field = el.getAttribute("hot-field");
|
|
130
|
+
if (field == null || field === "")
|
|
131
|
+
continue;
|
|
132
|
+
const val = obj[field];
|
|
133
|
+
if (val == null)
|
|
134
|
+
continue;
|
|
135
|
+
if (el instanceof HTMLInputElement && el.type === "checkbox")
|
|
136
|
+
el.checked = val === true || val === "true" || val === 1;
|
|
137
|
+
else
|
|
138
|
+
el.value = String(val);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
collectValues(page) {
|
|
142
|
+
const out = {};
|
|
143
|
+
const nodes = page.querySelectorAll("[hot-field]");
|
|
144
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
145
|
+
const el = nodes[i];
|
|
146
|
+
const field = el.getAttribute("hot-field");
|
|
147
|
+
if (field == null || field === "")
|
|
148
|
+
continue;
|
|
149
|
+
if (el instanceof HTMLInputElement && el.type === "checkbox")
|
|
150
|
+
out[field] = el.checked;
|
|
151
|
+
else if (el instanceof HTMLInputElement && el.type === "number")
|
|
152
|
+
out[field] = el.value === "" ? null : Number(el.value);
|
|
153
|
+
else
|
|
154
|
+
out[field] = el.value;
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
handleSave(page, id) {
|
|
159
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
160
|
+
const values = this.collectValues(page);
|
|
161
|
+
values.id = id;
|
|
162
|
+
const body = this.payload_key ? { [this.payload_key]: values } : values;
|
|
163
|
+
const btn = page.querySelector(".fl-detail-save");
|
|
164
|
+
if (btn)
|
|
165
|
+
btn.disabled = true;
|
|
166
|
+
try {
|
|
167
|
+
const headers = { "Content-Type": "application/json" };
|
|
168
|
+
if (this.jwt)
|
|
169
|
+
headers["Authorization"] = "Bearer " + this.jwt;
|
|
170
|
+
const res = yield fetch(this.save_url, {
|
|
171
|
+
method: "POST", headers: headers, body: JSON.stringify(body)
|
|
172
|
+
});
|
|
173
|
+
if (!res.ok) {
|
|
174
|
+
let msg = "HTTP " + res.status;
|
|
175
|
+
try {
|
|
176
|
+
const j = yield res.json();
|
|
177
|
+
if (j && j.error)
|
|
178
|
+
msg = j.error;
|
|
179
|
+
}
|
|
180
|
+
catch (e) { }
|
|
181
|
+
this.showError(page, "Save failed: " + msg);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
this.showSuccess(page, "Saved.");
|
|
185
|
+
}
|
|
186
|
+
catch (ex) {
|
|
187
|
+
this.showError(page, "Save failed: " + ex.message);
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
if (btn)
|
|
191
|
+
btn.disabled = false;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
handleDelete(id) {
|
|
196
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
197
|
+
if (!window.confirm(this.delete_confirm))
|
|
198
|
+
return;
|
|
199
|
+
try {
|
|
200
|
+
const headers = { "Content-Type": "application/json" };
|
|
201
|
+
if (this.jwt)
|
|
202
|
+
headers["Authorization"] = "Bearer " + this.jwt;
|
|
203
|
+
const res = yield fetch(this.delete_url, {
|
|
204
|
+
method: "POST", headers: headers, body: JSON.stringify({ id: id })
|
|
205
|
+
});
|
|
206
|
+
if (!res.ok) {
|
|
207
|
+
alert("Delete failed: HTTP " + res.status);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
window.location.href = this.back_url;
|
|
211
|
+
}
|
|
212
|
+
catch (ex) {
|
|
213
|
+
alert("Delete failed: " + ex.message);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
output() {
|
|
218
|
+
if (this.name === "")
|
|
219
|
+
throw new Error("admin-detail-page: id (name) is required");
|
|
220
|
+
if (this.get_url === "" || this.save_url === "")
|
|
221
|
+
throw new Error("admin-detail-page: hot-get-url and hot-save-url are required");
|
|
222
|
+
const deleteBtn = this.delete_url
|
|
223
|
+
? `<button type="button" class="btn btn-outline-danger fl-detail-delete">${this.delete_text}</button>`
|
|
224
|
+
: "";
|
|
225
|
+
return (`
|
|
226
|
+
<div id="${this.name}" class="fl-detail-page">
|
|
227
|
+
<div class="container" style="max-width:880px;padding:1.5rem 1rem 7rem;">
|
|
228
|
+
<div class="mb-3"><a href="${this.back_url}" class="text-muted small text-decoration-none">${this.back_text}</a></div>
|
|
229
|
+
<h1 class="h3 mb-3">${this.title}</h1>
|
|
230
|
+
<div class="fl-detail-feedback d-none"></div>
|
|
231
|
+
<div class="card mb-3"><div class="card-body">
|
|
232
|
+
<div class="row g-3">
|
|
233
|
+
<hot-place-here name="detailBody"></hot-place-here>
|
|
234
|
+
</div>
|
|
235
|
+
</div></div>
|
|
236
|
+
</div>
|
|
237
|
+
<div class="fl-detail-save-bar">
|
|
238
|
+
<div class="container d-flex justify-content-between align-items-center" style="max-width:880px;">
|
|
239
|
+
${deleteBtn}
|
|
240
|
+
<button type="button" class="btn btn-primary fl-detail-save ms-auto">${this.save_text}</button>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
</div>`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.AdminDetailPage = AdminDetailPage;
|
|
247
|
+
//# sourceMappingURL=admin-detail-page.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-detail-page.js","sourceRoot":"","sources":["../../src/components/admin-detail-page.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HotStaq, HotAPI, HotComponent, HotComponentOutput } from "hotstaq";
|
|
2
|
+
/**
|
|
3
|
+
* Pinned info card — short headline + body text, indigo left border.
|
|
4
|
+
* Pattern lifted from the DonorTiers "No governance influence"
|
|
5
|
+
* disclaimer on /donorTiers. Useful for "no influence", "draft only",
|
|
6
|
+
* "internal use", etc. notes that belong above the main content.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* <admin-disclaimer hot-heading="Disclaimer">
|
|
10
|
+
* The body text of the disclaimer goes here.
|
|
11
|
+
* </admin-disclaimer>
|
|
12
|
+
*/
|
|
13
|
+
export declare class AdminDisclaimer extends HotComponent {
|
|
14
|
+
/** Heading (h2.h6). */
|
|
15
|
+
heading: string;
|
|
16
|
+
/** Accent color for the left border. */
|
|
17
|
+
accent: string;
|
|
18
|
+
constructor(copy: HotComponent | HotStaq, api: HotAPI);
|
|
19
|
+
output(): string | HotComponentOutput[];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=admin-disclaimer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-disclaimer.d.ts","sourceRoot":"","sources":["../../src/components/admin-disclaimer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAO,MAAM,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEjF;;;;;;;;;;GAUG;AACH,qBAAa,eAAgB,SAAQ,YAAY;IAEhD,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;gBAEF,IAAI,EAAE,YAAY,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM;IAStD,MAAM,IAAK,MAAM,GAAG,kBAAkB,EAAE;CAaxC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AdminDisclaimer = void 0;
|
|
4
|
+
const hotstaq_1 = require("hotstaq");
|
|
5
|
+
/**
|
|
6
|
+
* Pinned info card — short headline + body text, indigo left border.
|
|
7
|
+
* Pattern lifted from the DonorTiers "No governance influence"
|
|
8
|
+
* disclaimer on /donorTiers. Useful for "no influence", "draft only",
|
|
9
|
+
* "internal use", etc. notes that belong above the main content.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* <admin-disclaimer hot-heading="Disclaimer">
|
|
13
|
+
* The body text of the disclaimer goes here.
|
|
14
|
+
* </admin-disclaimer>
|
|
15
|
+
*/
|
|
16
|
+
class AdminDisclaimer extends hotstaq_1.HotComponent {
|
|
17
|
+
constructor(copy, api) {
|
|
18
|
+
super(copy, api);
|
|
19
|
+
this.tag = "admin-disclaimer";
|
|
20
|
+
this.heading = "";
|
|
21
|
+
this.accent = "#4f46e5";
|
|
22
|
+
}
|
|
23
|
+
output() {
|
|
24
|
+
const heading = this.heading ? `<h2 class="h6 mb-2" style="letter-spacing:0.02em;">${this.heading}</h2>` : "";
|
|
25
|
+
return `
|
|
26
|
+
<div class="card fl-disclaimer mb-3" style="border-left:4px solid ${this.accent};">
|
|
27
|
+
<div class="card-body">
|
|
28
|
+
${heading}
|
|
29
|
+
<div class="mb-0 text-muted" style="font-size:0.9rem;line-height:1.45;">
|
|
30
|
+
${this.inner || ""}
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.AdminDisclaimer = AdminDisclaimer;
|
|
37
|
+
//# sourceMappingURL=admin-disclaimer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-disclaimer.js","sourceRoot":"","sources":["../../src/components/admin-disclaimer.ts"],"names":[],"mappings":";;;AAAA,qCAAiF;AAEjF;;;;;;;;;;GAUG;AACH,MAAa,eAAgB,SAAQ,sBAAY;IAOhD,YAAa,IAA4B,EAAE,GAAW;QAErD,KAAK,CAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAElB,IAAI,CAAC,GAAG,GAAO,kBAAkB,CAAC;QAClC,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC;QAClB,IAAI,CAAC,MAAM,GAAI,SAAS,CAAC;IAC1B,CAAC;IAED,MAAM;QAEL,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,sDAAsD,IAAI,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9G,OAAO;uEAC8D,IAAI,CAAC,MAAM;;OAE3E,OAAO;;QAEN,IAAI,CAAC,KAAK,IAAI,EAAE;;;UAGd,CAAC;IACV,CAAC;CACD;AA7BD,0CA6BC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HotStaq, HotAPI, HotComponent, HotComponentOutput } from "hotstaq";
|
|
2
|
+
/**
|
|
3
|
+
* A page heading with a small uppercase "eyebrow" label above it.
|
|
4
|
+
* Pattern lifted from the /live page on Freelight — the "Live Campaign
|
|
5
|
+
* Page" label above the candidate name.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* <admin-eyebrow-heading hot-eyebrow="Campaign Project"
|
|
9
|
+
* hot-heading="Q4 Outreach Plan"></admin-eyebrow-heading>
|
|
10
|
+
*/
|
|
11
|
+
export declare class AdminEyebrowHeading extends HotComponent {
|
|
12
|
+
/** The small uppercase label rendered above the heading. */
|
|
13
|
+
eyebrow: string;
|
|
14
|
+
/** The h1 text. */
|
|
15
|
+
heading: string;
|
|
16
|
+
/** Optional muted subtitle rendered below the heading. */
|
|
17
|
+
subtitle: string;
|
|
18
|
+
/** "center" | "start" (default). */
|
|
19
|
+
align: string;
|
|
20
|
+
constructor(copy: HotComponent | HotStaq, api: HotAPI);
|
|
21
|
+
output(): string | HotComponentOutput[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=admin-eyebrow-heading.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-eyebrow-heading.d.ts","sourceRoot":"","sources":["../../src/components/admin-eyebrow-heading.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAO,MAAM,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEjF;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;IAEpD,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;gBAED,IAAI,EAAE,YAAY,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM;IAWtD,MAAM,IAAK,MAAM,GAAG,kBAAkB,EAAE;CAgBxC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AdminEyebrowHeading = void 0;
|
|
4
|
+
const hotstaq_1 = require("hotstaq");
|
|
5
|
+
/**
|
|
6
|
+
* A page heading with a small uppercase "eyebrow" label above it.
|
|
7
|
+
* Pattern lifted from the /live page on Freelight — the "Live Campaign
|
|
8
|
+
* Page" label above the candidate name.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* <admin-eyebrow-heading hot-eyebrow="Campaign Project"
|
|
12
|
+
* hot-heading="Q4 Outreach Plan"></admin-eyebrow-heading>
|
|
13
|
+
*/
|
|
14
|
+
class AdminEyebrowHeading extends hotstaq_1.HotComponent {
|
|
15
|
+
constructor(copy, api) {
|
|
16
|
+
super(copy, api);
|
|
17
|
+
this.tag = "admin-eyebrow-heading";
|
|
18
|
+
this.eyebrow = "";
|
|
19
|
+
this.heading = "";
|
|
20
|
+
this.subtitle = "";
|
|
21
|
+
this.align = "start";
|
|
22
|
+
}
|
|
23
|
+
output() {
|
|
24
|
+
const alignClass = this.align === "center" ? "text-center" : "";
|
|
25
|
+
const eyebrow = this.eyebrow
|
|
26
|
+
? `<div class="text-uppercase text-muted small mb-2" style="letter-spacing:0.08em;">${this.eyebrow}</div>`
|
|
27
|
+
: "";
|
|
28
|
+
const subtitle = this.subtitle
|
|
29
|
+
? `<p class="text-muted mb-0">${this.subtitle}</p>`
|
|
30
|
+
: "";
|
|
31
|
+
return `
|
|
32
|
+
<div class="fl-eyebrow-heading mb-3 ${alignClass}">
|
|
33
|
+
${eyebrow}
|
|
34
|
+
<h1 class="h3 mb-1">${this.heading || this.inner || ""}</h1>
|
|
35
|
+
${subtitle}
|
|
36
|
+
</div>`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.AdminEyebrowHeading = AdminEyebrowHeading;
|
|
40
|
+
//# sourceMappingURL=admin-eyebrow-heading.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-eyebrow-heading.js","sourceRoot":"","sources":["../../src/components/admin-eyebrow-heading.ts"],"names":[],"mappings":";;;AAAA,qCAAiF;AAEjF;;;;;;;;GAQG;AACH,MAAa,mBAAoB,SAAQ,sBAAY;IAWpD,YAAa,IAA4B,EAAE,GAAW;QAErD,KAAK,CAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAElB,IAAI,CAAC,GAAG,GAAQ,uBAAuB,CAAC;QACxC,IAAI,CAAC,OAAO,GAAI,EAAE,CAAC;QACnB,IAAI,CAAC,OAAO,GAAI,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,GAAM,OAAO,CAAC;IACzB,CAAC;IAED,MAAM;QAEL,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO;YAC3B,CAAC,CAAC,oFAAoF,IAAI,CAAC,OAAO,QAAQ;YAC1G,CAAC,CAAC,EAAE,CAAC;QACN,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ;YAC7B,CAAC,CAAC,8BAA8B,IAAI,CAAC,QAAQ,MAAM;YACnD,CAAC,CAAC,EAAE,CAAC;QACN,OAAO;yCACgC,UAAU;MAC7C,OAAO;0BACa,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE;MACpD,QAAQ;UACJ,CAAC;IACV,CAAC;CACD;AAtCD,kDAsCC"}
|