Skip to content

Commit b1f72fb

Browse files
committed
I think it's working
1 parent d3c20e0 commit b1f72fb

5 files changed

Lines changed: 102 additions & 251 deletions

File tree

packages/admin-vanilla/src/app.tsx

Lines changed: 21 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -234,26 +234,20 @@ function deriveBagRecords(items: DataStore, templates: TemplateAdminRecord[], wi
234234
function derivePluginRecords(items: DataStore, templates: TemplateAdminRecord[], wikis: WikiAdminRecord[]): PluginAdminRecord[] {
235235
const pluginUsage = new Map<string, Set<string>>();
236236

237-
const addUsage = (pluginName: string, wikiName: string) => {
238-
if (!pluginName || !wikiName) return;
239-
const next = pluginUsage.get(pluginName) ?? new Set<string>();
240-
next.add(wikiName);
241-
pluginUsage.set(pluginName, next);
242-
};
243-
244237
for (const wiki of wikis) {
245238
const wikiName = wiki.slug || wiki.displayName || "";
246239
wiki.effectivePluginSet.forEach((pluginValue) => {
247240
const pluginName = pluginValue.split("@")[0]?.trim() ?? pluginValue.trim();
248-
addUsage(pluginName, wikiName);
241+
if (!pluginName || !wikiName) return;
242+
mapGetInit(pluginUsage, pluginName, () => new Set<string>()).add(wikiName);
249243
});
250244
}
251245

252246
return items.plugins.map((plugin) => {
253247
const usedByWikis = Array.from(pluginUsage.get(plugin.name ?? "") ?? []);
254248
return {
255249
...plugin as unknown as PluginAdminRecord,
256-
usedByWikis: usedByWikis.join("\n"),
250+
usedByWikis,
257251
usageCount: String(usedByWikis.length),
258252
};
259253
});
@@ -745,77 +739,6 @@ function getListColumnLink(tabId: TabId, columnKey: string, item: AdminRecord):
745739
return mapper ? mapper(item) : null;
746740
}
747741

748-
function countValueLines(value: readonly string[]): number {
749-
return value.length;
750-
}
751-
752-
function getSidebarFacts(tabId: TabId, draft: AdminRecord): Array<{ label: string; value: string; }>;
753-
function getSidebarFacts(tabId: TabId, draft: unknown): Array<{ label: string; value: string; }> {
754-
if (tabId === "wikis") {
755-
definitely<WikiAdminRecord>(draft);
756-
return [
757-
{ label: "Template", value: formatFieldValue(draft.templateName || draft.templateRef?.name) },
758-
{ label: "Default bag", value: formatFieldValue(draft.defaultWritableBag) },
759-
{ label: "Compiled", value: formatFieldValue(draft.lastCompiledAt) },
760-
];
761-
}
762-
763-
if (tabId === "templates") {
764-
definitely<TemplateAdminRecord>(draft);
765-
return [
766-
{ label: "Readonly bags", value: String((draft.readonlyBags.length)) },
767-
{ label: "Prefix rules", value: String(draft.writablePrefixBags.length || 0) },
768-
{ label: "Default bag", value: formatFieldValue(draft.defaultWritableBag) },
769-
{ label: "Plugins", value: String(draft.plugins.length) },
770-
{ label: "Validation", value: formatFieldValue(draft.validationStatus || draft.validationReport) },
771-
];
772-
}
773-
774-
if (tabId === "bags") {
775-
definitely<BagAdminRecord>(draft);
776-
return [
777-
{ label: "Permission roles", value: String(draft.permissions.length || 0) },
778-
{ label: "Referenced by templates", value: String(draft.referencedByTemplates.length) },
779-
{ label: "Referenced by wikis", value: String(draft.referencedByWikis.length) },
780-
{ label: "Routing roles", value: String(draft.referencedByWikis.length) },
781-
// { label: "Tiddlers", value: formatFieldValue(draft.tiddlerCount) },
782-
// { label: "Last activity", value: formatFieldValue(draft.lastActivityAt) },
783-
];
784-
}
785-
786-
if (tabId === "plugins") {
787-
definitely<PluginAdminRecord>(draft);
788-
return [
789-
{ label: "Version", value: formatFieldValue(draft.version) },
790-
{ label: "Status", value: formatFieldValue(draft.status) },
791-
{ label: "Used by wikis", value: String(draft.usedByWikis.length) },
792-
{ label: "Usage count", value: formatFieldValue(draft.usageCount) },
793-
{ label: "Draft of", value: formatFieldValue(draft.draftOf) },
794-
{ label: "Updated", value: formatFieldValue(draft.updatedAt) },
795-
];
796-
}
797-
798-
if (tabId === "roles") {
799-
definitely<RoleAdminRecord>(draft);
800-
return [
801-
{ label: "Role name", value: formatFieldValue(draft.roleId) },
802-
{ label: "Description", value: formatFieldValue(draft.description) },
803-
];
804-
}
805-
806-
if (tabId === "users") {
807-
definitely<UserAdminRecord>(draft);
808-
return [
809-
{ label: "Username", value: formatFieldValue(draft.username) },
810-
{ label: "Email", value: formatFieldValue(draft.email) },
811-
{ label: "Assigned roles", value: String(draft.userRoles.length) },
812-
];
813-
}
814-
815-
{ const t: never = tabId; return []; }
816-
817-
}
818-
819742
function renderSearchableInput({ id, currentValue, placeholder, options, onInput, disabled }: {
820743
id: string;
821744
currentValue: string;
@@ -890,15 +813,15 @@ function renderActivityFeedField(ctx: ReadonlyFieldContext<readonly string[]>) {
890813
}
891814

892815
function renderMetadataTableField(ctx: ReadonlyFieldContext<readonly string[]>) {
893-
const lines = ctx.value;
816+
const lines = ctx.saved;
894817
return <dl class="meta-list">{lines.map((line) => {
895818
const [key, ...rest] = line.split(":");
896819
return <><dt>{key}</dt><dd>{rest.join(":").trim()}</dd></>;
897820
})}</dl>;
898821
}
899822

900823
function renderTableField(ctx: ReadonlyFieldContext) {
901-
const { field, value, itemsByTab } = ctx;
824+
const { field, saved: value, itemsByTab } = ctx;
902825
definitely<readonly string[]>(value);
903826
const lines = value;
904827
const missingDependencyLines = getMissingDependencyLines(field, value, itemsByTab);
@@ -934,8 +857,8 @@ function renderTableField(ctx: ReadonlyFieldContext) {
934857
}
935858

936859
function renderCalloutField(ctx: ReadonlyFieldContext) {
937-
definitely<string>(ctx.value);
938-
return <div class="field-callout"><p>{formatFieldValue(ctx.value)}</p></div>;
860+
definitely<string>(ctx.saved);
861+
return <div class="field-callout"><p>{formatFieldValue(ctx.saved)}</p></div>;
939862
}
940863

941864
function renderPreField(ctx: ReadonlyFieldContext) {
@@ -1020,7 +943,7 @@ class SearchMultiselectFieldHandler extends FieldTypeHandler<string[]> {
1020943

1021944
public override renderSidebar(ctx: ReadonlyFieldContext<readonly string[]>): JSX.Node {
1022945
return <ul>
1023-
{ctx.value.map(e => <li>{e}</li>)}
946+
{ctx.saved.map(e => <li>{e}</li>)}
1024947
</ul>
1025948
}
1026949

@@ -1293,7 +1216,7 @@ class AutocompleteFieldHandler extends FieldTypeHandler<Reference | null> {
12931216
}
12941217

12951218
renderSidebar(ctx: ReadonlyFieldContext<Reference | null>) {
1296-
return ctx.value?.name ?? "";
1219+
return ctx.saved?.name ?? "";
12971220
}
12981221

12991222
public override renderEditor(ctx: FieldEditorContext<Reference | null>) {
@@ -1392,15 +1315,16 @@ class ValueListFieldHandler extends FieldTypeHandler<string[]> {
13921315

13931316
public override renderSidebar(ctx: ReadonlyFieldContext) {
13941317
// TODO: string should probably be a separate class
1395-
const lines = typeof ctx.value === "string"
1396-
? lineListCodec.parse(ctx.value)
1397-
: ctx.value as readonly string[];
1318+
const lines = typeof ctx.saved === "string"
1319+
? lineListCodec.parse(ctx.saved)
1320+
: ctx.saved as readonly string[];
13981321
return <ul class="value-list">{lines.map((line) => <li>{line}</li>)}</ul>;
13991322
}
14001323

14011324
public override renderEditor(ctx: FieldEditorContext) {
14021325
return this.renderSidebar(ctx);
14031326
}
1327+
14041328
}
14051329

14061330
class ActivityFeedFieldHandler extends FieldTypeHandler<readonly string[]> {
@@ -1793,10 +1717,14 @@ class RecordModalElement extends JSXElement {
17931717
);
17941718
})}
17951719

1796-
<footer class="modal-actions">
1797-
<button class="ghost-button" type="button" onclick={onClose} disabled={isSaving}>Cancel</button>
1798-
<button class="primary-button" type="button" onclick={onSave} disabled={isSaving || isOpeningItem}>{isSaving ? "Saving..." : modalState.mode === "create" ? `Save ${selectedTab.label.slice(0, -1)}` : "Save changes"}</button>
1799-
</footer>
1720+
{modalState.tabId !== "plugins"
1721+
? <footer class="modal-actions">
1722+
<button class="ghost-button" type="button" onclick={onClose} disabled={isSaving}>Cancel</button>
1723+
<button class="primary-button" type="button" onclick={onSave} disabled={isSaving || isOpeningItem}>{isSaving ? "Saving..." : modalState.mode === "create" ? `Save ${selectedTab.label.slice(0, -1)}` : "Save changes"}</button>
1724+
</footer>
1725+
: <footer class="modal-actions">
1726+
<button class="ghost-button" type="button" onclick={onClose} disabled={isSaving}>Close</button>
1727+
</footer>}
18001728
</div>
18011729
</div>
18021730
)}

packages/admin-vanilla/src/definition/tabs.ts

Lines changed: 37 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ export interface TabDefinition {
7474
fieldGroups?: Partial<Record<FieldSection, FieldGroupDefinition[]>>;
7575
}
7676

77-
const tabs = [
78-
{
77+
const tabs = {
78+
wikis: {
7979
id: "wikis",
8080
label: "Wikis",
8181
createLabel: "Create wiki",
@@ -189,7 +189,7 @@ const tabs = [
189189
"effectivePluginSet",
190190
]
191191
},
192-
{
192+
templates: {
193193
id: "templates",
194194
label: "Templates",
195195
createLabel: "Create template",
@@ -312,7 +312,7 @@ const tabs = [
312312
"dependentWikiCount",
313313
]
314314
},
315-
{
315+
bags: {
316316
id: "bags",
317317
label: "Bags",
318318
createLabel: "Create bag",
@@ -394,50 +394,38 @@ const tabs = [
394394
"referencedByWikis",
395395
]
396396
},
397-
{
397+
plugins: {
398398
id: "plugins",
399399
label: "Plugins",
400400
createLabel: "Create plugin",
401401
eyebrow: "Managed Assets",
402402
description: "Separately versioned plugins compiled into each wiki’s resolved plugin set. Still work in progress.",
403403
columns: [
404404
{ key: "name", label: "Name" },
405-
{ key: "version", label: "Version" },
406-
{ key: "status", label: "Status" },
405+
{ key: "description", label: "Description" },
406+
{ key: "pluginPath", label: "Plugin Path" },
407407
{ key: "usageCount", label: "Usage" },
408-
{ key: "updatedAt", label: "Updated" },
409408
],
410409
fields: [
411-
{ key: "name", label: "Name", type: "string", section: "authored", mode: "create edit" },
412-
{ key: "version", label: "Version", type: "version", section: "authored", mode: "create edit" },
413-
{ key: "status", label: "Status", type: "select", section: "authored", mode: "create edit" },
414-
{ key: "description", label: "Description", type: "text", section: "authored", mode: "create edit" },
415-
{
416-
key: "assetsMetadata",
417-
label: "Assets metadata",
418-
type: "metadata-table",
419-
section: "runtime",
420-
mode: "",
421-
architecture: "List of shadow tiddlers the plugin contains.",
422-
},
423-
{
424-
key: "usedByWikis",
425-
label: "Used by wikis",
426-
type: "relationship-table",
427-
section: "runtime",
428-
mode: "",
429-
architecture: "Read-only relationship view derived from compiled recipe-plugin rows, showing exact effective usage of this version.",
430-
},
410+
{ key: "name", label: "Name", type: "string", section: "authored", mode: "server" },
411+
{ key: "description", label: "Description", type: "text", section: "authored", mode: "server" },
412+
{ key: "pluginPath", label: "Path", type: "string", section: "authored", mode: "server" },
413+
{ key: "usageCount", label: "Wiki Count", type: "number", section: "runtime", mode: "" },
414+
{ key: "usedByWikis", label: "Active Wikis", type: "table", section: "runtime", mode: "" },
431415
],
432416
fieldGroups: {
433-
authored: [
434-
{ title: "Plugin basics", keys: ["name", "description"], width: fullWidth, layout: stackLayout },
435-
{ title: "Release details", keys: ["version", "status"], width: halfWidth },
417+
runtime: [
418+
{ title: "Used in", description: "List of wikis this plugin is used in. Only includes templates that are in use.", keys: ["usedByWikis"], width: fullWidth, layout: "grid" },
436419
],
437420
},
438-
sidebarDisplay: [],
421+
sidebarDisplay: [
422+
"name",
423+
"description",
424+
"usageCount",
425+
"pluginPath",
426+
],
439427
},
440-
{
428+
roles: {
441429
id: "roles",
442430
label: "Roles",
443431
createLabel: "Create role",
@@ -458,7 +446,7 @@ const tabs = [
458446
},
459447
sidebarDisplay: ["roleId", "description"],
460448
},
461-
{
449+
users: {
462450
id: "users",
463451
label: "Users",
464452
createLabel: "Create user",
@@ -488,38 +476,24 @@ const tabs = [
488476
"userRoles",
489477
]
490478
},
491-
] as const satisfies TabDefinition[];
492-
493-
// tabs.forEach(e => {
494-
// const fields = new Set(e.fields.map(e => e.key as string));
495-
// if (fields.size !== e.fields.length)
496-
// throw new Error("There are fields with duplicate keys in tab " + e.label);
497-
// const colsMissing = e.columns.filter(f => !fields.has(f.key as string));
498-
// if (colsMissing.length) {
499-
// console.log(colsMissing);
500-
// throw new Error(`There are columns that don't have a field in tab ${e.label}: ${colsMissing.map(e => e.key)}`);
501-
// }
502-
// if (Object.keys(e.fieldGroups).some(k => e.fieldGroups[k].some(f => {
503-
// f.keys.some(g => !fields.has(g as string))
504-
// }))) throw new Error("There are field groups which specify keys that don't exist in " + e.label);
505-
// })
506-
479+
} as const satisfies Record<string, TabDefinition>;
507480

508481
export function getTab(tabId: TabId): TabDefinition {
509-
return tabs.find((tab) => tab.id === tabId) ?? tabs[0];
482+
return tabs[tabId];
510483
}
511484
export function getAllTabs(): TabDefinition[] {
512-
return tabs;
485+
return Object.values(tabs);
513486
}
514487

515488
export type TabDef = typeof tabs;
516489

517490

518491

519492
type StoredTabKeys<T extends TabDefinition> = {
520-
[K in T["id"]]: MapFieldDefinitions<T["fields"]>[number] | "id"
521-
}[T["id"]];
493+
[K in keyof TabDef]: MapFieldDefinitions<T["fields"]>[number] | "id"
494+
}[keyof TabDef];
522495

496+
type t1 = TabDef[TabId]["fields"][number]["key"]
523497

524498

525499
type StoredTabRecord<D extends TabDefinition, T> = Pick<T, StoredTabKeys<D> & keyof T>;
@@ -548,12 +522,12 @@ export interface AdminRecordStore {
548522
}
549523

550524
export interface DataStore {
551-
wikis: StoredTabRecord<TabDef[0], WikiAdminRecord>[];
552-
templates: StoredTabRecord<TabDef[1], TemplateAdminRecord>[];
553-
bags: StoredTabRecord<TabDef[2], BagAdminRecord>[];
554-
plugins: StoredTabRecord<TabDef[3], PluginAdminRecord>[];
555-
roles: StoredTabRecord<TabDef[4], RoleAdminRecord>[];
556-
users: StoredTabRecord<TabDef[5], UserAdminRecord>[];
525+
wikis: StoredTabRecord<TabDef["wikis"], WikiAdminRecord>[];
526+
templates: StoredTabRecord<TabDef["templates"], TemplateAdminRecord>[];
527+
bags: StoredTabRecord<TabDef["bags"], BagAdminRecord>[];
528+
plugins: StoredTabRecord<TabDef["plugins"], PluginAdminRecord>[];
529+
roles: StoredTabRecord<TabDef["roles"], RoleAdminRecord>[];
530+
users: StoredTabRecord<TabDef["users"], UserAdminRecord>[];
557531
availableBagNames: Set<string>;
558532
availablePluginNames: Set<string>;
559533
};
@@ -630,16 +604,11 @@ export interface BagAdminRecord {
630604

631605
export interface PluginAdminRecord {
632606
id: string;
633-
version: string;
634-
description: string;
635607
name: string;
636-
status: string;
637-
publishFromDraft: string;
638-
assetsMetadata: string;
639-
usedByWikis: string;
608+
description: string;
609+
pluginPath: string;
640610
usageCount: string;
641-
draftOf: string;
642-
updatedAt: string;
611+
usedByWikis: string[];
643612
}
644613

645614
export interface RoleAdminRecord {

0 commit comments

Comments
 (0)