forked from holochain/scaffolding
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add react template (holochain#295)
* WIP * update ui module * add react to matched ui framework strings * hbsify templates * add base react components * react collection * react detail component * react create component * react edit template * react entry type for linked from component * field types * react link type components * fix field types * template swoop; fix issues * add missing imports, strip out eslint * fix images * refactor holochain provider * fix entry-type templates * fix link-type templates * correctly name field type widgets * add forum example * fix holochain context * check for links lengths before setting state * fix text field * styling improvments * extend base styles * improve example styling * fix mismatched components * remove ui readme * fix templates * fix imports * update elements and imports * type app signal callback * test with react template in ci * update styling * fix global styles * rename and move client context * make client context compatible with holo * fix indentation in templates * update client context template * fix entry-types for linked from component props * update detail components * add default field types * fix example app.tsx * fix vec detail render * fix vec edit render * fix timestamp * fix client context not updating loading state * fix vec input * fix vec input setters in edit components * Update templates/react/field-types/u32/NumberInput/edit/render.hbs Co-authored-by: Paul d'Aoust <amillionlobsters@gmail.com> * Update templates/react/field-types/Timestamp/DateTimePicker/edit/render.hbs Co-authored-by: Paul d'Aoust <amillionlobsters@gmail.com> * Update templates/react/field-types/Timestamp/DateTimePicker/edit/render.hbs Co-authored-by: Paul d'Aoust <amillionlobsters@gmail.com> * set default and initial values for boolean inputs to false * ensure previous zip file is deleted * fix templates --------- Co-authored-by: Paul d'Aoust <amillionlobsters@gmail.com>
- Loading branch information
Showing
104 changed files
with
2,344 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{{#if (eq collection_type.type "Global")}} | ||
At first, the UI for this application is empty. If you want the newly scaffolded collection to be the entry point for its UI, import the newly | ||
generated <{{pascal_case collection_name}} /> component | ||
{{/if}} |
77 changes: 77 additions & 0 deletions
77
...role_name}}/{{coordinator_zome_manifest.name}}/{{kebab_case collection_name}}.test.ts.hbs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { assert, test } from "vitest"; | ||
|
||
import { runScenario, dhtSync, CallableCell } from '@holochain/tryorama'; | ||
import { | ||
NewEntryAction, | ||
ActionHash, | ||
Record, | ||
Link, | ||
AppBundleSource, | ||
fakeActionHash, | ||
fakeAgentPubKey, | ||
fakeEntryHash | ||
} from '@holochain/client'; | ||
import { decode } from '@msgpack/msgpack'; | ||
|
||
import { create{{pascal_case referenceable.name}} } from './common.js'; | ||
|
||
test('create a {{pascal_case referenceable.name}} and get {{lower_case collection_name}}', async () => { | ||
await runScenario(async scenario => { | ||
// Construct proper paths for your app. | ||
// This assumes app bundle created by the `hc app pack` command. | ||
const testAppPath = process.cwd() + '/../workdir/{{app_name}}.happ'; | ||
|
||
// Set up the app to be installed | ||
const appSource = { appBundleSource: { path: testAppPath } }; | ||
|
||
// Add 2 players with the test app to the Scenario. The returned players | ||
// can be destructured. | ||
const [alice, bob] = await scenario.addPlayersWithApps([appSource, appSource]); | ||
|
||
// Shortcut peer discovery through gossip and register all agents in every | ||
// conductor of the scenario. | ||
await scenario.shareAllAgents(); | ||
|
||
// Bob gets {{lower_case collection_name}} | ||
let collectionOutput: Link[] = await bob.cells[0].callZome({ | ||
zome_name: "{{coordinator_zome_manifest.name}}", | ||
fn_name: "get_{{snake_case collection_name}}", | ||
payload: {{#if (eq collection_type.type "Global")}}null{{else}}alice.agentPubKey{{/if}} | ||
}); | ||
assert.equal(collectionOutput.length, 0); | ||
|
||
// Alice creates a {{pascal_case referenceable.name}} | ||
const createRecord: Record = await create{{pascal_case referenceable.name}}(alice.cells[0]); | ||
assert.ok(createRecord); | ||
|
||
await dhtSync([alice, bob], alice.cells[0].cell_id[0]); | ||
|
||
// Bob gets {{lower_case collection_name}} again | ||
collectionOutput = await bob.cells[0].callZome({ | ||
zome_name: "{{coordinator_zome_manifest.name}}", | ||
fn_name: "get_{{snake_case collection_name}}", | ||
payload: {{#if (eq collection_type.type "Global")}}null{{else}}alice.agentPubKey{{/if}} | ||
}); | ||
assert.equal(collectionOutput.length, 1); | ||
assert.deepEqual({{#if (eq referenceable.hash_type "EntryHash")}}(createRecord.signed_action.hashed.content as NewEntryAction).entry_hash{{else}}createRecord.signed_action.hashed.hash{{/if}}, collectionOutput[0].target); | ||
{{#if (and deletable (eq referenceable.hash_type "ActionHash"))}} | ||
|
||
// Alice deletes the {{pascal_case referenceable.name}} | ||
await alice.cells[0].callZome({ | ||
zome_name: "{{coordinator_zome_manifest.name}}", | ||
fn_name: "delete_{{snake_case referenceable.name}}", | ||
payload: createRecord.signed_action.hashed.hash | ||
}); | ||
|
||
await dhtSync([alice, bob], alice.cells[0].cell_id[0]); | ||
|
||
// Bob gets {{lower_case collection_name}} again | ||
collectionOutput = await bob.cells[0].callZome({ | ||
zome_name: "{{coordinator_zome_manifest.name}}", | ||
fn_name: "get_{{snake_case collection_name}}", | ||
payload: {{#if (eq collection_type.type "Global")}}null{{else}}alice.agentPubKey{{/if}} | ||
}); | ||
assert.equal(collectionOutput.length, 0); | ||
{{/if}} | ||
}); | ||
}); |
82 changes: 82 additions & 0 deletions
82
...na_role_name}}/{{coordinator_zome_manifest.name}}/{{pascal_case collection_name}}.tsx.hbs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { Link, AppSignal, HolochainError{{#if (eq collection_type.type "ByAuthor")}}, AgentPubKey{{/if}}{{#if (eq referenceable.hash_type "EntryHash")}}, NewEntryAction{{/if}} } from '@holochain/client'; | ||
import { FC, useCallback, useState, useEffect, useContext } from 'react'; | ||
|
||
import type { {{pascal_case coordinator_zome_manifest.name}}Signal } from './types'; | ||
import {{pascal_case referenceable.name}}Detail from './{{pascal_case referenceable.name}}Detail'; | ||
import { ClientContext } from '../../ClientContext'; | ||
|
||
const {{pascal_case collection_name}}: FC{{#if (eq collection_type.type "ByAuthor")}}<{{pascal_case collection_name}}Props>{{/if}} = ({{#if (eq collection_type.type "ByAuthor")}}{author}{{/if}}) => { | ||
const {client} = useContext(ClientContext); | ||
const [hashes, setHashes] = useState<Uint8Array[]>([]); | ||
const [loading, setLoading] = useState(false); | ||
const [error, setError] = useState<HolochainError | undefined>(); | ||
|
||
const fetch{{pascal_case (plural referenceable.name)}} = useCallback(async () => { | ||
setLoading(true) | ||
try { | ||
const links: Link[] = await client?.callZome({ | ||
cap_secret: null, | ||
role_name: '{{dna_role_name}}', | ||
zome_name: '{{snake_case coordinator_zome_manifest.name}}', | ||
fn_name: 'get_{{snake_case collection_name}}', | ||
payload: {{#if (eq collection_type.type "ByAuthor")}}author{{else}}null{{/if}}, | ||
}); | ||
if (links?.length) { | ||
setHashes(links.map((l) => l.target)); | ||
} | ||
} catch (e) { | ||
setError(e as HolochainError); | ||
} finally { | ||
setLoading(false); | ||
} | ||
}, [client{{#if (eq collection_type.type "ByAuthor")}}, author{{/if}}]); | ||
|
||
const handleSignal = useCallback((signal: AppSignal) => { | ||
if (signal.zome_name !== '{{coordinator_zome_manifest.name}}') return; | ||
const payload = signal.payload as {{pascal_case coordinator_zome_manifest.name}}Signal; | ||
if (payload.type !== 'EntryCreated') return; | ||
if (payload.app_entry.type !== '{{pascal_case referenceable.name}}') return; | ||
{{#if (eq collection_type.type "ByAuthor")}} | ||
if (author.toString() !== client?.myPubKey.toString()) return; | ||
{{/if}} | ||
setHashes((prevHashes) => [...prevHashes, {{#if (eq referenceable.hash_type "ActionHash")}}payload.action.hashed.hash{{else}}(payload.action.hashed.content as NewEntryAction).entry_hash{{/if}}]); | ||
}, [setHashes]); | ||
|
||
useEffect(() => { | ||
{{#if (eq collection_type.type "ByAuthor")}} | ||
if (author === undefined) { | ||
throw new Error(`The author prop is required for the {{pascal_case collection_name}} element`); | ||
} | ||
{{/if}} | ||
fetch{{pascal_case (plural referenceable.name)}}(); | ||
client?.on('signal', handleSignal); | ||
}, [client, handleSignal, fetch{{pascal_case (plural referenceable.name)}}{{#if (eq collection_type.type "ByAuthor")}}, author{{/if}}]); | ||
|
||
if (loading) { | ||
return <progress />; | ||
} | ||
|
||
return ( | ||
<div> | ||
{error ? ( | ||
<span>Error fetching the {{lower_case (plural referenceable.name)}}: {error.message}</span> | ||
) : hashes.length > 0 ? ( | ||
<div> | ||
{hashes.map((hash, i) => ( | ||
<{{pascal_case referenceable.name}}Detail key={i} {{camel_case referenceable.name}}Hash={hash} on{{pascal_case referenceable.name}}Deleted={fetch{{pascal_case (plural referenceable.name)}}} /> | ||
))} | ||
</div> | ||
) : ( | ||
<article>No {{lower_case (plural referenceable.name)}} found{{#if (eq collection_type.type "ByAuthor")}} for this author{{/if}}.</article> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
{{#if (eq collection_type.type "ByAuthor")}} | ||
interface {{pascal_case collection_name}}Props { | ||
author: AgentPubKey | ||
} | ||
{{/if}} | ||
|
||
export default {{pascal_case collection_name}}; |
3 changes: 3 additions & 0 deletions
3
...s/react/coordinator-zome/tests/src/{{dna_role_name}}/{{zome_manifest.name}}/common.ts.hbs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { CallableCell } from '@holochain/tryorama'; | ||
import { NewEntryAction, ActionHash, Record, AppBundleSource, fakeActionHash, fakeAgentPubKey, fakeEntryHash, fakeDnaHash } from '@holochain/client'; | ||
|
38 changes: 38 additions & 0 deletions
38
...lates/react/coordinator-zome/ui/src/{{dna_role_name}}/{{zome_manifest.name}}/types.ts.hbs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import type { | ||
Record, | ||
ActionHash, | ||
DnaHash, | ||
SignedActionHashed, | ||
EntryHash, | ||
AgentPubKey, | ||
Create, | ||
Update, | ||
Delete, | ||
CreateLink, | ||
DeleteLink | ||
} from '@holochain/client'; | ||
|
||
export type {{pascal_case zome_manifest.name}}Signal = { | ||
type: 'EntryCreated'; | ||
action: SignedActionHashed<Create>; | ||
app_entry: EntryTypes; | ||
} | { | ||
type: 'EntryUpdated'; | ||
action: SignedActionHashed<Update>; | ||
app_entry: EntryTypes; | ||
original_app_entry: EntryTypes; | ||
} | { | ||
type: 'EntryDeleted'; | ||
action: SignedActionHashed<Delete>; | ||
original_app_entry: EntryTypes; | ||
} | { | ||
type: 'LinkCreated'; | ||
action: SignedActionHashed<CreateLink>; | ||
link_type: string; | ||
} | { | ||
type: 'LinkDeleted'; | ||
action: SignedActionHashed<DeleteLink>; | ||
link_type: string; | ||
}; | ||
|
||
export type EntryTypes = {}; |
53 changes: 53 additions & 0 deletions
53
...t/entry-type/tests/src/{{dna_role_name}}/{{coordinator_zome_manifest.name}}/common.ts.hbs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
{{previous_file_content}} | ||
|
||
export async function sample{{pascal_case entry_type.name}}(cell: CallableCell, partial{{pascal_case entry_type.name}} = {}) { | ||
return { | ||
...{ | ||
{{#each entry_type.fields}} | ||
{{#if linked_from}} | ||
{{#if (ne linked_from.hash_type "AgentPubKey")}} | ||
{{#if (eq cardinality "vector")}} | ||
{{#if (eq (pascal_case linked_from.name) (pascal_case ../entry_type.name))}} | ||
{{field_name}}: [], | ||
{{else}} | ||
{{#if (eq linked_from.hash_type "ActionHash")}} | ||
{{field_name}}: [(await create{{pascal_case linked_from.name}}(cell)).signed_action.hashed.hash], | ||
{{else}} | ||
{{field_name}}: [((await create{{pascal_case linked_from.name}}(cell)).signed_action.hashed.content as NewEntryAction).entry_hash], | ||
{{/if}} | ||
{{/if}} | ||
{{else}} | ||
{{#if (eq (pascal_case linked_from.name) (pascal_case ../entry_type.name))}} | ||
{{field_name}}: null, | ||
{{else}} | ||
{{#if (eq linked_from.hash_type "ActionHash")}} | ||
{{field_name}}: (await create{{pascal_case linked_from.name}}(cell)).signed_action.hashed.hash, | ||
{{else}} | ||
{{field_name}}: ((await create{{pascal_case linked_from.name}}(cell)).signed_action.hashed.content as NewEntryAction).entry_hash, | ||
{{/if}} | ||
{{/if}} | ||
{{/if}} | ||
{{else}} | ||
{{field_name}}: cell.cell_id[1], | ||
{{/if}} | ||
{{else}} | ||
{{#if (eq cardinality "vector")}} | ||
{{field_name}}: [{{> (concat field_type.type "/sample") field_type=field_type}}], | ||
{{else}} | ||
{{field_name}}: {{> (concat field_type.type "/sample") field_type=field_type}}, | ||
{{/if}} | ||
{{/if}} | ||
{{/each}} | ||
}, | ||
...partial{{pascal_case entry_type.name}} | ||
}; | ||
} | ||
|
||
export async function create{{pascal_case entry_type.name}}(cell: CallableCell, {{camel_case entry_type.name}} = undefined): Promise<Record> { | ||
return cell.callZome({ | ||
zome_name: "{{coordinator_zome_manifest.name}}", | ||
fn_name: "create_{{snake_case entry_type.name}}", | ||
payload: {{camel_case entry_type.name}} || await sample{{pascal_case entry_type.name}}(cell), | ||
}); | ||
} | ||
|
Oops, something went wrong.