From 388bb9a95e44b8a787c74d20707fb4166c52d335 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 8 Oct 2024 12:17:19 +0200 Subject: [PATCH 1/5] add custom logic to get all profiles and use custom profile-detail component --- cli/package.json | 4 +- .../src/elements/reusable/profile-detail.ts | 150 ++++++++++++++++++ .../src/groups/elements/group-home.ts | 6 +- .../src/groups/elements/group-peers-status.ts | 40 +++-- .../src/groups/elements/stewards-settings.ts | 8 +- src/renderer/src/groups/group-store.ts | 54 ++++++- .../welcome-view/elements/feed-element.ts | 6 +- 7 files changed, 236 insertions(+), 32 deletions(-) create mode 100644 src/renderer/src/elements/reusable/profile-detail.ts diff --git a/cli/package.json b/cli/package.json index 5a17564d..f4e6e472 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@theweave/cli", - "version": "0.13.0-beta.7", + "version": "0.13.0-gamma.1", "description": "CLI to run Tools for the Weave in development mode", "license": "CAL-1.0", "repository": { @@ -20,7 +20,7 @@ "@holochain/client": "0.18.0-dev.13", "@holochain-open-dev/utils": "0.400.0-dev.4", "@theweave/api": "0.1.0", - "@lightningrodlabs/we-rust-utils": "0.400.0-dev.11", + "@lightningrodlabs/we-rust-utils": "0.400.0-dev.12", "@matthme/electron-updater": "6.3.0-alpha.1", "@msgpack/msgpack": "^2.8.0", "adm-zip": "0.5.14", diff --git a/src/renderer/src/elements/reusable/profile-detail.ts b/src/renderer/src/elements/reusable/profile-detail.ts new file mode 100644 index 00000000..1c27da4b --- /dev/null +++ b/src/renderer/src/elements/reusable/profile-detail.ts @@ -0,0 +1,150 @@ +import { consume } from '@lit/context'; +import { AgentPubKey } from '@holochain/client'; +import { html, LitElement } from 'lit'; +import { StoreSubscriber } from '@holochain-open-dev/stores'; +import { customElement, property } from 'lit/decorators.js'; +import { localized, msg } from '@lit/localize'; +import { hashProperty } from '@holochain-open-dev/elements'; + +import '@holochain-open-dev/elements/dist/elements/display-error.js'; +import '@holochain-open-dev/profiles/dist/elements/agent-avatar.js'; + +import '@shoelace-style/shoelace/dist/components/skeleton/skeleton.js'; + +import { profilesStoreContext } from '@holochain-open-dev/profiles'; +import { ProfilesStore } from '@holochain-open-dev/profiles'; +import { Profile } from '@holochain-open-dev/profiles'; +import { EntryRecord } from '@holochain-open-dev/utils'; +import { weStyles } from '../../shared-styles'; + +/** + * @element profile-detail + */ +@localized() +@customElement('profile-detail-moss') +export class ProfileDetail extends LitElement { + /** Public properties */ + + /** + * REQUIRED. Public key identifying the agent for which the profile should be shown + */ + @property(hashProperty('agent-pub-key')) + agentPubKey!: AgentPubKey; + + /** + * Profiles store for this element, not required if you embed this element inside a + */ + @consume({ context: profilesStoreContext, subscribe: true }) + @property() + store!: ProfilesStore; + + @property({ type: Boolean, attribute: 'no-additional-fields' }) + noAdditionalFields = false; + + /** Private properties */ + + /** + * @internal + */ + private _agentProfile = new StoreSubscriber( + this, + () => this.store.profiles.get(this.agentPubKey), + () => [this.agentPubKey, this.store], + ); + + getAdditionalFields(profile: Profile): Record { + const fields: Record = {}; + + for (const [key, value] of Object.entries(profile.fields)) { + if (key !== 'avatar') { + fields[key] = value; + } + } + + return fields; + } + + renderAdditionalField(fieldId: string, fieldValue: string) { + return html` +
+ + ${fieldId.substring(0, 1).toUpperCase()}${fieldId.substring(1)} + ${fieldValue} +
+ `; + } + + renderProfile(profile: EntryRecord | undefined | 'error') { + if (!profile) + return html` +
+
+ + ${msg('unknown')} + +
+
+ `; + + if (profile === 'error') + return html` +
+
+ + ${msg('ERROR')} + +
+
+ `; + + return html` +
+
+ + ${profile.entry.nickname} + + + + +
+ + ${this.noAdditionalFields + ? html`` + : Object.entries(this.getAdditionalFields(profile.entry)) + .filter(([, value]) => value !== '') + .map(([key, value]) => this.renderAdditionalField(key, value))} +
+ `; + } + + render() { + switch (this._agentProfile.value.status) { + case 'pending': + return html` +
+
+ +
+ +
+
+
+ `; + case 'complete': + return this.renderProfile(this._agentProfile.value.value); + case 'error': + console.error('Failed to get agent profile: ', this._agentProfile.value.error); + return this.renderProfile('error'); + } + } + + static styles = [weStyles]; +} diff --git a/src/renderer/src/groups/elements/group-home.ts b/src/renderer/src/groups/elements/group-home.ts index 8b2bbb94..c5416d01 100644 --- a/src/renderer/src/groups/elements/group-home.ts +++ b/src/renderer/src/groups/elements/group-home.ts @@ -33,7 +33,6 @@ import SlDialog from '@shoelace-style/shoelace/dist/components/dialog/dialog.js' import TimeAgo from 'javascript-time-ago'; import '@holochain-open-dev/profiles/dist/elements/profile-prompt.js'; -import '@holochain-open-dev/profiles/dist/elements/profile-detail.js'; import '@holochain-open-dev/profiles/dist/elements/agent-avatar.js'; import '@holochain-open-dev/elements/dist/elements/display-error.js'; import '@shoelace-style/shoelace/dist/components/card/card.js'; @@ -60,6 +59,7 @@ import './edit-custom-group-view.js'; import '../../elements/reusable/tab-group.js'; import './foyer-stream.js'; import './agent-permission.js'; +import '../../elements/reusable/profile-detail.js'; import { groupStoreContext } from '../context.js'; import { GroupStore } from '../group-store.js'; @@ -636,10 +636,10 @@ export class GroupHome extends LitElement { renderMemberProfile() { return html`
- + >
Role: diff --git a/src/renderer/src/groups/elements/group-peers-status.ts b/src/renderer/src/groups/elements/group-peers-status.ts index 3dea1d03..96ceab33 100644 --- a/src/renderer/src/groups/elements/group-peers-status.ts +++ b/src/renderer/src/groups/elements/group-peers-status.ts @@ -7,16 +7,15 @@ import { css, html, LitElement } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import '@holochain-open-dev/elements/dist/elements/display-error.js'; -import '@holochain-open-dev/profiles/dist/elements/profile-detail.js'; import '@shoelace-style/shoelace/dist/components/spinner/spinner.js'; import { groupStoreContext } from '../context.js'; import { weStyles } from '../../shared-styles.js'; -import { GroupStore, IDLE_THRESHOLD, OFFLINE_THRESHOLD } from '../group-store.js'; +import { GroupStore, IDLE_THRESHOLD, MaybeProfile, OFFLINE_THRESHOLD } from '../group-store.js'; import { mossStoreContext } from '../../context.js'; import { MossStore } from '../../moss-store.js'; -import { EntryRecord } from '@holochain-open-dev/utils'; -import { Profile } from '@holochain-open-dev/profiles'; + +import '../../elements/reusable/profile-detail.js'; export type AgentAndTzOffset = { agent: AgentPubKey; @@ -37,7 +36,7 @@ export class GroupPeersStatus extends LitElement { _groupMemberWithProfiles = new StoreSubscriber( this, - () => this._groupStore?.membersWithProfiles, + () => this._groupStore?.allProfiles, () => [this._groupStore, this.groupDnaHash], ); @@ -47,12 +46,14 @@ export class GroupPeersStatus extends LitElement { () => [this._groupStore], ); - renderPeersStatus(members: ReadonlyMap>) { + renderPeersStatus(members: ReadonlyMap) { const headlessNodes = Array.from(members.entries()).filter( - ([_pubKey, profile]) => !!profile.entry.fields.wdockerNode, + ([_pubKey, maybeProfile]) => + maybeProfile.type === 'profile' && !!maybeProfile.profile.entry.fields.wdockerNode, ); let normalMembers = Array.from(members.entries()).filter( - ([_pubKey, profile]) => !profile.entry.fields.wdockerNode, + ([_pubKey, maybeProfile]) => + maybeProfile.type === 'unknown' || !maybeProfile.profile.entry.fields.wdockerNode, ); if (!this._peerStatuses.value) return html``; const now = Date.now(); @@ -134,7 +135,11 @@ export class GroupPeersStatus extends LitElement { } }} > - +
- + >
@@ -213,11 +219,11 @@ export class GroupPeersStatus extends LitElement { } }} > - + >
`, )} @@ -252,11 +258,11 @@ export class GroupPeersStatus extends LitElement { } }} > - + > ${agentInfo.status ? html`
` : html``}
`, diff --git a/src/renderer/src/groups/elements/stewards-settings.ts b/src/renderer/src/groups/elements/stewards-settings.ts index 7a505321..a66e5160 100644 --- a/src/renderer/src/groups/elements/stewards-settings.ts +++ b/src/renderer/src/groups/elements/stewards-settings.ts @@ -3,7 +3,6 @@ import { customElement, state } from 'lit/decorators.js'; import { localized, msg } from '@lit/localize'; import { consume } from '@lit/context'; import '@holochain-open-dev/profiles/dist/elements/profiles-context.js'; -import '@holochain-open-dev/profiles/dist/elements/profile-detail.js'; import '@shoelace-style/shoelace/dist/components/button/button.js'; import '@shoelace-style/shoelace/dist/components/card/card.js'; @@ -19,6 +18,8 @@ import { PermissionType } from '@theweave/group-client'; import { weStyles } from '../../shared-styles.js'; import { notify, notifyError } from '@holochain-open-dev/elements'; +import '../../elements/reusable/profile-detail.js'; + @localized() @customElement('stewards-settings') export class StewardsSettings extends LitElement { @@ -180,7 +181,10 @@ export class StewardsSettings extends LitElement { ([pubkey, level]) => html`
- +
diff --git a/src/renderer/src/groups/group-store.ts b/src/renderer/src/groups/group-store.ts index 892b8fe3..857d5230 100644 --- a/src/renderer/src/groups/group-store.ts +++ b/src/renderer/src/groups/group-store.ts @@ -4,6 +4,7 @@ import { AsyncStatus, Readable, Writable, + asyncReadable, completed, derived, joinMap, @@ -53,6 +54,7 @@ import { Tool, UpdateableEntity } from '@theweave/tool-library-client'; import { PeerStatusClient, SignalPayload } from '@theweave/group-client'; import { FoyerStore } from './foyer.js'; import { appIdFromAppletHash, toLowerCaseB64 } from '@theweave/utils'; +import { encode } from '@msgpack/msgpack'; export const NEW_APPLETS_POLLING_FREQUENCY = 10000; const AGENTS_REFETCH_FREQUENCY = 10; @@ -60,6 +62,15 @@ const PING_AGENTS_FREQUENCY_MS = 8000; export const OFFLINE_THRESHOLD = 26000; // Peer is considered offline if they did not respond to 3 consecutive pings export const IDLE_THRESHOLD = 300000; // Peer is considered inactive after 5 minutes without interaction inside Moss +export type MaybeProfile = + | { + type: 'unknown'; + } + | { + type: 'profile'; + profile: EntryRecord; + }; + // Given a group, all the functionality related to that group export class GroupStore { profilesStore: ProfilesStore; @@ -70,9 +81,7 @@ export class GroupStore { customViewsStore: CustomViewsStore; - members: AsyncReadable>; - - membersWithProfiles: AsyncReadable>>; + allProfiles: AsyncReadable>; _peerStatuses: Writable | undefined>; @@ -100,8 +109,6 @@ export class GroupStore { this.peerStatusClient = new PeerStatusClient(appWebsocket, 'group'); this.profilesStore = new ProfilesStore(new ProfilesClient(appWebsocket, 'group')); this.customViewsStore = new CustomViewsStore(new CustomViewsClient(appWebsocket, 'group')); - this.members = this.profilesStore.agentsWithProfile; - this.membersWithProfiles = this.profilesStore.allProfiles; this.foyerStore = new FoyerStore( this.profilesStore, @@ -127,6 +134,10 @@ export class GroupStore { } }); + this.allProfiles = pipe(this.profilesStore.agentsWithProfile, (agents) => + this.agentsProfiles(agents), + ); + setTimeout(async () => { await this.pingAgentsAndCleanPeerStatuses(); }); @@ -206,6 +217,39 @@ export class GroupStore { this.groupClient.getGroupAppletsMetaData(), ); + agentsProfiles( + agents: Array, + ): AsyncReadable> { + return sliceAndJoin(this.membersProfiles, agents); + } + + membersProfiles = new LazyHoloHashMap((agent: AgentPubKey) => + asyncReadable(async (set) => { + try { + const profile = await this.profilesStore.client.getAgentProfile(agent); + profile ? set({ type: 'profile', profile }) : set({ type: 'unknown' }); + } catch (e) { + console.error('Failed to fetch profile: ', e); + set({ type: 'unknown' }); + } + + return this.profilesStore.client.onSignal((signal) => { + if (this.profilesStore.client.client.myPubKey.toString() !== agent.toString()) return; + if (!(signal.type === 'EntryCreated' || signal.type === 'EntryUpdated')) return; + const record = new EntryRecord({ + entry: { + Present: { + entry_type: 'App', + entry: encode(signal.app_entry), + }, + }, + signed_action: signal.action, + }); + set({ type: 'profile', profile: record }); + }); + }), + ); + peerStatuses(): Readable | undefined> { return derived(this._peerStatuses, (state) => state); } diff --git a/src/renderer/src/personal-views/welcome-view/elements/feed-element.ts b/src/renderer/src/personal-views/welcome-view/elements/feed-element.ts index 4edb7837..d48e72f3 100644 --- a/src/renderer/src/personal-views/welcome-view/elements/feed-element.ts +++ b/src/renderer/src/personal-views/welcome-view/elements/feed-element.ts @@ -5,12 +5,12 @@ import { localized } from '@lit/localize'; import '@shoelace-style/shoelace/dist/components/card/card.js'; import '@shoelace-style/shoelace/dist/components/icon/icon.js'; import '@shoelace-style/shoelace/dist/components/button/button.js'; -import '@holochain-open-dev/profiles/dist/elements/profile-detail.js'; import '../../../elements/dialogs/select-group-dialog.js'; import '../../../applets/elements/applet-logo.js'; import '../../../applets/elements/applet-title.js'; import '../../../groups/elements/group-context.js'; +import '../../../elements/reusable/profile-detail.js'; import { consume } from '@lit/context'; import { decodeHashFromBase64 } from '@holochain/client'; @@ -132,11 +132,11 @@ export class FeedElement extends LitElement { if (!this.groupDnaHash) return html`[unknown]`; return html` - + > `; } From 90a31d094ea5ddb857023ca31a3db8bf4e88d9bb Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 8 Oct 2024 12:17:56 +0200 Subject: [PATCH 2/5] bump Moss version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b27079b..581b7e3f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "org.lightningrodlabs.moss-0.13", - "version": "0.13.0-gamma.0", + "version": "0.13.0-gamma.1", "private": true, "description": "Moss (0.13)", "main": "./out/main/index.js", From 17445834a2f04d2fc153ca7d269ff435953ca4c0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 8 Oct 2024 19:37:19 +0200 Subject: [PATCH 3/5] add debug info for group apps as well --- .../debugging-panel/debugging-panel.ts | 39 +++++++++++++++++-- src/renderer/src/utils.ts | 15 ++++++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/renderer/src/elements/debugging-panel/debugging-panel.ts b/src/renderer/src/elements/debugging-panel/debugging-panel.ts index cb78e76e..007c0afb 100644 --- a/src/renderer/src/elements/debugging-panel/debugging-panel.ts +++ b/src/renderer/src/elements/debugging-panel/debugging-panel.ts @@ -1,4 +1,4 @@ -import { StoreSubscriber } from '@holochain-open-dev/stores'; +import { StoreSubscriber, toPromise } from '@holochain-open-dev/stores'; import { consume } from '@lit/context'; import { css, html, LitElement } from 'lit'; import { customElement, state } from 'lit/decorators.js'; @@ -32,7 +32,7 @@ import { MossStore } from '../../moss-store.js'; import { weStyles } from '../../shared-styles.js'; import { AppletStore } from '../../applets/applet-store.js'; import { AppletId } from '@theweave/api'; -import { getCellId } from '../../utils.js'; +import { getCellId, groupModifiersToAppId } from '../../utils.js'; import { DumpData } from '../../types.js'; import { notify, wrapPathInSvg } from '@holochain-open-dev/elements'; import { mdiBug } from '@mdi/js'; @@ -72,6 +72,9 @@ export class DebuggingPanel extends LitElement { @state() _toolsLibraryCellIds: CellId[] = []; + @state() + _groupAppIds: Record = {}; + @state() _showFeedbackBoardDetails = false; @@ -176,6 +179,15 @@ export class DebuggingPanel extends LitElement { console.log('networkInfo: ', networkInfo); } + async getGroupAppId(groupDnaHash: Uint8Array) { + const groupStore = await this._mossStore.groupStore(groupDnaHash); + if (!groupStore) throw new Error('No group store found for dna hash'); + const modifiers = await toPromise(groupStore.modifiers); + const appId = await groupModifiersToAppId(modifiers); + console.log('Got group app id: ', appId); + return appId; + } + toggleAppletDetails(appletId: AppletId) { const appletsWithDetails = this._appletsWithDetails; if (appletsWithDetails.includes(appletId)) { @@ -229,7 +241,11 @@ export class DebuggingPanel extends LitElement { ); } - renderDebugInfo(appId: InstalledAppId, netInfo: NetworkInfo, dump: DumpData) { + renderDebugInfo( + appId: InstalledAppId, + netInfo: NetworkInfo | undefined, + dump: DumpData | undefined, + ) { return html`
@@ -406,6 +422,10 @@ export class DebuggingPanel extends LitElement { const groupId = encodeHashToBase64(groupDnaHash); const zomeCallCount = window[`__mossZomeCallCount_${groupId}`]; const showDetails = this._groupsWithDetails.includes(groupId); + const groupAppId = this._groupAppIds[groupId]; + const netInfo = groupAppId ? this._appsWithNetInfo[groupAppId] : undefined; + const dump = groupAppId ? this._appsWithDumps[groupAppId] : undefined; + const showDebug = this._appsWithDebug.includes(groupAppId); return html`
@@ -434,9 +454,22 @@ export class DebuggingPanel extends LitElement { @click=${() => this.toggleGroupDetails(groupId)} >${showDetails ? 'Hide' : 'Details'} + + { + const groupAppId = await this.getGroupAppId(groupDnaHash); + const newGroupAppIds = this._groupAppIds; + newGroupAppIds[groupId] = groupAppId; + this._groupAppIds = newGroupAppIds; + this.toggleDebug(groupAppId); + }} + .src=${wrapPathInSvg(mdiBug)} + > +
${showDetails ? this.renderZomeCallDetails(zomeCallCount) : html``}
+ ${showDebug ? this.renderDebugInfo(groupAppId, netInfo, dump) : html``} `; })}
diff --git a/src/renderer/src/utils.ts b/src/renderer/src/utils.ts index 380b199b..0b980f47 100644 --- a/src/renderer/src/utils.ts +++ b/src/renderer/src/utils.ts @@ -19,11 +19,12 @@ import { Timestamp, AppAuthenticationToken, DnaModifiers, + InstalledAppId, } from '@holochain/client'; import { Hrl, WAL, RenderView, FrameNotification, AppletHash, AppletId } from '@theweave/api'; import { GroupDnaProperties } from '@theweave/group-client'; import { decode, encode } from '@msgpack/msgpack'; -import { fromUint8Array, toUint8Array } from 'js-base64'; +import { Base64, fromUint8Array, toUint8Array } from 'js-base64'; import isEqual from 'lodash-es/isEqual.js'; import { AppletNotificationSettings, NotificationSettings } from './applets/types.js'; @@ -622,6 +623,18 @@ export function modifiersToInviteUrl(modifiers: DnaModifiers) { return `https://theweave.social/wal?weave-0.13://invite/${modifiers.network_seed}&progenitor=${groupDnaProperties.progenitor}`; } +export async function groupModifiersToAppId(modifiers: DnaModifiers): Promise { + const hashBuffer = await crypto.subtle.digest( + 'SHA-256', + new TextEncoder().encode(modifiers.network_seed), + ); + const hashArray = new Uint8Array(hashBuffer); + const hashedSeed = Base64.fromUint8Array(hashArray); + // const hashedSeed = hashArray.map((item) => item.toString(16).padStart(2, '0')).join(''); + const groupDnaProperties = decode(modifiers.properties) as GroupDnaProperties; + return `group#${hashedSeed}#${groupDnaProperties.progenitor ? groupDnaProperties.progenitor : null}`; +} + export function markdownParseSafe(input: string) { const markedData = marked.parse(input) as string; return DOMPurify.sanitize(markedData); From dfd2c6d91aa2b59316a6ede467a47ee481069aaf Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 8 Oct 2024 22:06:21 +0200 Subject: [PATCH 4/5] add debugging for all cells of an app --- libs/api/package.json | 2 +- .../debugging-panel/app-debugging-details.ts | 76 ++++++++++ .../elements/debugging-panel/cell-details.ts | 142 ++++++++++++++++++ .../debugging-panel/debugging-panel.ts | 135 +++-------------- .../elements/debugging-panel/state-dump.ts | 59 +++++--- 5 files changed, 281 insertions(+), 133 deletions(-) create mode 100644 src/renderer/src/elements/debugging-panel/app-debugging-details.ts create mode 100644 src/renderer/src/elements/debugging-panel/cell-details.ts diff --git a/libs/api/package.json b/libs/api/package.json index f5b3928a..25daffeb 100644 --- a/libs/api/package.json +++ b/libs/api/package.json @@ -1,6 +1,6 @@ { "name": "@theweave/api", - "version": "0.1.1", + "version": "0.2.0", "main": "./dist/index.js", "module": "./dist/index.js", "license": "MIT", diff --git a/src/renderer/src/elements/debugging-panel/app-debugging-details.ts b/src/renderer/src/elements/debugging-panel/app-debugging-details.ts new file mode 100644 index 00000000..e1279134 --- /dev/null +++ b/src/renderer/src/elements/debugging-panel/app-debugging-details.ts @@ -0,0 +1,76 @@ +import { css, html, LitElement } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { localized, msg } from '@lit/localize'; +import { CellId, InstalledAppId } from '@holochain/client'; + +import '@shoelace-style/shoelace/dist/components/card/card.js'; + +import '../../groups/elements/group-context.js'; +import '../../applets/elements/applet-logo.js'; +import '../dialogs/create-group-dialog.js'; +import '../reusable/groups-for-applet.js'; +import './cell-details.js'; + +import { weStyles } from '../../shared-styles.js'; +import { consume } from '@lit/context'; +import { mossStoreContext } from '../../context.js'; +import { MossStore } from '../../moss-store.js'; +import { getCellId, getCellName } from '../../utils.js'; + +@localized() +@customElement('app-debugging-details') +export class AppDebuggingDetails extends LitElement { + @consume({ context: mossStoreContext }) + _mossStore!: MossStore; + + @property() + appId!: InstalledAppId; + + @state() + cellsAndIds: Record = {}; + + async firstUpdated() { + const appClient = await this._mossStore.getAppClient(this.appId); + const appInfo = await appClient.appInfo(); + // if (!appInfo) throw new Error(`AppInfo of app '${appClient}' undefined.`); + const cellInfos = Object.values(appInfo!.cell_info).flat(); + const cellsAndIds: Record = {}; + + cellInfos.forEach((cellInfo) => { + const cellName = getCellName(cellInfo); + const cellId = getCellId(cellInfo); + if (cellName && cellId) { + cellsAndIds[cellName] = cellId; + } + }); + this.cellsAndIds = cellsAndIds; + } + + render() { + return html`
+ ${Object.entries(this.cellsAndIds).map( + ([cellName, cellId]) => html` + +
+ ${cellName} +
+ +
+
+ `, + )} +
`; + } + + static styles = [ + weStyles, + css` + :host { + display: flex; + } + `, + ]; +} diff --git a/src/renderer/src/elements/debugging-panel/cell-details.ts b/src/renderer/src/elements/debugging-panel/cell-details.ts new file mode 100644 index 00000000..e6d8347a --- /dev/null +++ b/src/renderer/src/elements/debugging-panel/cell-details.ts @@ -0,0 +1,142 @@ +import { css, html, LitElement } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { localized } from '@lit/localize'; +import { CellId, DumpFullStateRequest, InstalledAppId, NetworkInfo } from '@holochain/client'; + +import '@holochain-open-dev/elements/dist/elements/display-error.js'; +import '@shoelace-style/shoelace/dist/components/skeleton/skeleton.js'; +import '@shoelace-style/shoelace/dist/components/tooltip/tooltip.js'; +import '@shoelace-style/shoelace/dist/components/button/button.js'; + +import '../../groups/elements/group-context.js'; +import '../../applets/elements/applet-logo.js'; +import '../dialogs/create-group-dialog.js'; +import '../reusable/groups-for-applet.js'; + +import { weStyles } from '../../shared-styles.js'; +import { DumpData } from '../../types.js'; +import { consume } from '@lit/context'; +import { mossStoreContext } from '../../context.js'; +import { MossStore } from '../../moss-store.js'; + +@localized() +@customElement('cell-details') +export class CellDetails extends LitElement { + @consume({ context: mossStoreContext }) + _mossStore!: MossStore; + + @property() + appId!: InstalledAppId; + + @property() + cellId!: CellId; + + @state() + netInfo: NetworkInfo | undefined; + + @state() + dumpData: DumpData | undefined; + + async networkInfo() { + const appClient = await this._mossStore.getAppClient(this.appId); + const networkInfo = await appClient.networkInfo({ + dnas: [this.cellId[0]], + last_time_queried: (Date.now() - 60000) * 1000, // get bytes from last 60 seconds + }); + + this.netInfo = networkInfo[0]; + console.log('networkInfo: ', networkInfo); + } + + async dumpState() { + let currentDump = this.dumpData; + const req: DumpFullStateRequest = { + cell_id: this.cellId, + dht_ops_cursor: currentDump ? currentDump.dump.integration_dump.dht_ops_cursor : 0, + }; + const resp = await this._mossStore.adminWebsocket.dumpFullState(req); + let newOpsCount = 0; + if (!currentDump) { + newOpsCount = resp.integration_dump.dht_ops_cursor; + currentDump = { + dump: resp, + newOpsCount, + }; + } else { + newOpsCount = + resp.integration_dump.dht_ops_cursor - currentDump.dump.integration_dump.dht_ops_cursor; + if (newOpsCount > 0) { + const currentIntegrated = currentDump.dump.integration_dump.integrated; + currentIntegrated.concat([...currentDump.dump.integration_dump.integrated]); + } + currentDump.dump.peer_dump = resp.peer_dump; + currentDump.dump.source_chain_dump = resp.source_chain_dump; + currentDump.newOpsCount = newOpsCount; + } + this.dumpData = currentDump; + console.log('dump data: ', this.dumpData); + } + + render() { + return html` +
+
+
+
+ Network Info + + { + this.networkInfo(); + }} + >Query +
+ ${this.netInfo ? html`` : html``} +
+
+
+ State Dump + + { + await this.dumpState(); + }} + >Query +
+ ${this.dumpData ? html`` : html``} +
+
+
+ `; + } + + static styles = [ + weStyles, + css` + :host { + display: flex; + } + + .debug-data { + margin-top: 10px; + width: 100%; + display: flex; + flex: 1; + flex-direction: column; + background-color: #fff; + border-radius: 5px; + } + + .debug-title { + font-weight: bold; + font-size: 105%; + } + `, + ]; +} diff --git a/src/renderer/src/elements/debugging-panel/debugging-panel.ts b/src/renderer/src/elements/debugging-panel/debugging-panel.ts index 007c0afb..031afdae 100644 --- a/src/renderer/src/elements/debugging-panel/debugging-panel.ts +++ b/src/renderer/src/elements/debugging-panel/debugging-panel.ts @@ -8,11 +8,9 @@ import { CellId, DnaHash, DnaHashB64, - DumpFullStateRequest, encodeHashToBase64, EntryHash, InstalledAppId, - NetworkInfo, } from '@holochain/client'; import '@holochain-open-dev/elements/dist/elements/display-error.js'; @@ -26,14 +24,15 @@ import '../dialogs/create-group-dialog.js'; import '../reusable/groups-for-applet.js'; import './state-dump.js'; import './net-info.js'; +import './cell-details.js'; +import './app-debugging-details.js'; import { mossStoreContext } from '../../context.js'; import { MossStore } from '../../moss-store.js'; import { weStyles } from '../../shared-styles.js'; import { AppletStore } from '../../applets/applet-store.js'; import { AppletId } from '@theweave/api'; -import { getCellId, groupModifiersToAppId } from '../../utils.js'; -import { DumpData } from '../../types.js'; +import { getCellId, getCellName, groupModifiersToAppId } from '../../utils.js'; import { notify, wrapPathInSvg } from '@holochain-open-dev/elements'; import { mdiBug } from '@mdi/js'; import { FEEDBACK_BOARD_APP_ID, TOOLS_LIBRARY_APP_ID } from '@theweave/moss-types'; @@ -84,12 +83,6 @@ export class DebuggingPanel extends LitElement { @state() _appsWithDebug: InstalledAppId[] = []; - @state() - _appsWithDumps: { [key: InstalledAppId]: DumpData } = {}; - - @state() - _appsWithNetInfo: { [key: InstalledAppId]: NetworkInfo } = {}; - @state() _toolLibraryTotalAgents: number | undefined; @@ -134,49 +127,20 @@ export class DebuggingPanel extends LitElement { return cellIds as CellId[]; } - async dumpState(appId: InstalledAppId) { - const appClient = await this._mossStore.getAppClient(appId); - const cellIds = await this.getCellIds(appClient); - const cell_id = cellIds[0]!; - - let currentDump = this._appsWithDumps[appClient.installedAppId]; - - const req: DumpFullStateRequest = { - cell_id, - dht_ops_cursor: currentDump ? currentDump.dump.integration_dump.dht_ops_cursor : 0, - }; - const resp = await this._mossStore.adminWebsocket.dumpFullState(req); - let newOpsCount = 0; - if (!currentDump) { - newOpsCount = resp.integration_dump.dht_ops_cursor; - currentDump = { - dump: resp, - newOpsCount, - }; - } else { - newOpsCount = - resp.integration_dump.dht_ops_cursor - currentDump.dump.integration_dump.dht_ops_cursor; - if (newOpsCount > 0) { - const currentIntegrated = currentDump.dump.integration_dump.integrated; - currentIntegrated.concat([...currentDump.dump.integration_dump.integrated]); + async getCellsAndIds(appClient: AppClient): Promise> { + const appInfo = await appClient.appInfo(); + // if (!appInfo) throw new Error(`AppInfo of app '${appClient}' undefined.`); + const cellInfos = Object.values(appInfo!.cell_info).flat(); + const cellAndIds: Record = {}; + + cellInfos.forEach((cellInfo) => { + const cellName = getCellName(cellInfo); + const cellId = getCellId(cellInfo); + if (cellName && cellId) { + cellAndIds[cellName] = cellId; } - currentDump.dump.peer_dump = resp.peer_dump; - currentDump.dump.source_chain_dump = resp.source_chain_dump; - currentDump.newOpsCount = newOpsCount; - } - this._appsWithDumps[appClient.installedAppId] = currentDump; - } - - async networkInfo(appId: InstalledAppId) { - const appClient = await this._mossStore.getAppClient(appId); - const cellIds = await this.getCellIds(appClient); - const networkInfo = await appClient.networkInfo({ - dnas: cellIds.map((id) => id![0]), - last_time_queried: (Date.now() - 60000) * 1000, // get bytes from last 60 seconds }); - this._appsWithNetInfo[appClient.installedAppId] = networkInfo[0]; - - console.log('networkInfo: ', networkInfo); + return cellAndIds; } async getGroupAppId(groupDnaHash: Uint8Array) { @@ -241,41 +205,6 @@ export class DebuggingPanel extends LitElement { ); } - renderDebugInfo( - appId: InstalledAppId, - netInfo: NetworkInfo | undefined, - dump: DumpData | undefined, - ) { - return html` -
-
- Network Info - { - this.networkInfo(appId); - }} - >Query -
- ${netInfo ? html`` : html``} -
- State Dump - { - await this.dumpState(appId); - }} - >Query -
- ${dump ? html`` : html``} -
- `; - } - renderDefaultApps() { const toolsLibraryZomeCallCount = this._toolsLibraryCellIds.length > 0 @@ -287,12 +216,7 @@ export class DebuggingPanel extends LitElement { : undefined; const showToolsLibraryDebug = this._appsWithDebug.includes(TOOLS_LIBRARY_APP_ID); - const toolsLibraryNetInfo = this._appsWithNetInfo[TOOLS_LIBRARY_APP_ID]; - const toolsLibraryDump = this._appsWithDumps[TOOLS_LIBRARY_APP_ID]; - const showfeedbackBoardDebug = this._appsWithDebug.includes(FEEDBACK_BOARD_APP_ID); - const feedbackBoardNetInfo = this._appsWithNetInfo[FEEDBACK_BOARD_APP_ID]; - const feedbackBoardDump = this._appsWithDumps[FEEDBACK_BOARD_APP_ID]; return html`
@@ -342,7 +266,7 @@ export class DebuggingPanel extends LitElement { : html``}
${showToolsLibraryDebug - ? this.renderDebugInfo(TOOLS_LIBRARY_APP_ID, toolsLibraryNetInfo, toolsLibraryDump) + ? html`` : html``}
@@ -386,7 +310,7 @@ export class DebuggingPanel extends LitElement { : html``}
${showfeedbackBoardDebug - ? this.renderDebugInfo(FEEDBACK_BOARD_APP_ID, feedbackBoardNetInfo, feedbackBoardDump) + ? html`` : html``}
`; @@ -423,8 +347,6 @@ export class DebuggingPanel extends LitElement { const zomeCallCount = window[`__mossZomeCallCount_${groupId}`]; const showDetails = this._groupsWithDetails.includes(groupId); const groupAppId = this._groupAppIds[groupId]; - const netInfo = groupAppId ? this._appsWithNetInfo[groupAppId] : undefined; - const dump = groupAppId ? this._appsWithDumps[groupAppId] : undefined; const showDebug = this._appsWithDebug.includes(groupAppId); return html`
@@ -469,7 +391,9 @@ export class DebuggingPanel extends LitElement {
${showDetails ? this.renderZomeCallDetails(zomeCallCount) : html``}
- ${showDebug ? this.renderDebugInfo(groupAppId, netInfo, dump) : html``} + ${showDebug + ? html`` + : html``} `; })}
@@ -508,8 +432,6 @@ export class DebuggingPanel extends LitElement { const appId = appIdFromAppletHash(appletHash); const zomeCallCount = window[`__appletZomeCallCount_${appletId}`]; const showDetails = this._appletsWithDetails.includes(appletId); - const dump = this._appsWithDumps[appId]; - const netInfo = this._appsWithNetInfo[appId]; const showDebug = this._appsWithDebug.includes(appId); return html`
@@ -554,7 +476,9 @@ export class DebuggingPanel extends LitElement {
${showDetails ? this.renderZomeCallDetails(zomeCallCount) : html``}
- ${showDebug ? this.renderDebugInfo(appId, netInfo, dump) : html``} + ${showDebug + ? html`` + : html``} `; })} @@ -624,19 +548,6 @@ export class DebuggingPanel extends LitElement { :host { display: flex; } - - .debug-data { - padding: 5px; - display: flex; - flex-direction: column; - background-color: #fff; - border-radius: 5px; - } - - .debug-title { - font-weight: bold; - font-size: 105%; - } `, ]; } diff --git a/src/renderer/src/elements/debugging-panel/state-dump.ts b/src/renderer/src/elements/debugging-panel/state-dump.ts index 700f7843..122113db 100644 --- a/src/renderer/src/elements/debugging-panel/state-dump.ts +++ b/src/renderer/src/elements/debugging-panel/state-dump.ts @@ -4,12 +4,14 @@ import { localized } from '@lit/localize'; import { Action, AgentPubKey, + ChainOp, CreateLink, DhtOp, encodeHashToBase64, Entry, HoloHash, SourceChainJsonRecord, + WarrantOp, } from '@holochain/client'; import '@holochain-open-dev/elements/dist/elements/display-error.js'; @@ -49,6 +51,7 @@ export class StateDump extends LitElement { const opsHtml = []; for (let i = start; i > end && i >= 0; i -= 1) { const r = this.dump.dump.integration_dump.integrated[i]; + console.log('DhtOP: ', r); // @ts-ignore opsHtml.push(html`
${this.renderDhtOp(r)}
`); } @@ -56,29 +59,41 @@ export class StateDump extends LitElement { } renderDhtOp(op: DhtOp) { - const opName = Object.keys(op)[0]; - const opValue = Object.values(op)[0]; - const action: Action = opValue[1]; + const opType = Object.keys(op)[0]; // ChainOp or WarrantOp + if (opType === 'ChainOp') { + const opContent: ChainOp = op[opType]; + const opName = Object.keys(opContent)[0]; + const opValue = Object.values(opContent)[0]; + const action: Action = opValue[1]; - let entry: Entry | undefined; - if (opName == 'StoreEntry') { - entry = opValue[2]; - } else if (opName == 'StoreRecord' && action.type == 'Create') { - if (opValue[2]['Present']) { - entry = opValue[2]['Present']; + let entry: Entry | undefined; + if (opName == 'StoreEntry') { + entry = opValue[2]; + } else if (opName == 'StoreRecord' && action.type == 'Create') { + if (opValue[2]['Present']) { + entry = opValue[2]['Present']; + } } - } - return html` -
- ${opName}: ${action.type} - ${dateStr(action.timestamp)} - ${action.author ? html`by ${this.renderHash(action.author)}` : ''} - ${action.type == 'CreateLink' ? this.renderCreateLink(action) : ''} - ${entry ? this.renderEntry(entry) : ''} - ${opName == 'RegisterAddLink' ? this.renderCreateLink(action as CreateLink) : ''} -
- `; + return html` +
+ ${opName}: ${action.type} + ${dateStr(action.timestamp)} + ${action.author ? html`by ${this.renderHash(action.author)}` : ''} + ${action.type == 'CreateLink' ? this.renderCreateLink(action) : ''} + ${entry ? this.renderEntry(entry) : ''} + ${opName == 'RegisterAddLink' ? this.renderCreateLink(action as CreateLink) : ''} +
+ `; + } else { + const opContent: WarrantOp = op[opType]; + return html` +
+ WARRANT + ${dateStr(opContent.timestamp)} +
+ `; + } } renderHash(hash: HoloHash) { @@ -255,6 +270,10 @@ export class StateDump extends LitElement { display: flex; } + .warrant-op { + background: #b000007c; + } + .long-list { border: solid 1px #aaa; max-height: 1000px; From 358d52bbc1ebd2a6f9b61fc0e19bacbc688824ca Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 8 Oct 2024 23:57:11 +0200 Subject: [PATCH 5/5] display integration and validation limbo --- .../debugging-panel/app-debugging-details.ts | 8 +- .../elements/debugging-panel/cell-details.ts | 89 +++++++- .../elements/debugging-panel/dht-op-detail.ts | 206 ++++++++++++++++++ .../elements/debugging-panel/state-dump.ts | 5 +- 4 files changed, 293 insertions(+), 15 deletions(-) create mode 100644 src/renderer/src/elements/debugging-panel/dht-op-detail.ts diff --git a/src/renderer/src/elements/debugging-panel/app-debugging-details.ts b/src/renderer/src/elements/debugging-panel/app-debugging-details.ts index e1279134..a40e9a52 100644 --- a/src/renderer/src/elements/debugging-panel/app-debugging-details.ts +++ b/src/renderer/src/elements/debugging-panel/app-debugging-details.ts @@ -48,8 +48,10 @@ export class AppDebuggingDetails extends LitElement { render() { return html`
- ${Object.entries(this.cellsAndIds).map( - ([cellName, cellId]) => html` + ${Object.entries(this.cellsAndIds) + .sort(([name_a, _a], [name_b, _b]) => name_a.localeCompare(name_b)) + .map( + ([cellName, cellId]) => html`
`, - )} + )}
`; } diff --git a/src/renderer/src/elements/debugging-panel/cell-details.ts b/src/renderer/src/elements/debugging-panel/cell-details.ts index e6d8347a..3cf3f130 100644 --- a/src/renderer/src/elements/debugging-panel/cell-details.ts +++ b/src/renderer/src/elements/debugging-panel/cell-details.ts @@ -3,22 +3,17 @@ import { customElement, property, state } from 'lit/decorators.js'; import { localized } from '@lit/localize'; import { CellId, DumpFullStateRequest, InstalledAppId, NetworkInfo } from '@holochain/client'; -import '@holochain-open-dev/elements/dist/elements/display-error.js'; -import '@shoelace-style/shoelace/dist/components/skeleton/skeleton.js'; -import '@shoelace-style/shoelace/dist/components/tooltip/tooltip.js'; import '@shoelace-style/shoelace/dist/components/button/button.js'; -import '../../groups/elements/group-context.js'; -import '../../applets/elements/applet-logo.js'; -import '../dialogs/create-group-dialog.js'; -import '../reusable/groups-for-applet.js'; - import { weStyles } from '../../shared-styles.js'; import { DumpData } from '../../types.js'; import { consume } from '@lit/context'; import { mossStoreContext } from '../../context.js'; import { MossStore } from '../../moss-store.js'; +import './dht-op-detail.js'; +import { notify } from '@holochain-open-dev/elements'; + @localized() @customElement('cell-details') export class CellDetails extends LitElement { @@ -37,6 +32,15 @@ export class CellDetails extends LitElement { @state() dumpData: DumpData | undefined; + @state() + showFullDetail = false; + + @state() + showValidationLimbo = false; + + @state() + showIntegrationLimbo = false; + async networkInfo() { const appClient = await this._mossStore.getAppClient(this.appId); const networkInfo = await appClient.networkInfo({ @@ -77,6 +81,73 @@ export class CellDetails extends LitElement { console.log('dump data: ', this.dumpData); } + renderDumpData() { + return html` +
+
+ Validation Limbo: ${this.dumpData?.dump.integration_dump.validation_limbo.length} + +
+ ${this.showValidationLimbo && this.dumpData + ? html`
+ ${this.dumpData.dump.integration_dump.validation_limbo.map( + (dhtOp) => + html` { + console.log(dhtOp); + notify('DhtOp logged to console.'); + }} + style="border: 1px solid black; border-radius: 5px; padding: 3px; cursor: pointer;" + .dhtOp=${dhtOp} + >`, + )} +
` + : html``} +
+ Integration Limbo: ${this.dumpData?.dump.integration_dump.integration_limbo.length} + +
+ ${this.showIntegrationLimbo && this.dumpData + ? html`
+ ${this.dumpData.dump.integration_dump.integration_limbo.map( + (dhtOp) => + html` { + console.log(dhtOp); + notify('DhtOp logged to console.'); + }} + style="border: 1px solid black; border-radius: 5px; padding: 3px; cursor: pointer;" + .dhtOp=${dhtOp} + >`, + )} +
` + : html``} +
Integrated: ${this.dumpData?.dump.integration_dump.integrated.length}
+ + ${this.showFullDetail ? html`` : html``} +
+ `; + } + render() { return html`
@@ -109,7 +180,7 @@ export class CellDetails extends LitElement { >Query
- ${this.dumpData ? html`` : html``} + ${this.dumpData ? this.renderDumpData() : html``} diff --git a/src/renderer/src/elements/debugging-panel/dht-op-detail.ts b/src/renderer/src/elements/debugging-panel/dht-op-detail.ts new file mode 100644 index 00000000..1583291e --- /dev/null +++ b/src/renderer/src/elements/debugging-panel/dht-op-detail.ts @@ -0,0 +1,206 @@ +import { css, html, LitElement, TemplateResult } from 'lit'; +import { customElement, property, state } from 'lit/decorators.js'; +import { localized } from '@lit/localize'; +import { + Action, + AgentPubKey, + ChainOp, + CreateLink, + DhtOp, + encodeHashToBase64, + Entry, + HoloHash, + WarrantOp, +} from '@holochain/client'; + +import '@shoelace-style/shoelace/dist/components/button/button.js'; + +import { weStyles } from '../../shared-styles.js'; +import { dateStr } from '../../utils.js'; +import { decode } from '@msgpack/msgpack'; + +@localized() +@customElement('dht-op-detail') +export class DhtOpDetail extends LitElement { + @property() + dhtOp!: DhtOp; + + renderCreateLink(createLink: CreateLink) { + return html` Base: ${this.renderHash(createLink.base_address)}; Target: + ${this.renderHash(createLink.target_address)}`; + } + + renderDhtOp(op: DhtOp) { + const opType = Object.keys(op)[0]; // ChainOp or WarrantOp + if (opType === 'ChainOp') { + const opContent: ChainOp = op[opType]; + const opName = Object.keys(opContent)[0]; + const opValue = Object.values(opContent)[0]; + const action: Action = opValue[1]; + + let entry: Entry | undefined; + if (opName == 'StoreEntry') { + entry = opValue[2]; + } else if (opName == 'StoreRecord' && action.type == 'Create') { + if (opValue[2]['Present']) { + entry = opValue[2]['Present']; + } + } + + return html` +
+ ${opName}: ${action.type} + ${dateStr(action.timestamp)} + ${action.author ? html`by ${this.renderHash(action.author)}` : ''} + ${action.type == 'CreateLink' ? this.renderCreateLink(action) : ''} + ${entry ? this.renderEntry(entry) : ''} + ${opName == 'RegisterAddLink' ? this.renderCreateLink(action as CreateLink) : ''} +
+ `; + } else { + const opContent: WarrantOp = op[opType]; + return html` +
+ WARRANT + ${dateStr(opContent.timestamp)} +
+ `; + } + } + + renderHash(hash: HoloHash) { + const hashB64 = encodeHashToBase64(hash); + return html` ${hashB64.slice(0, 10)} `; + } + + renderObjectWithHashes(object: Object) { + return Object.entries(object).map( + ([key, value]) => + html`${key}:${value && value['0'] === 132 && value['1'] == '32' && value['2'] == 36 + ? this.renderHash(value) + : JSON.stringify(value)}; `, + ); + } + + renderUnknownSerializedObject(object: Object) { + try { + // @ts-ignore + return JSON.stringify(decode(object)); + } catch (e) { + // @ts-ignore + const x = Array.from(object); + // @ts-ignore + return String.fromCharCode.apply(null, x); + } + } + + renderEntry(entry: Entry) { + const entry_type = Object.keys(entry.entry_type)[0]; // Fixme in version 0.4 + const entry_data = entry.entry; + let entryHtml: undefined | TemplateResult; + if (entry_type === 'App') { + const decoded = decode(entry_data as Uint8Array) as Object; + if (decoded['document_hash'] && decoded['name']) + entryHtml = html`Syn-Workspace Doc:${this.renderHash(decoded['document_hash'])}: ${decoded['name']}`; + else if (decoded['initial_state'] && decoded['meta']) { + const state = decode(decoded['initial_state']) as Object; + const meta = decode(decoded['meta']) as Object; + entryHtml = html`Syn-Document + Meta->${this.renderObjectWithHashes( + meta, + )}--InitialState:${this.renderUnknownSerializedObject(state)}`; + } else if (decoded['document_hash'] && decoded['state']) { + const state = decode(decoded['state']) as object; + entryHtml = html`
+ Syn-Commit Doc:${this.renderHash(decoded['document_hash'])}--- + previous commits: + ${decoded['previous_commit_hashes'].map((h) => this.renderHash(h))} +
${this.renderUnknownSerializedObject(state)}
+
`; + } else { + entryHtml = html`${JSON.stringify(decoded)}`; + } + } + return html` +
+ ${entry_type}--${entry_type == 'Agent' ? this.renderHash(entry_data as AgentPubKey) : ''} + ${entryHtml ? entryHtml : ''} + ${entry_type === 'App' && !entryHtml ? JSON.stringify(entry_data) : ''} +
+ `; + } + + render() { + return this.renderDhtOp(this.dhtOp); + } + + static styles = [ + weStyles, + css` + :host { + display: flex; + } + + .warrant-op { + background: #b000007c; + } + + .long-list { + border: solid 1px #aaa; + max-height: 1000px; + overflow-y: auto; + border-radius: 5px; + } + .list-item { + margin-left: 5px; + border-bottom: solid 1px #ddd; + padding: 2px; + overflow-x: auto; + line-break: anywhere; + } + .pager { + margin-left: 5px; + margin-right: 5px; + display: flex; + justify-content: center; + align-items: center; + background-color: lightgreen; + border-radius: 50%; + cursor: pointer; + height: 15px; + width: 15px; + } + .pager:hover { + background-color: green; + border-color: green; + } + .action-type { + font-weight: bold; + } + .entry { + margin-left: 10px; + } + .syn { + padding: 4px; + background-color: lightcoral; + } + .app-entry { + padding: 4px; + background-color: lightblue; + } + + .hash { + background-color: #ccc; + font-size: 80%; + border-radius: 5px; + padding: 2px; + } + `, + ]; +} diff --git a/src/renderer/src/elements/debugging-panel/state-dump.ts b/src/renderer/src/elements/debugging-panel/state-dump.ts index 122113db..e5049769 100644 --- a/src/renderer/src/elements/debugging-panel/state-dump.ts +++ b/src/renderer/src/elements/debugging-panel/state-dump.ts @@ -51,9 +51,8 @@ export class StateDump extends LitElement { const opsHtml = []; for (let i = start; i > end && i >= 0; i -= 1) { const r = this.dump.dump.integration_dump.integrated[i]; - console.log('DhtOP: ', r); // @ts-ignore - opsHtml.push(html`
${this.renderDhtOp(r)}
`); + opsHtml.push(html`
${this.renderDhtOp(r)}
`); } return opsHtml; } @@ -98,7 +97,7 @@ export class StateDump extends LitElement { renderHash(hash: HoloHash) { const hashB64 = encodeHashToBase64(hash); - return html` ${hashB64.slice(0, 8)} `; + return html` ${hashB64.slice(0, 10)} `; } renderObjectWithHashes(object: Object) {