[]]>> {
40 | return this.callZome('get_deleted_{{snake_case (plural from_referenceable.name)}}_for_{{snake_case to_referenceable.name}}', {{camel_case to_referenceable.singular_arg}});
41 | }
42 | {{/if}}
43 | {{/if}}
44 | {{/match_scope}}
45 | {{/merge}}
46 |
--------------------------------------------------------------------------------
/templates/zome/web-app/ui/demo/index.html.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
28 | {{title_case app_name}}
29 |
30 |
31 |
32 |
33 |
34 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/templates/zome/collection/ui/src/elements/{{kebab_case collection_name}}.ts.hbs:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from 'lit';
2 | import { state, customElement, property } from 'lit/decorators.js';
3 | import { AgentPubKey, EntryHash, ActionHash, Record } from '@holochain/client';
4 | import { SignalWatcher } from '@holochain-open-dev/signals';
5 | import { consume } from '@lit/context';
6 | import { localized, msg } from '@lit/localize';
7 | import { hashProperty, sharedStyles, wrapPathInSvg } from '@holochain-open-dev/elements';
8 | import { mdiInformationOutline } from '@mdi/js';
9 |
10 | import '@holochain-open-dev/elements/dist/elements/display-error.js';
11 | import '@shoelace-style/shoelace/dist/components/spinner/spinner.js';
12 | import '@shoelace-style/shoelace/dist/components/icon/icon.js';
13 |
14 | import './{{kebab_case referenceable.name}}-summary.js';
15 | import { {{pascal_case coordinator_zome_manifest.name}}Store } from '../{{kebab_case coordinator_zome_manifest.name}}-store.js';
16 | import { {{camel_case coordinator_zome_manifest.name}}StoreContext } from '../context.js';
17 |
18 | /**
19 | * @element {{kebab_case collection_name}}
20 | */
21 | @localized()
22 | @customElement('{{kebab_case collection_name}}')
23 | export class {{pascal_case collection_name}} extends SignalWatcher(LitElement) {
24 | {{#if (eq collection_type.type "ByAuthor")}}
25 |
26 | /**
27 | * REQUIRED. The author for which the {{plural (pascal_case referenceable.name)}} should be fetched
28 | */
29 | @property(hashProperty('author'))
30 | author!: AgentPubKey;
31 | {{/if}}
32 |
33 | /**
34 | * @internal
35 | */
36 | @consume({ context: {{camel_case coordinator_zome_manifest.name}}StoreContext, subscribe: true })
37 | {{camel_case coordinator_zome_manifest.name}}Store!: {{pascal_case coordinator_zome_manifest.name}}Store;
38 |
39 | {{#if (eq collection_type.type "ByAuthor")}}
40 | firstUpdated() {
41 | if (this.author === undefined) {
42 | throw new Error(`The author property is required for the {{pascal_case collection_name}} element`);
43 | }
44 | }
45 | {{/if}}
46 |
47 | renderList(hashes: Array<{{referenceable.hash_type}}>) {
48 | if (hashes.length === 0)
49 | return html`
50 |
55 | ${msg("No {{lower_case (plural referenceable.name)}} found")}
56 |
`;
57 |
58 | return html`
59 |
60 | ${hashes.map(hash =>
61 | html`<{{kebab_case referenceable.name}}-summary .{{camel_case referenceable.name}}Hash=${hash}>{{kebab_case referenceable.name}}-summary>`
62 | )}
63 |
64 | `;
65 | }
66 |
67 | render() {
68 | const map = this.{{camel_case coordinator_zome_manifest.name}}Store.{{camel_case collection_name}}{{#if (eq collection_type.type "ByAuthor")}}.get(this.author){{/if}}.get();
69 |
70 | switch (map.status) {
71 | case 'pending':
72 | return html`
73 |
74 |
`;
75 | case 'error':
76 | return html``;
80 | case 'completed':
81 | return this.renderList(Array.from(map.value.keys()));
82 | }
83 | }
84 |
85 | static styles = [sharedStyles];
86 | }
87 |
--------------------------------------------------------------------------------
/templates/app/collection/ui/src/{{dna_role_name}}/{{kebab_case coordinator_zome_manifest.name}}/elements/{{kebab_case collection_name}}.ts.hbs:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from 'lit';
2 | import { state, customElement, property } from 'lit/decorators.js';
3 | import { AgentPubKey, EntryHash, ActionHash, Record } from '@holochain/client';
4 | import { SignalWatcher } from '@holochain-open-dev/signals';
5 | import { consume } from '@lit/context';
6 | import { localized, msg } from '@lit/localize';
7 | import { hashProperty, wrapPathInSvg } from '@holochain-open-dev/elements';
8 | import { mdiInformationOutline } from '@mdi/js';
9 |
10 | import '@holochain-open-dev/elements/dist/elements/display-error.js';
11 | import '@shoelace-style/shoelace/dist/components/spinner/spinner.js';
12 | import '@shoelace-style/shoelace/dist/components/icon/icon.js';
13 |
14 | import { appStyles } from '../../../app-styles.js';
15 | import './{{kebab_case referenceable.name}}-summary.js';
16 | import { {{pascal_case coordinator_zome_manifest.name}}Store } from '../{{kebab_case coordinator_zome_manifest.name}}-store.js';
17 | import { {{camel_case coordinator_zome_manifest.name}}StoreContext } from '../context.js';
18 |
19 | /**
20 | * @element {{kebab_case collection_name}}
21 | */
22 | @localized()
23 | @customElement('{{kebab_case collection_name}}')
24 | export class {{pascal_case collection_name}} extends SignalWatcher(LitElement) {
25 | {{#if (eq collection_type.type "ByAuthor")}}
26 |
27 | /**
28 | * REQUIRED. The author for which the {{plural (pascal_case referenceable.name)}} should be fetched
29 | */
30 | @property(hashProperty('author'))
31 | author!: AgentPubKey;
32 | {{/if}}
33 |
34 | /**
35 | * @internal
36 | */
37 | @consume({ context: {{camel_case coordinator_zome_manifest.name}}StoreContext, subscribe: true })
38 | {{camel_case coordinator_zome_manifest.name}}Store!: {{pascal_case coordinator_zome_manifest.name}}Store;
39 |
40 | {{#if (eq collection_type.type "ByAuthor")}}
41 | firstUpdated() {
42 | if (this.author === undefined) {
43 | throw new Error(`The author property is required for the {{pascal_case collection_name}} element`);
44 | }
45 | }
46 | {{/if}}
47 |
48 | renderList(hashes: Array<{{referenceable.hash_type}}>) {
49 | if (hashes.length === 0)
50 | return html`
51 |
56 | ${msg("No {{lower_case (plural referenceable.name)}} found")}
57 |
`;
58 |
59 | return html`
60 |
61 | ${hashes.map(hash =>
62 | html`<{{kebab_case referenceable.name}}-summary .{{camel_case referenceable.name}}Hash=${hash}>{{kebab_case referenceable.name}}-summary>`
63 | )}
64 |
65 | `;
66 | }
67 |
68 | render() {
69 | const map = this.{{camel_case coordinator_zome_manifest.name}}Store.{{camel_case collection_name}}{{#if (eq collection_type.type "ByAuthor")}}.get(this.author){{/if}}.get();
70 |
71 | switch (map.status) {
72 | case 'pending':
73 | return html`
74 |
75 |
`;
76 | case 'error':
77 | return html``;
81 | case 'completed':
82 | return this.renderList(Array.from(map.value.keys()));
83 | }
84 | }
85 |
86 | static styles = appStyles;
87 | }
88 |
--------------------------------------------------------------------------------
/templates/zome/web-app/.github/workflows/build-and-cache-zomes.yaml.hbs:
--------------------------------------------------------------------------------
1 | name: "Build and cache zomes"
2 | on:
3 | push:
4 | branches: [ main ]
5 | pull_request:
6 | branches: [ main ]
7 |
8 | jobs:
9 | build-and-cache-zomes:
10 | strategy:
11 | matrix:
12 | os: [ubuntu-latest, macos-latest]
13 |
14 | runs-on: $\{{ matrix.os }}
15 | steps:
16 | - uses: actions/checkout@v3
17 |
18 | - uses: cachix/install-nix-action@v27
19 | with:
20 | github_access_token: ${{ secrets.GITHUB_TOKEN }}
21 | nix_path: nixpkgs=channel:nixos-24.05
22 |
23 | - uses: cachix/cachix-action@v15
24 | with:
25 | name: holochain-ci
26 |
27 | - uses: cachix/cachix-action@v15
28 | with:
29 | name: holochain-open-dev
30 |
31 | - name: Install and test
32 | run: |
33 | nix develop --no-update-lock-file --accept-flake-config --command bash -c "pnpm i && pnpm t && pnpm -F @holochain-open-dev/{{kebab_case app_name}} build"
34 |
35 | - name: 'Setup jq'
36 | uses: dcarbone/install-jq-action@v2
37 |
38 | - name: Build debug zomes
39 | env:
40 | CACHIX_AUTH_TOKEN: "$\{{ secrets.CACHIX_TOKEN_HOLOCHAIN_OPEN_DEV }}"
41 | run: |
42 | cachix watch-exec holochain-open-dev -- nix build --no-update-lock-file --accept-flake-config -L .#{{snake_case app_name}}_integrity
43 | cachix push holochain-open-dev $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}}_integrity | jq -- -r 'keys[0]')
44 |
45 | cachix watch-exec holochain-open-dev -- nix build --no-update-lock-file --accept-flake-config -L .#{{snake_case app_name}}
46 | cachix push holochain-open-dev $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}} | jq -- -r 'keys[0]')
47 |
48 | - name: Pin debug zomes
49 | if: github.event_name != 'pull_request'
50 | env:
51 | CACHIX_AUTH_TOKEN: "$\{{ secrets.CACHIX_TOKEN_HOLOCHAIN_OPEN_DEV }}"
52 | run: |
53 | cachix pin holochain-open-dev {{snake_case app_name}}_integrity_debug $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}}_integrity | jq -- -r 'keys[0]')
54 | cachix pin holochain-open-dev {{snake_case app_name}}_debug $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}} | jq -- -r 'keys[0]')
55 |
56 | - name: Build release zomes
57 | if: matrix.os == 'ubuntu-latest'
58 | env:
59 | CACHIX_AUTH_TOKEN: "$\{{ secrets.CACHIX_TOKEN_HOLOCHAIN_OPEN_DEV }}"
60 | run: |
61 | cachix watch-exec holochain-open-dev -- nix build --no-update-lock-file --accept-flake-config -L .#{{snake_case app_name}}_integrity.meta.release
62 | cachix push holochain-open-dev $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}}_integrity.meta.release | jq -- -r 'keys[0]')
63 |
64 | cachix watch-exec holochain-open-dev -- nix build --no-update-lock-file --accept-flake-config -L .#{{snake_case app_name}}.meta.release
65 | cachix push holochain-open-dev $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}}.meta.release | jq -- -r 'keys[0]')
66 |
67 | - name: Pin release zomes
68 | if: github.event_name != 'pull_request' && matrix.os == 'ubuntu-latest'
69 | env:
70 | CACHIX_AUTH_TOKEN: "$\{{ secrets.CACHIX_TOKEN_HOLOCHAIN_OPEN_DEV }}"
71 | run: |
72 | cachix pin holochain-open-dev {{snake_case app_name}}_integrity_debug $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}}_integrity | jq -- -r 'keys[0]')
73 | cachix pin holochain-open-dev {{snake_case app_name}}_debug $(nix path-info --json --accept-flake-config --no-warn-dirty .#{{snake_case app_name}} | jq -- -r 'keys[0]')
74 |
75 |
--------------------------------------------------------------------------------
/templates/app/web-app/ui/src/holochain-app.ts.hbs:
--------------------------------------------------------------------------------
1 |
2 | import { LitElement, css, html } from 'lit';
3 | import { property, state, customElement } from 'lit/decorators.js';
4 | import { AppWebsocket, AppClient, ActionHash } from '@holochain/client';
5 | import { SignalWatcher } from '@holochain-open-dev/signals';
6 | import { Router } from '@holochain-open-dev/elements';
7 | import { provide } from '@lit/context';
8 | import { localized, msg } from '@lit/localize';
9 | import {
10 | Profile,
11 | ProfilesClient,
12 | ProfilesStore,
13 | profilesStoreContext
14 | } from '@holochain-open-dev/profiles';
15 | import { EntryRecord } from '@holochain-open-dev/utils';
16 |
17 | import '@holochain-open-dev/elements/dist/elements/display-error.js';
18 | import '@holochain-open-dev/profiles/dist/elements/profile-prompt.js';
19 | import '@holochain-open-dev/profiles/dist/elements/my-profile.js';
20 | import '@shoelace-style/shoelace/dist/components/spinner/spinner.js';
21 | import '@shoelace-style/shoelace/dist/components/icon-button/icon-button.js';
22 |
23 | import { rootRouterContext } from './context.js';
24 | import { appStyles } from './app-styles.js';
25 | import './home-page.js';
26 |
27 | @localized()
28 | @customElement('holochain-app')
29 | export class HolochainApp extends SignalWatcher(LitElement) {
30 | @state() _loading = true;
31 | @state() _view = { view: 'main' };
32 | @state() _error: unknown | undefined;
33 |
34 | @provide({ context: profilesStoreContext })
35 | @property()
36 | _profilesStore!: ProfilesStore;
37 |
38 | _client!: AppClient;
39 |
40 | @provide({ context: rootRouterContext })
41 | router = new Router(this, [
42 | {
43 | path: "/",
44 | enter: () => {
45 | // Redirect to "/home/"
46 | this.router.goto("/home/");
47 | return false;
48 | },
49 | },
50 | {
51 | path: "/home/*",
52 | render: () => html``,
53 | },
54 | {
55 | path: "/my-profile",
56 | render: () => this.renderMyProfilePage(),
57 | },
58 | ]);
59 |
60 | async firstUpdated() {
61 | try {
62 | this._client = await AppWebsocket.connect();
63 | await this.initStores(this._client);
64 | } catch (e: unknown) {
65 | this._error = e;
66 | } finally {
67 | this._loading = false;
68 | }
69 | }
70 |
71 | // Don't change this
72 | async initStores(appClient: AppClient) {
73 | this._profilesStore = new ProfilesStore(new ProfilesClient(appClient, 'TODO:REPLACE_ME_WITH_THE_DNA_WITH_THE_PROFILES_ZOME'));
74 | }
75 |
76 | renderMyProfilePage() {
77 | return html`
78 |
79 |
80 | this.router.pop()}
83 | >
84 | ${msg("{{title_case app_name}}")}
85 |
86 |
87 |
88 |
89 | `;
90 | }
91 |
92 | render() {
93 | if (this._loading)
94 | return html`
98 |
99 |
`;
100 |
101 | if (this._error)
102 | return html`
103 |
104 |
105 |
106 |
107 | `;
108 |
109 | return html`
110 |
111 | ${this.router.outlet()}
112 |
113 | `;
114 | }
115 |
116 | static styles = [
117 | css`
118 | :host {
119 | display: flex;
120 | flex: 1;
121 | }
122 | `,
123 | ...appStyles,
124 | ];
125 | }
126 |
--------------------------------------------------------------------------------
/templates/zome/collection/docs/elements/{{kebab_case collection_name}}.md.hbs:
--------------------------------------------------------------------------------
1 | # `<{{kebab_case collection_name}}>`
2 |
3 | ## Usage
4 |
5 | 0. If you haven't already, [go through the setup for the module](/setup).
6 |
7 | 1. Import the `<{{kebab_case collection_name}}>` element somewhere in the javascript side of your web-app like this:
8 |
9 | ```js
10 | import '@holochain-open-dev/{{kebab_case coordinator_zome_manifest.name}}/dist/elements/{{kebab_case collection_name}}.js'
11 | ```
12 |
13 | 2. Use it in the html side of your web-app like this:
14 |
15 | ```html
16 | <{{kebab_case collection_name}}>
17 | {{kebab_case collection_name}}>
18 | ```
19 |
20 | > [!WARNING]
21 | > Like all the elements in this module, `<{{kebab_case collection_name}}>` needs to be placed inside an initialized `<{{kebab_case coordinator_zome_manifest.name}}-context>`.
22 |
23 | ## Demo
24 |
25 | Here is an interactive demo of the element:
26 |
27 |
28 |
29 |
30 |
83 |
84 | ## API Reference
85 |
86 | `<{{kebab_case collection_name}}>` is a [custom element](https://web.dev/articles/custom-elements-v1), which means that it can be used in any web app or website. Here is the reference for its API:
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/templates/app/web-app/ui/src/home-page.ts.hbs:
--------------------------------------------------------------------------------
1 | import { Router, Routes } from "@holochain-open-dev/elements";
2 | import { AsyncResult, SignalWatcher } from "@holochain-open-dev/signals";
3 | import { ProfilesStore, profilesStoreContext } from "@holochain-open-dev/profiles";
4 | import { LitElement, css, html } from "lit";
5 | import { customElement, property } from "lit/decorators.js";
6 | import { EntryRecord } from "@holochain-open-dev/utils";
7 | import { consume } from "@lit/context";
8 | import { msg } from "@lit/localize";
9 |
10 | import "@shoelace-style/shoelace/dist/components/tab-group/tab-group.js";
11 | import "@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.js";
12 | import '@holochain-open-dev/profiles/dist/elements/profile-list-item-skeleton.js';
13 | import '@holochain-open-dev/profiles/dist/elements/agent-avatar.js';
14 |
15 | import { rootRouterContext } from "./context.js";
16 | import { appStyles } from './app-styles.js';
17 |
18 | @customElement("home-page")
19 | export class HomePage extends SignalWatcher(LitElement) {
20 |
21 | /**
22 | * @internal
23 | */
24 | @consume({ context: rootRouterContext, subscribe: true })
25 | rootRouter!: Router;
26 |
27 | /**
28 | * @internal
29 | */
30 | @consume({ context: profilesStoreContext, subscribe: true })
31 | @property()
32 | _profilesStore!: ProfilesStore;
33 |
34 | routes = new Routes(this, [
35 | {
36 | path: "",
37 | enter: () => {
38 | this.routes.goto("tab1/");
39 | return false;
40 | },
41 | },
42 | {
43 | path: "tab1/*",
44 | render: () => html`TODO: replace me
`,
45 | },
46 | {
47 | path: "tab2/*",
48 | render: () => html`TODO: replace me
`,
49 | },
50 | {
51 | path: "tab3/",
52 | render: () => html`TODO: replace me
`,
53 | },
54 | ]);
55 |
56 | renderMyProfile() {
57 | const myProfile = this._profilesStore.myProfile.get();
58 |
59 | switch (myProfile.status) {
60 | case 'pending':
61 | return html``;
62 | case 'error':
63 | return html``;
68 | case 'completed':
69 | return html`
74 |
75 |
${myProfile.value?.entry.nickname}
76 |
`;
77 | }
78 | }
79 |
80 | render() {
81 | return html`
82 |
83 |
84 |
${msg("{{title_case app_name}}")}
85 |
86 |
87 | ${this.renderMyProfile()}
88 |
89 |
90 |
91 |
92 | {
96 | this.routes.goto("orders/");
97 | }}
98 | >${msg("Orders")}
100 | {
104 | this.routes.goto("producers/");
105 | }}
106 | >${msg("Producers")}
108 | {
112 | this.routes.goto("members/");
113 | }}
114 | >${msg("Members")}
116 |
117 | ${this.routes.outlet()}
118 |
119 |
120 | `;
121 | }
122 |
123 | static styles = [
124 | css`
125 | :host {
126 | display: flex;
127 | flex: 1;
128 | }
129 |
130 | `,
131 | ...appStyles,
132 | ];
133 | }
134 |
--------------------------------------------------------------------------------
/templates/zome/entry-type/ui/src/elements/{{kebab_case entry_type.name}}-summary.ts.hbs:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from 'lit';
2 | import { state, property, customElement } from 'lit/decorators.js';
3 | import { EntryHash, Record, ActionHash } from '@holochain/client';
4 | import { EntryRecord } from '@holochain-open-dev/utils';
5 | import { SignalWatcher } from '@holochain-open-dev/signals';
6 | import { hashProperty, sharedStyles } from '@holochain-open-dev/elements';
7 | import { consume } from '@lit/context';
8 |
9 | import { localized, msg } from '@lit/localize';
10 |
11 | {{#uniq_lines}}
12 | import '@shoelace-style/shoelace/dist/components/card/card.js';
13 | import '@shoelace-style/shoelace/dist/components/spinner/spinner.js';
14 | import '@holochain-open-dev/elements/dist/elements/display-error.js';
15 | {{#each entry_type.fields}}
16 | {{#if widget}}
17 | {{> (concat field_type.type "/" widget "/detail/imports") }}
18 |
19 | {{/if}}
20 | {{/each}}
21 | {{/uniq_lines}}
22 |
23 | import { {{pascal_case coordinator_zome_manifest.name}}Store } from '../{{kebab_case coordinator_zome_manifest.name}}-store.js';
24 | import { {{camel_case coordinator_zome_manifest.name}}StoreContext } from '../context.js';
25 | import { {{pascal_case entry_type.name}}{{#each entry_type.fields}}{{#if (eq field_type.type "Enum")}}, {{field_type.label}}{{/if}}{{/each}} } from '../types.js';
26 |
27 | /**
28 | * @element {{kebab_case entry_type.name}}-summary
29 | * @fires {{kebab_case entry_type.name}}-selected: detail will contain { {{camel_case entry_type.name}}Hash }
30 | */
31 | @localized()
32 | @customElement('{{kebab_case entry_type.name}}-summary')
33 | export class {{pascal_case entry_type.name}}Summary extends SignalWatcher(LitElement) {
34 |
35 | /**
36 | * REQUIRED. The hash of the {{pascal_case entry_type.name}} to show
37 | */
38 | @property(hashProperty('{{kebab_case entry_type.name}}-hash'))
39 | {{camel_case entry_type.name}}Hash!: {{#if entry_type.reference_entry_hash}}EntryHash{{else}}ActionHash{{/if}};
40 |
41 | /**
42 | * @internal
43 | */
44 | @consume({ context: {{camel_case coordinator_zome_manifest.name}}StoreContext, subscribe: true })
45 | {{camel_case coordinator_zome_manifest.name}}Store!: {{pascal_case coordinator_zome_manifest.name}}Store;
46 |
47 | renderSummary(entryRecord: EntryRecord<{{pascal_case entry_type.name}}>) {
48 | return html`
49 |
50 |
51 | {{#each entry_type.fields}}
52 | {{#if widget}}
53 |
54 | ${msg("{{title_case field_name}}")}
55 | {{#if (not (eq cardinality "vector") )}}
56 | {{> (concat field_type.type "/" widget "/detail/render") field_name=field_name variable_to_read=(concat "entryRecord.entry." (snake_case field_name) ) }}
57 | {{else}}
58 | {{> Vec/detail/render variable_to_read=(concat "entryRecord.entry." (snake_case field_name) ) field_name=field_name field_type=field_type widget=widget }}
59 | {{/if}}
60 |
61 |
62 | {{/if}}
63 | {{/each}}
64 |
65 | `;
66 | }
67 |
68 | render{{pascal_case entry_type.name}}() {
69 | const {{camel_case entry_type.name}} = this.{{camel_case coordinator_zome_manifest.name}}Store.{{camel_case (plural entry_type.name)}}.get(this.{{camel_case entry_type.name}}Hash).{{#if crud.update}}latestVersion{{else}}entry{{/if}}.get();
70 |
71 | switch ({{camel_case entry_type.name}}.status) {
72 | case 'pending':
73 | return html`
75 |
76 |
`;
77 | case 'error':
78 | return html``;
82 | case 'completed':
83 | return this.renderSummary({{camel_case entry_type.name}}.value);
84 | }
85 | }
86 |
87 | render() {
88 | return html` this.dispatchEvent(new CustomEvent('{{kebab_case entry_type.name}}-selected', {
89 | composed: true,
90 | bubbles: true,
91 | detail: {
92 | {{camel_case entry_type.name}}Hash: this.{{camel_case entry_type.name}}Hash
93 | }
94 | }))}>
95 | ${this.render{{pascal_case entry_type.name}}()}
96 | `;
97 | }
98 |
99 |
100 | static styles = [sharedStyles];
101 | }
102 |
--------------------------------------------------------------------------------
/templates/app/entry-type/ui/src/{{dna_role_name}}/{{kebab_case coordinator_zome_manifest.name}}/elements/{{kebab_case entry_type.name}}-summary.ts.hbs:
--------------------------------------------------------------------------------
1 | import { LitElement, html } from 'lit';
2 | import { state, property, customElement } from 'lit/decorators.js';
3 | import { EntryHash, Record, ActionHash } from '@holochain/client';
4 | import { EntryRecord } from '@holochain-open-dev/utils';
5 | import { SignalWatcher } from '@holochain-open-dev/signals';
6 | import { hashProperty } from '@holochain-open-dev/elements';
7 | import { consume } from '@lit/context';
8 |
9 | import { localized, msg } from '@lit/localize';
10 |
11 | {{#uniq_lines}}
12 | import '@shoelace-style/shoelace/dist/components/card/card.js';
13 | import '@shoelace-style/shoelace/dist/components/spinner/spinner.js';
14 | import '@holochain-open-dev/elements/dist/elements/display-error.js';
15 | {{#each entry_type.fields}}
16 | {{#if widget}}
17 | {{> (concat field_type.type "/" widget "/detail/imports") }}
18 |
19 | {{/if}}
20 | {{/each}}
21 | {{/uniq_lines}}
22 |
23 | import { appStyles } from '../../../app-styles.js';
24 | import { {{pascal_case coordinator_zome_manifest.name}}Store } from '../{{kebab_case coordinator_zome_manifest.name}}-store.js';
25 | import { {{camel_case coordinator_zome_manifest.name}}StoreContext } from '../context.js';
26 | import { {{pascal_case entry_type.name}}{{#each entry_type.fields}}{{#if (eq field_type.type "Enum")}}, {{field_type.label}}{{/if}}{{/each}} } from '../types.js';
27 |
28 | /**
29 | * @element {{kebab_case entry_type.name}}-summary
30 | * @fires {{kebab_case entry_type.name}}-selected: detail will contain { {{camel_case entry_type.name}}Hash }
31 | */
32 | @localized()
33 | @customElement('{{kebab_case entry_type.name}}-summary')
34 | export class {{pascal_case entry_type.name}}Summary extends SignalWatcher(LitElement) {
35 |
36 | /**
37 | * REQUIRED. The hash of the {{pascal_case entry_type.name}} to show
38 | */
39 | @property(hashProperty('{{kebab_case entry_type.name}}-hash'))
40 | {{camel_case entry_type.name}}Hash!: {{#if entry_type.reference_entry_hash}}EntryHash{{else}}ActionHash{{/if}};
41 |
42 | /**
43 | * @internal
44 | */
45 | @consume({ context: {{camel_case coordinator_zome_manifest.name}}StoreContext, subscribe: true })
46 | {{camel_case coordinator_zome_manifest.name}}Store!: {{pascal_case coordinator_zome_manifest.name}}Store;
47 |
48 | renderSummary(entryRecord: EntryRecord<{{pascal_case entry_type.name}}>) {
49 | return html`
50 |
51 |
52 | {{#each entry_type.fields}}
53 | {{#if widget}}
54 |
55 | ${msg("{{title_case field_name}}")}
56 | {{#if (not (eq cardinality "vector") )}}
57 | {{> (concat field_type.type "/" widget "/detail/render") field_name=field_name variable_to_read=(concat "entryRecord.entry." (snake_case field_name) ) }}
58 | {{else}}
59 | {{> Vec/detail/render variable_to_read=(concat "entryRecord.entry." (snake_case field_name) ) field_name=field_name field_type=field_type widget=widget }}
60 | {{/if}}
61 |
62 |
63 | {{/if}}
64 | {{/each}}
65 |
66 | `;
67 | }
68 |
69 | render{{pascal_case entry_type.name}}() {
70 | const {{camel_case entry_type.name}} = this.{{camel_case coordinator_zome_manifest.name}}Store.{{camel_case (plural entry_type.name)}}.get(this.{{camel_case entry_type.name}}Hash).{{#if crud.update}}latestVersion{{else}}entry{{/if}}.get();
71 |
72 | switch ({{camel_case entry_type.name}}.status) {
73 | case 'pending':
74 | return html`
76 |
77 |
`;
78 | case 'error':
79 | return html``;
83 | case 'completed':
84 | return this.renderSummary({{camel_case entry_type.name}}.value);
85 | }
86 | }
87 |
88 | render() {
89 | return html` this.dispatchEvent(new CustomEvent('{{kebab_case entry_type.name}}-selected', {
90 | composed: true,
91 | bubbles: true,
92 | detail: {
93 | {{camel_case entry_type.name}}Hash: this.{{camel_case entry_type.name}}Hash
94 | }
95 | }))}>
96 | ${this.render{{pascal_case entry_type.name}}()}
97 | `;
98 | }
99 |
100 |
101 | static styles = appStyles;
102 | }
103 |
--------------------------------------------------------------------------------