@@ -2,11 +2,15 @@ import { createProjectJourneyMockRepository } from "../toolbox/project-journey/p
22import { createAssetToolMockRepository } from "../toolbox/assets/assets-mock-repository.js" ;
33import { createProjectWorkspacePaletteRepository } from "../toolbox/colors/palette-workspace-repository.js" ;
44import {
5- getAllPersistedMockDbTables ,
5+ getAllPersistedMockDbSnapshot ,
6+ clearMockDbTables ,
7+ getMockDbSessionUser ,
8+ getMockDbSessionUsers ,
69 getStandaloneMockDbTables ,
7- } from "../src/shared/mock-db/mock-db-store.js" ;
10+ setMockDbSessionUser ,
11+ } from "../src/engine/persistence/mock-db-store.js" ;
812
9- const AUDIT_FIELDS = [ "createdAt" , "updatedAt" , "createdByType " , "updatedByType " ] ;
13+ const AUDIT_FIELDS = [ "createdAt" , "updatedAt" , "createdBy " , "updatedBy " ] ;
1014const TOOL_GROUP_ORDER = [ "project-journey" , "palette" , "asset" ] ;
1115const TOOL_GROUP_LABELS = Object . freeze ( {
1216 asset : "Asset" ,
@@ -17,22 +21,29 @@ const STANDALONE_TABLE_LABELS = Object.freeze({
1721 users : "Users" ,
1822 actors : "Actors" ,
1923} ) ;
20- const AUDIT_REQUIRED_TABLES = new Set ( [ "users" , "actors" ] ) ;
2124
2225class AdminDbViewer {
2326 constructor ( documentRef = document ) {
2427 this . document = documentRef ;
25- this . projectJourneyRepository = createProjectJourneyMockRepository ( ) ;
26- this . paletteRepository = createProjectWorkspacePaletteRepository ( ) ;
27- this . assetRepository = createAssetToolMockRepository ( ) ;
28+ this . createRepositories ( ) ;
2829 this . activeFilter = "all" ;
30+ this . clearButton = documentRef . querySelector ( "[data-admin-db-clear]" ) ;
2931 this . filterRoot = documentRef . querySelector ( "[data-admin-db-filters]" ) ;
3032 this . status = documentRef . querySelector ( "[data-admin-db-status]" ) ;
3133 this . diagnostics = documentRef . querySelector ( "[data-admin-db-diagnostics]" ) ;
3234 this . relationships = documentRef . querySelector ( "[data-admin-db-relationships]" ) ;
35+ this . sessionSummary = documentRef . querySelector ( "[data-session-user-summary]" ) ;
36+ this . sessionHeader = documentRef . querySelector ( "[data-session-user-header]" ) ;
37+ this . sessionUserControls = documentRef . querySelector ( "[data-session-user-controls]" ) ;
3338 this . tablesRoot = documentRef . querySelector ( "[data-admin-db-tables]" ) ;
3439 }
3540
41+ createRepositories ( ) {
42+ this . projectJourneyRepository = createProjectJourneyMockRepository ( ) ;
43+ this . paletteRepository = createProjectWorkspacePaletteRepository ( ) ;
44+ this . assetRepository = createAssetToolMockRepository ( ) ;
45+ }
46+
3647 start ( ) {
3748 this . projectJourneyRepository . openProject ( "demo-project" ) ;
3849 this . render ( ) ;
@@ -44,6 +55,26 @@ class AdminDbViewer {
4455 this . activeFilter = button . dataset . adminDbFilter || "all" ;
4556 this . render ( ) ;
4657 } ) ;
58+ this . sessionUserControls ?. addEventListener ( "click" , ( event ) => {
59+ const button = event . target . closest ( "[data-session-user-button]" ) ;
60+ if ( ! button ) {
61+ return ;
62+ }
63+ setMockDbSessionUser ( button . dataset . sessionUserButton || "user1" ) ;
64+ this . createRepositories ( ) ;
65+ this . projectJourneyRepository . openProject ( "demo-project" ) ;
66+ this . render ( ) ;
67+ } ) ;
68+ this . clearButton ?. addEventListener ( "click" , ( ) => {
69+ if ( ! window . confirm ( "Clear all shared Mock DB records?" ) ) {
70+ return ;
71+ }
72+ clearMockDbTables ( ) ;
73+ this . createRepositories ( ) ;
74+ this . projectJourneyRepository . openProject ( "demo-project" ) ;
75+ this . activeFilter = "all" ;
76+ this . render ( ) ;
77+ } ) ;
4778 }
4879
4980 createElement ( tagName , options = { } ) {
@@ -96,40 +127,40 @@ class AdminDbViewer {
96127 }
97128
98129 collectSnapshot ( ) {
99- const projectJourneyTables = this . projectJourneyRepository . getTables ( ) ;
100- const paletteTables = this . paletteRepository . getTables ( ) ;
101- const assetTables = this . assetRepository . getTables ( ) ;
102- const standaloneTables = getStandaloneMockDbTables ( ) ;
103- const persistedTables = getAllPersistedMockDbTables ( ) ;
104- const tables = {
105- ...persistedTables ,
106- ...projectJourneyTables ,
107- ...paletteTables ,
108- ...assetTables ,
109- ...standaloneTables ,
110- } ;
130+ this . projectJourneyRepository . getTables ( ) ;
131+ this . paletteRepository . getTables ( ) ;
132+ this . assetRepository . getTables ( ) ;
133+ getStandaloneMockDbTables ( ) ;
134+ const snapshot = getAllPersistedMockDbSnapshot ( ) ;
135+ const tables = snapshot . tables ;
136+ const owners = snapshot . owners || { } ;
137+ const tableNamesForOwner = ( ownerId ) => Object . keys ( tables )
138+ . filter ( ( tableName ) => owners [ tableName ] === ownerId )
139+ . sort ( ) ;
140+ const toolGroupIds = TOOL_GROUP_ORDER . filter ( ( id ) => tableNamesForOwner ( id ) . length > 0 ) ;
141+ const toolOwnedTables = new Set ( toolGroupIds . flatMap ( tableNamesForOwner ) ) ;
142+ const unownedTableNames = Object . keys ( tables )
143+ . filter ( ( tableName ) => ! toolOwnedTables . has ( tableName ) ) ;
144+ const standaloneTableNames = [
145+ ...Object . keys ( STANDALONE_TABLE_LABELS ) . filter ( ( tableName ) => unownedTableNames . includes ( tableName ) ) ,
146+ ...unownedTableNames . filter ( ( tableName ) => ! Object . hasOwn ( STANDALONE_TABLE_LABELS , tableName ) ) . sort ( ) ,
147+ ] ;
111148 const groups = [
112149 {
113150 id : "all" ,
114151 label : "All" ,
115152 tableNames : Object . keys ( tables ) . sort ( ) ,
116153 type : "all" ,
117154 } ,
118- ...TOOL_GROUP_ORDER . map ( ( id ) => ( {
155+ ...toolGroupIds . map ( ( id ) => ( {
119156 id,
120157 label : TOOL_GROUP_LABELS [ id ] ,
121- tableNames : Object . keys (
122- id === "project-journey"
123- ? projectJourneyTables
124- : id === "palette"
125- ? paletteTables
126- : assetTables ,
127- ) . sort ( ) ,
158+ tableNames : tableNamesForOwner ( id ) ,
128159 type : "tool" ,
129160 } ) ) ,
130- ...Object . entries ( STANDALONE_TABLE_LABELS ) . map ( ( [ tableName , label ] ) => ( {
161+ ...standaloneTableNames . map ( ( tableName ) => ( {
131162 id : tableName ,
132- label,
163+ label : STANDALONE_TABLE_LABELS [ tableName ] || tableName ,
133164 tableNames : [ tableName ] ,
134165 type : "table" ,
135166 } ) ) ,
@@ -165,18 +196,35 @@ class AdminDbViewer {
165196 } ) ;
166197 table . setAttribute ( "aria-label" , `${ tableName } records` ) ;
167198
168- const fields = this . tableFields ( records ) ;
199+ const fields = this . tableFields ( records ) . filter ( ( field ) => field !== "key" ) ;
169200 const head = this . createElement ( "thead" ) ;
170201 const headerRow = this . createElement ( "tr" ) ;
202+ headerRow . append ( this . createElement ( "th" , { text : "Key" } ) ) ;
171203 fields . forEach ( ( field ) => {
172204 headerRow . append ( this . createElement ( "th" , { text : field } ) ) ;
173205 } ) ;
174206 head . append ( headerRow ) ;
175207
176208 const tableBody = this . createElement ( "tbody" ) ;
209+ if ( ! records . length ) {
210+ const row = this . createElement ( "tr" ) ;
211+ const cell = this . createElement ( "td" , {
212+ text : "No records in this table. Add records from its tool or clear browser mock DB storage to reseed defaults." ,
213+ } ) ;
214+ cell . colSpan = Math . max ( 1 , fields . length + 1 ) ;
215+ row . append ( cell ) ;
216+ tableBody . append ( row ) ;
217+ }
177218 records . forEach ( ( record ) => {
178219 const row = this . createElement ( "tr" ) ;
179220 row . dataset . adminDbRecord = this . recordId ( record ) ;
221+ const keyCell = this . createElement ( "td" , {
222+ text : this . isUlidKey ( record . key ) ? this . formatKeyValue ( record . key ) : this . formatValue ( record . key ) ,
223+ } ) ;
224+ if ( this . isUlidKey ( record . key ) ) {
225+ keyCell . title = String ( record . key ) ;
226+ }
227+ row . append ( keyCell ) ;
180228 fields . forEach ( ( field ) => {
181229 const value = record [ field ] ;
182230 const cell = this . createElement ( "td" , {
@@ -223,12 +271,29 @@ class AdminDbViewer {
223271 } ) ;
224272 }
225273
274+ renderSessionUser ( ) {
275+ const sessionUser = getMockDbSessionUser ( ) ;
276+ if ( this . sessionHeader ) {
277+ this . sessionHeader . textContent = `Session user: ${ sessionUser . label } ` ;
278+ }
279+ if ( this . sessionSummary ) {
280+ this . sessionSummary . textContent = `Selected session user: ${ sessionUser . label } .` ;
281+ }
282+ this . document . querySelectorAll ( "[data-session-user-button]" ) . forEach ( ( button ) => {
283+ const selected = button . dataset . sessionUserButton === sessionUser . id ;
284+ button . classList . toggle ( "primary" , selected ) ;
285+ button . setAttribute ( "aria-pressed" , String ( selected ) ) ;
286+ if ( selected ) {
287+ button . setAttribute ( "aria-current" , "true" ) ;
288+ } else {
289+ button . removeAttribute ( "aria-current" ) ;
290+ }
291+ } ) ;
292+ }
293+
226294 auditFindings ( tables ) {
227295 const findings = [ ] ;
228296 Object . entries ( tables ) . forEach ( ( [ tableName , records ] ) => {
229- if ( ! tableName . startsWith ( "project_journey_" ) && ! AUDIT_REQUIRED_TABLES . has ( tableName ) ) {
230- return ;
231- }
232297 records . forEach ( ( record ) => {
233298 AUDIT_FIELDS . forEach ( ( field ) => {
234299 if ( ! Object . hasOwn ( record , field ) ) {
@@ -244,6 +309,7 @@ class AdminDbViewer {
244309 const noteTypeKeys = new Set ( ( tables . project_journey_note_types || [ ] ) . map ( ( type ) => type . key ) ) ;
245310 const noteKeys = new Set ( ( tables . project_journey_notes || [ ] ) . map ( ( note ) => note . key ) ) ;
246311 const userKeys = new Set ( ( tables . users || [ ] ) . map ( ( user ) => user . key ) ) ;
312+ const actorKeys = new Set ( ( tables . actors || [ ] ) . map ( ( actor ) => actor . key ) ) ;
247313 const actorUserKeys = new Set ( ( tables . actors || [ ] ) . map ( ( actor ) => actor . userKey ) ) ;
248314 const activeTemplateKeys = new Set (
249315 ( tables . project_journey_templates || [ ] )
@@ -254,7 +320,23 @@ class AdminDbViewer {
254320 const paletteColorKeys = new Set ( ( tables . palette_colors || [ ] ) . map ( ( row ) => `${ row . projectId } :${ row . symbol } ` ) ) ;
255321 const assetIds = new Set ( ( tables . asset_library_items || [ ] ) . map ( ( asset ) => asset . id ) ) ;
256322 const assetStorageIds = new Set ( ( tables . asset_storage_objects || [ ] ) . map ( ( object ) => object . id ) ) ;
323+ const allRecords = Object . entries ( tables ) . flatMap ( ( [ tableName , records ] ) =>
324+ records . map ( ( record ) => ( {
325+ ...record ,
326+ tableName,
327+ } ) ) ,
328+ ) ;
257329 return [
330+ {
331+ name : "*.createdBy -> actors.key" ,
332+ checked : allRecords . length ,
333+ missing : allRecords . filter ( ( record ) => ! actorKeys . has ( record . createdBy ) ) ,
334+ } ,
335+ {
336+ name : "*.updatedBy -> actors.key" ,
337+ checked : allRecords . length ,
338+ missing : allRecords . filter ( ( record ) => ! actorKeys . has ( record . updatedBy ) ) ,
339+ } ,
258340 {
259341 name : "project_journey_notes.typeKey -> project_journey_note_types.key" ,
260342 checked : ( tables . project_journey_notes || [ ] ) . length ,
@@ -363,7 +445,7 @@ class AdminDbViewer {
363445 const staleFindings = this . staleDisplayFindings ( tables , groups ) ;
364446 const auditSummary = auditFindings . length
365447 ? auditFindings
366- : [ "All current mock DB tables include createdAt, updatedAt, createdByType , and updatedByType where required by the owning mock model ." ] ;
448+ : [ "All current mock DB tables include createdAt, updatedAt, createdBy , and updatedBy ." ] ;
367449 const bleedSummary = bleedFindings . length ? bleedFindings : [ "No table bleed detected." ] ;
368450 this . diagnostics . append (
369451 this . renderList ( auditSummary , "adminDbAuditFindings" ) ,
@@ -376,7 +458,7 @@ class AdminDbViewer {
376458 this . relationships . replaceChildren ( ) ;
377459 const relationshipRows = this . relationshipsForTables ( tables ) ;
378460 const missingLinks = relationshipRows . flatMap ( ( relationship ) =>
379- relationship . missing . map ( ( record ) => `${ relationship . name } missing for ${ this . recordId ( record ) } .` ) ,
461+ relationship . missing . map ( ( record ) => `${ relationship . name } missing for ${ record . tableName ? ` ${ record . tableName } .` : "" } ${ this . recordId ( record ) } .` ) ,
380462 ) ;
381463 const relationshipList = this . createElement ( "ul" ) ;
382464 relationshipList . dataset . adminDbRelationshipSummary = "" ;
@@ -403,6 +485,7 @@ class AdminDbViewer {
403485 . map ( ( tableName ) => [ tableName , snapshot . tables [ tableName ] ] ) ,
404486 ) ;
405487 this . renderFilters ( snapshot . groups ) ;
488+ this . renderSessionUser ( ) ;
406489 this . renderDiagnostics ( snapshot . tables , snapshot . groups ) ;
407490 this . renderRelationships ( snapshot . tables ) ;
408491 this . renderTables ( visibleTables ) ;
0 commit comments