Skip to content

Commit 7382c18

Browse files
committed
Store schema against data, allow listing objects by type
1 parent 0a2937d commit 7382c18

File tree

9 files changed

+402
-72
lines changed

9 files changed

+402
-72
lines changed

typescript/packages/common-ui/src/components/common-table.ts

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,43 +37,111 @@ export class CommonCardElement extends LitElement {
3737
}
3838
.value {
3939
color: #666;
40+
max-height: 128px;
41+
overflow-y: auto;
42+
}
43+
pre {
44+
white-space: pre-wrap;
45+
word-break: break-word;
46+
margin: 0;
47+
}
48+
.string-value {
49+
white-space: pre-wrap;
50+
word-break: break-word;
51+
}
52+
.self-pill {
53+
display: inline-block;
54+
background: #f3f4f6;
55+
border-radius: 12px;
56+
padding: 2px 8px;
57+
font-family: monospace;
58+
font-size: 10px;
4059
}
4160
`
4261
];
4362

4463
override render() {
45-
if (!this.schema || !this.item) {
46-
return html`<div>Missing schema or data</div>`;
64+
if (!this.item) {
65+
return html`<div>Missing data</div>`;
66+
}
67+
68+
if (this.schema) {
69+
const entries = Object.entries(this.schema.shape);
70+
const nonSelfEntries = entries.filter(([key]) => key !== 'self');
71+
const selfEntry = entries.find(([key]) => key === 'self');
72+
73+
return html`
74+
${nonSelfEntries.map(([key, schema]) => html`
75+
<div class="field">
76+
<div class="label">${key.replace(/([A-Z])/g, ' $1').trim()}</div>
77+
<div class="value">${this.formatValue(this.item[key], schema, key)}</div>
78+
</div>
79+
`)}
80+
${selfEntry ? html`
81+
<div class="field">
82+
<div class="label">${selfEntry[0].replace(/([A-Z])/g, ' $1').trim()}</div>
83+
<div class="value">${this.formatValue(this.item[selfEntry[0]], selfEntry[1], selfEntry[0])}</div>
84+
</div>
85+
` : ''}
86+
`;
4787
}
4888

89+
const entries = Object.entries(this.item);
90+
const nonSelfEntries = entries.filter(([key]) => key !== 'self');
91+
const selfEntry = entries.find(([key]) => key === 'self');
92+
4993
return html`
50-
${Object.entries(this.schema.shape).map(([key, schema]) => html`
94+
${nonSelfEntries.map(([key, value]) => html`
5195
<div class="field">
5296
<div class="label">${key.replace(/([A-Z])/g, ' $1').trim()}</div>
53-
<div class="value">${this.formatValue(this.item[key], schema)}</div>
97+
<div class="value">${this.formatValue(value, undefined, key)}</div>
5498
</div>
5599
`)}
100+
${selfEntry ? html`
101+
<div class="field">
102+
<div class="label">${selfEntry[0].replace(/([A-Z])/g, ' $1').trim()}</div>
103+
<div class="value">${this.formatValue(selfEntry[1], undefined, selfEntry[0])}</div>
104+
</div>
105+
` : ''}
56106
`;
57107
}
58108

59-
formatValue(value: any, schema: any) {
109+
formatValue(value: any, schema?: any, key?: string) {
60110
if (value === null || value === undefined) {
61111
return '';
62112
}
63113

64-
switch (schema._def.typeName) {
65-
case 'ZodArray':
66-
case 'ZodObject':
67-
return html`<pre>${JSON.stringify(value, null, 2)}</pre>`;
68-
case 'ZodBoolean':
69-
return value ? '✓' : '✗';
70-
case 'ZodDate':
71-
return new Date(value).toLocaleString();
72-
default:
73-
return String(value);
114+
if (key === 'self') {
115+
return html`<span class="self-pill">${value.toString()}</span>`;
116+
}
117+
118+
if (schema) {
119+
switch (schema._def.typeName) {
120+
case 'ZodArray':
121+
case 'ZodObject':
122+
return html`<pre>${JSON.stringify(value, null, 2)}</pre>`;
123+
case 'ZodBoolean':
124+
return value ? '✓' : '✗';
125+
case 'ZodDate':
126+
return new Date(value).toLocaleString();
127+
case 'ZodString':
128+
return html`<div class="string-value">${value}</div>`;
129+
default:
130+
return String(value);
131+
}
74132
}
133+
134+
if (typeof value === 'object') {
135+
return html`<pre>${JSON.stringify(value, null, 2)}</pre>`;
136+
} else if (typeof value === 'boolean') {
137+
return value ? '✓' : '✗';
138+
} else if (value instanceof Date) {
139+
return value.toLocaleString();
140+
}
141+
return html`<div class="string-value">${value}</div>`;
75142
}
76143
}
144+
77145
@customElement("common-table")
78146
export class CommonTableElement extends LitElement {
79147
@property({ type: Object }) schema: ZodObject<any> = null;

typescript/packages/lookslike-high-level/src/data.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import { spellManager } from './spells/19_process_manager.jsx'
6262
import { shaderManager } from './spells/20_shader_editor.jsx'
6363
import { schemaGenerator } from './spells/21_model_builder.jsx'
6464
import { search } from './spells/22_search.jsx'
65+
import { notebook } from './spells/23_notes.jsx'
6566

6667
export type Charm = {
6768
[NAME]?: string;
@@ -262,6 +263,7 @@ addCharms([
262263
shaderManager.spawn({ shaderManager: 1 }),
263264
schemaGenerator.spawn({ schemaGenerator: 1 }),
264265
search.spawn({ search: 1 }),
266+
notebook.spawn({ notes: 1 }),
265267
FetchService.spawn() as any,
266268
GmailService.spawn() as any,
267269
ViewService.spawn() as any,

typescript/packages/lookslike-high-level/src/spells/16_contacts.tsx

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ import { event, subview, Transact } from "../sugar.js";
77
import { Charm, initRules, typedBehavior } from "./spell.jsx";
88
import { z } from "zod";
99
import { Reference } from "merkle-reference";
10-
import { resolve } from "../sugar/sugar.jsx";
10+
import { importEntity, resolve, tagWithSchema } from "../sugar/sugar.jsx";
1111
import { Ref, UiFragment } from "../sugar/zod.js";
1212

1313
const Contact = z.object({
1414
name: z.string().min(1).max(255).describe("The name of the contact"),
1515
email: z.string().email().describe("The email address of the contact"),
1616
phone: z.string().min(10).max(20).describe("The phone number of the contact"),
1717
// nickname: z.string().nullable().default(null).describe("The nickname of the contact"),
18-
});
18+
}).describe('Contact');
1919

2020
const AddressBook = z.object({
2121
focused: Ref.describe("The contact that is currently being edited"),
@@ -57,22 +57,17 @@ const contactEditor = typedBehavior(Contact, {
5757

5858
export const addressBook = typedBehavior(
5959
AddressBook.pick({
60-
focused: true,
60+
// focused: true,
6161
'~/common/ui/list': true
6262
}), {
63-
render: ({ self, focused, '~/common/ui/list': contactList }) => (
64-
<div entity={self} >
63+
render: ({ self, '~/common/ui/list': contactList }) => (
64+
<div entity={self} name="Contacts">
6565
<div>
66-
{focused ? (
67-
<div>
68-
<button onclick="~/on/close-editor">Close</button>
69-
<Charm self={focused} spell={contactEditor as any} />
70-
</div>
71-
) : <common-form
66+
<common-form
7267
schema={Contact}
7368
reset
7469
onsubmit="~/on/add-contact"
75-
/>}
70+
/>
7671
</div>
7772

7873
<br />
@@ -88,14 +83,16 @@ export const addressBook = typedBehavior(
8883
const ev = Session.resolve<SubmitEvent>(event);
8984
const contact = ev.detail.value;
9085

91-
cmd.add({ Import: contact })
92-
cmd.add(...Transact.assert(self, { contacts: refer(contact) }))
86+
const { self: id, instructions } = importEntity(contact, Contact)
87+
cmd.add(...instructions);
88+
cmd.add(...Transact.assert(self, { contacts: id }));
9389
}),
9490

9591
onEditContact: event("~/on/edit-contact")
9692
.transact(({ self, event }, cmd) => {
9793
const ev = Session.resolve<EditEvent>(event);
9894
cmd.add(...Transact.set(self, { focused: ev.detail.item }))
95+
cmd.add(...tagWithSchema(self, Contact))
9996
}),
10097

10198
onDeleteContact: event("~/on/delete-contact")

typescript/packages/lookslike-high-level/src/spells/18_music.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,27 @@ import { Ref, UiFragment } from "../sugar/zod.js";
1212

1313
export const Artist = z.object({
1414
name: z.string().min(1).max(255).describe("The name of the artist"),
15-
});
15+
}).describe('Artist');
1616

1717
export const Song = z.object({
1818
title: z.string().min(1).max(255).describe("The title of the song"),
1919
artists: z.array(Artist).min(1).describe("The artists who performed the song"),
2020
duration: z.number().min(1).describe("The duration in seconds"),
2121
year: z.number().min(1900).max(2100).describe("The release year")
22-
});
22+
}).describe('Song');
2323

2424
export const Album = z.object({
2525
"album/title": z.string().min(1).max(255).describe("The album title"),
2626
artist: Artist.describe("The primary artist"),
2727
songs: z.array(Song).min(1).describe("The songs on the album"),
2828
year: z.number().min(1900).max(2100).describe("The release year")
29-
});
29+
}).describe('Album');
3030

3131
const Playlist = z.object({
3232
name: z.string().min(1).max(255).describe("The playlist name"),
3333
description: z.string().max(1000).describe("The playlist description"),
3434
songs: z.array(Song).describe("The songs in the playlist")
35-
});
35+
}).describe('Playlist');
3636

3737
const MusicLibrary = z.object({
3838
focused: Ref.describe("The item that is currently being edited"),

typescript/packages/lookslike-high-level/src/spells/19_process_manager.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const Spell = z.object({
4545
sourceCode: z.string().min(1).max(8192).describe("The spell's source code"),
4646
notes: z.string().describe("Notes about the spell"),
4747
instances: z.array(Ref).describe("References to charm instances of this spell")
48-
});
48+
}).describe('Spell');
4949

5050
const Charm = z.object({
5151
spell: Ref.describe("Reference to the spell this charm instantiates"),
@@ -163,7 +163,7 @@ const spellEditor = typedBehavior(Spell, {
163163
const ev = Session.resolve<SubmitEvent<z.infer<typeof Spell>>>(event);
164164
const spell = ev.detail.value;
165165
cmd.add(...Transact.set(self, spell))
166-
cmd.add(tagWithSchema(self, Spell))
166+
cmd.add(...tagWithSchema(self, Spell))
167167
}),
168168

169169
onModifyWithAI: event("~/on/modify-with-ai")

typescript/packages/lookslike-high-level/src/spells/20_shader_editor.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ const SHADER_TEMPLATE = ` precision mediump float;
4747
// Define the core schemas
4848
export const Shader = z.object({
4949
name: z.string().min(1).max(255).describe("The name of the shader"),
50-
sourceCode: z.string().min(1).max(8192).describe("The shader's GLSL source code"),
50+
sourceCode: z.string().min(1).max(2 * 8192).describe("The shader's GLSL source code"),
5151
notes: z.string().describe("Notes about the shader")
52-
});
52+
}).describe('Shader');
5353

5454
const ShaderEditor = z.object({
5555
editingShader: Ref.describe("The shader currently being edited"),
@@ -107,7 +107,7 @@ const shaderEditor = typedBehavior(Shader, {
107107
const ev = Session.resolve<SubmitEvent<z.infer<typeof Shader>>>(event);
108108
const shader = ev.detail.value;
109109
cmd.add(...Transact.set(self, shader))
110-
cmd.add(tagWithSchema(self, Shader))
110+
cmd.add(...tagWithSchema(self, Shader))
111111
}),
112112

113113
onModifyWithAI: event("~/on/modify-with-ai")

0 commit comments

Comments
 (0)