@ibgib/space-gib 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/dist/client/bootstrap.mjs +31 -31
- package/dist/client/bootstrap.mjs.map +3 -3
- package/dist/client/chunk-DBHMHCGD.mjs +2341 -0
- package/dist/client/{chunk-SMOZ2D5E.mjs.map → chunk-DBHMHCGD.mjs.map} +4 -4
- package/dist/client/chunk-SUQ5QJH4.mjs +42 -0
- package/dist/client/chunk-SUQ5QJH4.mjs.map +7 -0
- package/dist/client/index.mjs +1 -1
- package/dist/client/script.mjs +1 -1
- package/dist/server/server.mjs +1561 -179
- package/dist/server/server.mjs.map +4 -4
- package/package.json +5 -5
- package/space-gib.localhost-1783713259760.log +45 -0
- package/src/client/AUTO-GENERATED-version.mts +1 -1
- package/src/client/api/space-gib-api-bridge.mts +7 -2
- package/src/client/bootstrap.mts +9 -0
- package/src/client/components/identity-header/identity-header.mts +43 -26
- package/src/client/components/identity-manager/identity-manager.css +57 -392
- package/src/client/components/identity-manager/identity-manager.html +0 -114
- package/src/client/components/identity-manager/identity-manager.mts +356 -543
- package/src/client/components/keystone-creator/keystone-creator.mts +4 -3
- package/src/client/components/keystone-details/keystone-details.css +569 -0
- package/src/client/components/keystone-details/keystone-details.html +127 -0
- package/src/client/components/keystone-details/keystone-details.mts +1013 -0
- package/src/client/components/keystone-scrubber/SCRUBBER_IMPLEMENTATION.md +33 -0
- package/src/client/components/keystone-scrubber/keystone-scrubber.css +46 -0
- package/src/client/components/keystone-scrubber/keystone-scrubber.html +15 -0
- package/src/client/components/keystone-scrubber/keystone-scrubber.mts +356 -0
- package/src/client/ui/shell/space-gib-shell-service.mts +4 -0
- package/src/server/path-constants.mts +12 -0
- package/src/server/serve-gib/handlers/api/keystone/keystone-evolve.handler.mts +33 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-config.handler.mts +66 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-link.handler.mts +140 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-login.handler.mts +190 -0
- package/src/server/server.mts +6 -0
- package/dist/client/chunk-734MMI4C.mjs +0 -42
- package/dist/client/chunk-734MMI4C.mjs.map +0 -7
- package/dist/client/chunk-SMOZ2D5E.mjs +0 -2049
|
@@ -2,28 +2,35 @@ import styleCss from "../../style.css";
|
|
|
2
2
|
import thisCss from "./identity-manager.css";
|
|
3
3
|
import thisHtml from "./identity-manager.html";
|
|
4
4
|
|
|
5
|
-
import { extractErrorMsg, pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
5
|
+
import { delay, extractErrorMsg, pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
6
6
|
import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
|
|
7
7
|
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
|
|
8
|
-
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
8
|
+
import { getIbAndGib, getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
9
9
|
import { ROOT_ADDR } from "@ibgib/ts-gib/dist/V1/constants.mjs";
|
|
10
|
+
import { getGibInfo } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
|
|
10
11
|
import { KeystoneService_V1 } from "@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs";
|
|
11
|
-
import {
|
|
12
|
+
import { getTjpAddr } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
|
|
13
|
+
import { mut8Timeline } from "@ibgib/core-gib/dist/timeline/timeline-api.mjs";
|
|
14
|
+
import { MetaspaceService } from "@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs";
|
|
12
15
|
import {
|
|
13
|
-
IbGibDynamicComponentMetaBase,
|
|
16
|
+
IbGibDynamicComponentMetaBase,
|
|
17
|
+
IbGibDynamicComponentInstanceBase_ParentOfTabs,
|
|
14
18
|
} from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
|
|
15
19
|
import {
|
|
16
|
-
ElementsBase, IbGibDynamicComponentInstance,
|
|
20
|
+
ElementsBase, ChildInfoBase, IbGibDynamicComponentInstance,
|
|
17
21
|
IbGibDynamicComponentInstanceInitOpts,
|
|
18
22
|
} from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
|
|
23
|
+
import { getDeterministicColorInfo, getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs";
|
|
19
24
|
import { SettingsType } from "@ibgib/web-gib/dist/common/settings/settings-constants.mjs";
|
|
20
|
-
import { Settings_General } from "@ibgib/web-gib/dist/common/settings/settings-types.mjs";
|
|
25
|
+
import { Settings_General, Settings_IdentityManager } from "@ibgib/web-gib/dist/common/settings/settings-types.mjs";
|
|
26
|
+
import { getSectionName } from "@ibgib/web-gib/dist/common/settings/settings-helpers.mjs";
|
|
21
27
|
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";
|
|
22
28
|
import { EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, EVENT_IBGIB_IDENTITY_CHANGED } from "@ibgib/web-gib/dist/ui/ui-constants.mjs";
|
|
23
29
|
|
|
24
30
|
import { getComponentCtorArg, getIbGibGlobalThis_SpaceGib } from "../../helpers.web.mjs";
|
|
25
31
|
import { APP_CONFIG } from "../../constants.mjs";
|
|
26
32
|
import { devLog } from "../../dev-tools.mjs";
|
|
33
|
+
import { KEYSTONE_ATOM } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
|
|
27
34
|
|
|
28
35
|
export const IDENTITY_MANAGER_COMPONENT_NAME = 'ibgib-identity-manager';
|
|
29
36
|
|
|
@@ -62,6 +69,9 @@ export class IdentityManagerComponentMeta extends IbGibDynamicComponentMetaBase
|
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
71
|
|
|
72
|
+
interface IdentityTabInfo extends ChildInfoBase<IbGibDynamicComponentInstance<any, any>> {
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
/**
|
|
66
76
|
* References to DOM elements within the component's shadow root.
|
|
67
77
|
*/
|
|
@@ -72,82 +82,53 @@ interface IdentityManagerElements extends ElementsBase {
|
|
|
72
82
|
btnAddIdentityEl: HTMLButtonElement;
|
|
73
83
|
noIdentityPlaceholderEl: HTMLDivElement;
|
|
74
84
|
btnCreatePlaceholderEl: HTMLButtonElement;
|
|
75
|
-
identityDetailsViewEl: HTMLDivElement;
|
|
76
|
-
identityAddrEl: HTMLElement;
|
|
77
|
-
identityGenEl: HTMLElement;
|
|
78
|
-
identityTimestampEl: HTMLElement;
|
|
79
|
-
identityUuidEl: HTMLElement;
|
|
80
|
-
identityNameEl: HTMLElement;
|
|
81
|
-
identityDescriptionEl: HTMLElement;
|
|
82
|
-
identityFrameDetailsEl: HTMLPreElement;
|
|
83
|
-
identityAggrDetailsEl: HTMLPreElement;
|
|
84
|
-
|
|
85
|
-
// Scrubber elements
|
|
86
|
-
btnScrubFirstEl: HTMLButtonElement;
|
|
87
|
-
btnScrubPrev10El: HTMLButtonElement;
|
|
88
|
-
btnScrubPrevEl: HTMLButtonElement;
|
|
89
|
-
scrubberStatusEl: HTMLSpanElement;
|
|
90
|
-
btnScrubNextEl: HTMLButtonElement;
|
|
91
|
-
btnScrubNext10El: HTMLButtonElement;
|
|
92
|
-
btnScrubLatestEl: HTMLButtonElement;
|
|
93
|
-
|
|
94
|
-
poolsContainerEl: HTMLDivElement;
|
|
95
|
-
btnVerifyChainEl: HTMLButtonElement;
|
|
96
|
-
// btnSyncIdentityEl: HTMLButtonElement;
|
|
97
|
-
btnSetActiveEl: HTMLButtonElement;
|
|
98
|
-
verificationStatusEl: HTMLDivElement;
|
|
99
|
-
replicasListEl: HTMLDivElement;
|
|
100
|
-
// inputReplicaUrlEl: HTMLInputElement;
|
|
101
|
-
// btnAddReplicaEl: HTMLButtonElement;
|
|
102
|
-
rawAccordionHeaderEl: HTMLDivElement;
|
|
103
|
-
rawAccordionContentEl: HTMLDivElement;
|
|
104
|
-
rawKeystoneJsonEl: HTMLPreElement;
|
|
105
|
-
delegatesListEl: HTMLTableSectionElement;
|
|
106
85
|
}
|
|
107
86
|
|
|
108
87
|
/**
|
|
109
88
|
* Concrete implementation of the Identity Manager component.
|
|
110
89
|
*/
|
|
111
90
|
export class IdentityManagerComponentInstance
|
|
112
|
-
extends
|
|
91
|
+
extends IbGibDynamicComponentInstanceBase_ParentOfTabs<Settings_IdentityManager, IbGib_V1, IdentityManagerElements, IdentityTabInfo>
|
|
113
92
|
implements IbGibDynamicComponentInstance<IbGib_V1, IdentityManagerElements> {
|
|
114
93
|
|
|
115
|
-
protected lc: string = `[IdentityManagerComponentInstance]`;
|
|
94
|
+
protected override lc: string = `[IdentityManagerComponentInstance]`;
|
|
116
95
|
|
|
117
|
-
private activeAddr: string | null = null;
|
|
118
96
|
private globalActiveAddr: string | null = null;
|
|
119
97
|
private _onIdentityChanged: ((e: any) => void) | null = null;
|
|
120
|
-
private
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
98
|
+
private keystoneCache: Map<string, { username: string, description: string, isPrimary: boolean, n: number }> = new Map();
|
|
99
|
+
metaspace: MetaspaceService | undefined;
|
|
100
|
+
|
|
101
|
+
protected get settingsType(): SettingsType {
|
|
102
|
+
return SettingsType.identityManager;
|
|
103
|
+
}
|
|
124
104
|
|
|
125
105
|
constructor() {
|
|
126
106
|
super();
|
|
127
107
|
}
|
|
128
108
|
|
|
129
|
-
private async getKeystoneDetails(addr: string): Promise<{ username: string, description: string }> {
|
|
109
|
+
private async getKeystoneDetails(addr: string): Promise<{ username: string, description: string, isPrimary: boolean, n: number }> {
|
|
130
110
|
const cached = this.keystoneCache.get(addr);
|
|
131
111
|
if (cached) return cached;
|
|
132
112
|
|
|
133
113
|
const metaspace = getIbGibGlobalThis_SpaceGib(APP_CONFIG).metaspace;
|
|
134
|
-
if (!metaspace) return { username: '', description: '' };
|
|
114
|
+
if (!metaspace) return { username: '', description: '', isPrimary: false, n: 0 };
|
|
135
115
|
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
136
|
-
if (!space) return { username: '', description: '' };
|
|
116
|
+
if (!space) return { username: '', description: '', isPrimary: false, n: 0 };
|
|
137
117
|
|
|
138
118
|
try {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
119
|
+
const keystoneSvc = new KeystoneService_V1();
|
|
120
|
+
const info = await keystoneSvc.getKeystoneCommonInfo({
|
|
121
|
+
addr,
|
|
122
|
+
metaspace,
|
|
123
|
+
space
|
|
124
|
+
});
|
|
125
|
+
if (info) {
|
|
126
|
+
const details = {
|
|
127
|
+
username: info.name,
|
|
128
|
+
description: info.description,
|
|
129
|
+
isPrimary: info.isPrimary,
|
|
130
|
+
n: info.n
|
|
131
|
+
};
|
|
151
132
|
this.keystoneCache.set(addr, details);
|
|
152
133
|
return details;
|
|
153
134
|
}
|
|
@@ -155,10 +136,14 @@ export class IdentityManagerComponentInstance
|
|
|
155
136
|
console.warn(`Error getting details for keystone ${addr}: ${extractErrorMsg(err)}`);
|
|
156
137
|
}
|
|
157
138
|
|
|
158
|
-
return { username: '', description: '' };
|
|
139
|
+
return { username: '', description: '', isPrimary: false, n: 0 };
|
|
159
140
|
}
|
|
160
141
|
|
|
161
142
|
override async initialize(opts: IbGibDynamicComponentInstanceInitOpts): Promise<void> {
|
|
143
|
+
if (!this.metaspace) {
|
|
144
|
+
this.metaspace = await getGlobalMetaspace_waitIfNeeded({ delayIntervalMs: 50 });
|
|
145
|
+
}
|
|
146
|
+
opts.ibGibAddr = await this.metaspace.getLatestAddr({ addr: opts.ibGibAddr }) ?? opts.ibGibAddr;
|
|
162
147
|
await super.initialize(opts);
|
|
163
148
|
}
|
|
164
149
|
|
|
@@ -172,39 +157,8 @@ export class IdentityManagerComponentInstance
|
|
|
172
157
|
this.elements.btnAddIdentityEl = shadow.getElementById('btn-add-identity') as HTMLButtonElement;
|
|
173
158
|
this.elements.noIdentityPlaceholderEl = shadow.getElementById('no-identity-placeholder') as HTMLDivElement;
|
|
174
159
|
this.elements.btnCreatePlaceholderEl = shadow.getElementById('btn-create-placeholder') as HTMLButtonElement;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
this.elements.identityGenEl = shadow.getElementById('identity-gen') as HTMLSpanElement;
|
|
178
|
-
this.elements.identityTimestampEl = shadow.getElementById('identity-timestamp') as HTMLSpanElement;
|
|
179
|
-
this.elements.identityUuidEl = shadow.getElementById('identity-uuid') as HTMLSpanElement;
|
|
180
|
-
this.elements.identityNameEl = shadow.getElementById('identity-name') as HTMLElement;
|
|
181
|
-
this.elements.identityDescriptionEl = shadow.getElementById('identity-description') as HTMLElement;
|
|
182
|
-
this.elements.identityFrameDetailsEl = shadow.getElementById('identity-frame-details') as HTMLPreElement;
|
|
183
|
-
this.elements.identityAggrDetailsEl = shadow.getElementById('identity-aggr-details') as HTMLPreElement;
|
|
184
|
-
|
|
185
|
-
// Scrubber elements
|
|
186
|
-
this.elements.btnScrubFirstEl = shadow.getElementById('btn-scrub-first') as HTMLButtonElement;
|
|
187
|
-
this.elements.btnScrubPrev10El = shadow.getElementById('btn-scrub-prev10') as HTMLButtonElement;
|
|
188
|
-
this.elements.btnScrubPrevEl = shadow.getElementById('btn-scrub-prev') as HTMLButtonElement;
|
|
189
|
-
this.elements.scrubberStatusEl = shadow.getElementById('scrubber-status') as HTMLSpanElement;
|
|
190
|
-
this.elements.btnScrubNextEl = shadow.getElementById('btn-scrub-next') as HTMLButtonElement;
|
|
191
|
-
this.elements.btnScrubNext10El = shadow.getElementById('btn-scrub-next10') as HTMLButtonElement;
|
|
192
|
-
this.elements.btnScrubLatestEl = shadow.getElementById('btn-scrub-latest') as HTMLButtonElement;
|
|
193
|
-
|
|
194
|
-
this.elements.poolsContainerEl = shadow.getElementById('pools-container') as HTMLDivElement;
|
|
195
|
-
this.elements.btnVerifyChainEl = shadow.getElementById('btn-verify-chain') as HTMLButtonElement;
|
|
196
|
-
// this.elements.btnSyncIdentityEl = shadow.getElementById('btn-sync-identity') as HTMLButtonElement;
|
|
197
|
-
this.elements.btnSetActiveEl = shadow.getElementById('btn-set-active') as HTMLButtonElement;
|
|
198
|
-
this.elements.verificationStatusEl = shadow.getElementById('verification-status') as HTMLDivElement;
|
|
199
|
-
this.elements.replicasListEl = shadow.getElementById('replicas-list') as HTMLDivElement;
|
|
200
|
-
// this.elements.inputReplicaUrlEl = shadow.getElementById('input-replica-url') as HTMLInputElement;
|
|
201
|
-
// this.elements.btnAddReplicaEl = shadow.getElementById('btn-add-replica') as HTMLButtonElement;
|
|
202
|
-
this.elements.rawAccordionHeaderEl = shadow.getElementById('raw-accordion-header') as HTMLDivElement;
|
|
203
|
-
this.elements.rawAccordionContentEl = shadow.getElementById('raw-accordion-content') as HTMLDivElement;
|
|
204
|
-
this.elements.rawKeystoneJsonEl = shadow.getElementById('raw-keystone-json') as HTMLPreElement;
|
|
205
|
-
this.elements.delegatesListEl = shadow.getElementById('delegates-list') as HTMLTableSectionElement;
|
|
206
|
-
|
|
207
|
-
// ElementBase requires contentEl (points to the main container/body area)
|
|
160
|
+
|
|
161
|
+
// ElementBase requires contentEl
|
|
208
162
|
this.elements.contentEl = shadow.getElementById('identity-manager-content') as HTMLDivElement;
|
|
209
163
|
|
|
210
164
|
this.initHandlers();
|
|
@@ -216,12 +170,65 @@ export class IdentityManagerComponentInstance
|
|
|
216
170
|
};
|
|
217
171
|
window.addEventListener(EVENT_IBGIB_IDENTITY_CHANGED, this._onIdentityChanged);
|
|
218
172
|
|
|
173
|
+
// Listen for requests to view details of a delegate (from child details component)
|
|
174
|
+
this.addEventListener('ibgib-view-keystone-details', async (e: any) => {
|
|
175
|
+
const addr = e.detail?.addr;
|
|
176
|
+
if (addr) {
|
|
177
|
+
await this.activateIbGib({ addr });
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
219
181
|
if (this.ibGibAddr === ROOT_ADDR || !this.ibGib) {
|
|
220
182
|
await this.loadKeystonesIndex();
|
|
221
183
|
} else {
|
|
222
184
|
await this.initSettings();
|
|
223
185
|
}
|
|
186
|
+
|
|
224
187
|
await this.renderUI();
|
|
188
|
+
|
|
189
|
+
// Spin off tab restore or defaults to allow createdPromise to resolve first
|
|
190
|
+
this.restoreOrInitTabs();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private async restoreOrInitTabs(): Promise<void> {
|
|
194
|
+
const settings = await this.getSettings<Settings_IdentityManager>({
|
|
195
|
+
settingsType: this.settingsType,
|
|
196
|
+
useCase: 'current',
|
|
197
|
+
});
|
|
198
|
+
if (settings) {
|
|
199
|
+
const validAddrs = (settings.openChildTjpAddrs ?? []).filter(addr => {
|
|
200
|
+
if (!addr || addr === '^' || addr === 'gib') return false;
|
|
201
|
+
const { gib } = getIbAndGib({ ibGibAddr: addr });
|
|
202
|
+
return !!gib && gib !== 'gib' && gib !== '^';
|
|
203
|
+
});
|
|
204
|
+
if (validAddrs.length !== (settings.openChildTjpAddrs ?? []).length) {
|
|
205
|
+
settings.openChildTjpAddrs = validAddrs;
|
|
206
|
+
const metaspace = getIbGibGlobalThis_SpaceGib(APP_CONFIG).metaspace;
|
|
207
|
+
if (metaspace) {
|
|
208
|
+
const sectionName_current = await getSectionName({
|
|
209
|
+
settingsType: this.settingsType,
|
|
210
|
+
useCase: 'current',
|
|
211
|
+
});
|
|
212
|
+
await mut8Timeline({
|
|
213
|
+
timeline: this.settings!.ibGib!,
|
|
214
|
+
metaspace,
|
|
215
|
+
mut8Opts: {
|
|
216
|
+
dataToAddOrPatch: {
|
|
217
|
+
sections: {
|
|
218
|
+
[sectionName_current]: settings,
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (!settings || (settings.openChildTjpAddrs ?? []).length === 0) {
|
|
228
|
+
await this.loadDefaultPrimaryIdentityTabs();
|
|
229
|
+
} else {
|
|
230
|
+
await this.reopenOldTabs();
|
|
231
|
+
}
|
|
225
232
|
}
|
|
226
233
|
|
|
227
234
|
override async disconnected(): Promise<void> {
|
|
@@ -252,45 +259,20 @@ export class IdentityManagerComponentInstance
|
|
|
252
259
|
}
|
|
253
260
|
}
|
|
254
261
|
|
|
255
|
-
|
|
256
|
-
|
|
257
262
|
private initHandlers() {
|
|
258
|
-
// Setup raw JSON accordion toggle
|
|
259
|
-
this.elements!.rawAccordionHeaderEl.addEventListener('click', () => this.toggleAccordion());
|
|
260
|
-
|
|
261
263
|
// Buttons
|
|
262
264
|
this.elements!.btnAddIdentityEl.addEventListener('click', () => this.handleAddNewIdentityFlow());
|
|
263
265
|
this.elements!.btnCreatePlaceholderEl.addEventListener('click', () => this.handleAddNewIdentityFlow());
|
|
264
|
-
this.elements!.btnVerifyChainEl.addEventListener('click', () => this.handleVerifyIdentityChain());
|
|
265
|
-
// this.elements!.btnSyncIdentityEl.addEventListener('click', () => this.handleSyncIdentity());
|
|
266
|
-
this.elements!.btnSetActiveEl.addEventListener('click', () => this.handleSetActiveIdentity());
|
|
267
|
-
// this.elements!.btnAddReplicaEl.addEventListener('click', () => this.handleAddReplicaSpace());
|
|
268
|
-
|
|
269
|
-
// Scrubber Buttons
|
|
270
|
-
this.elements!.btnScrubFirstEl.addEventListener('click', () => this.scrubFirst());
|
|
271
|
-
this.elements!.btnScrubPrev10El.addEventListener('click', () => this.scrubPrev10());
|
|
272
|
-
this.elements!.btnScrubPrevEl.addEventListener('click', () => this.scrubPrev());
|
|
273
|
-
this.elements!.btnScrubNextEl.addEventListener('click', () => this.scrubNext());
|
|
274
|
-
this.elements!.btnScrubNext10El.addEventListener('click', () => this.scrubNext10());
|
|
275
|
-
this.elements!.btnScrubLatestEl.addEventListener('click', () => this.scrubLatest());
|
|
276
266
|
|
|
277
267
|
// Convert vertical mouse wheel scrolling into horizontal scroll for tabs
|
|
278
268
|
this.elements!.tabsListEl.addEventListener('wheel', (e: WheelEvent) => {
|
|
279
269
|
if (e.deltaY !== 0) {
|
|
280
270
|
e.preventDefault();
|
|
281
|
-
// this.elements!.tabsListEl.scrollLeft += e.deltaY;
|
|
282
271
|
this.elements!.tabsListEl.scrollBy({ left: e.deltaY, behavior: 'smooth' });
|
|
283
272
|
}
|
|
284
273
|
}, { passive: false });
|
|
285
274
|
}
|
|
286
275
|
|
|
287
|
-
private toggleAccordion() {
|
|
288
|
-
const header = this.elements!.rawAccordionHeaderEl;
|
|
289
|
-
const content = this.elements!.rawAccordionContentEl;
|
|
290
|
-
header.classList.toggle('expanded');
|
|
291
|
-
content.classList.toggle('expanded');
|
|
292
|
-
}
|
|
293
|
-
|
|
294
276
|
protected async handleAddNewIdentityFlow() {
|
|
295
277
|
const lc = `${this.lc}[${this.handleAddNewIdentityFlow.name}]`;
|
|
296
278
|
devLog(`${lc} Triggering identity creation/import flow...`);
|
|
@@ -302,14 +284,21 @@ export class IdentityManagerComponentInstance
|
|
|
302
284
|
useRegExpPrefilter: true,
|
|
303
285
|
});
|
|
304
286
|
if (creator) {
|
|
305
|
-
// Hide placeholder
|
|
287
|
+
// Hide placeholder
|
|
306
288
|
this.elements!.noIdentityPlaceholderEl.classList.add('hidden');
|
|
307
|
-
this.elements!.identityDetailsViewEl.classList.add('hidden');
|
|
308
289
|
|
|
309
|
-
// Clear any previous creator
|
|
290
|
+
// Clear any previous creator/details
|
|
310
291
|
const existing = this.elements!.contentEl.querySelector('ibgib-keystone-creator');
|
|
311
292
|
if (existing) { existing.remove(); }
|
|
312
293
|
|
|
294
|
+
// Clear active child component inside ParentOfTabs to prevent conflict
|
|
295
|
+
const active = this.activeChildInfo;
|
|
296
|
+
if (active) {
|
|
297
|
+
active.childBtnEl.classList.remove('active');
|
|
298
|
+
active.active = false;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
this.elements!.contentEl.innerHTML = '';
|
|
313
302
|
this.elements!.contentEl.appendChild(creator as any);
|
|
314
303
|
devLog(`${lc} Mounted ibgib-keystone-creator successfully.`);
|
|
315
304
|
} else {
|
|
@@ -317,79 +306,13 @@ export class IdentityManagerComponentInstance
|
|
|
317
306
|
}
|
|
318
307
|
} catch (error) {
|
|
319
308
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
320
|
-
this.setVerificationStatus(`Failed to load creator: ${extractErrorMsg(error)}`, "error");
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
protected async handleVerifyIdentityChain() {
|
|
325
|
-
const lc = `${this.lc}[${this.handleVerifyIdentityChain.name}]`;
|
|
326
|
-
devLog(`${lc} Verifying identity keystone timeline...`);
|
|
327
|
-
this.setVerificationStatus("Verification request sent...", "info");
|
|
328
|
-
try {
|
|
329
|
-
// Skeleton logic placeholder
|
|
330
|
-
this.setVerificationStatus("Verification complete. Root Keystone is verified (Genesis phase 1).", "success");
|
|
331
|
-
} catch (error) {
|
|
332
|
-
this.setVerificationStatus(`Verification failed: ${extractErrorMsg(error)}`, "error");
|
|
333
309
|
}
|
|
334
310
|
}
|
|
335
311
|
|
|
336
|
-
// leave this in
|
|
337
|
-
// protected async handleSyncIdentity() {
|
|
338
|
-
// const lc = `${this.lc}[${this.handleSyncIdentity.name}]`;
|
|
339
|
-
// devLog(`${lc} Starting Peer-to-Peer sync saga...`);
|
|
340
|
-
// this.setVerificationStatus("Starting synchronization session...", "info");
|
|
341
|
-
// }
|
|
342
|
-
|
|
343
|
-
// leave this in
|
|
344
|
-
// protected async handleAddReplicaSpace() {
|
|
345
|
-
// const lc = `${this.lc}[${this.handleAddReplicaSpace.name}]`;
|
|
346
|
-
// const url = this.elements!.inputReplicaUrlEl.value;
|
|
347
|
-
// if (!url) {
|
|
348
|
-
// this.setVerificationStatus("Please enter a valid space replication URL.", "error");
|
|
349
|
-
// return;
|
|
350
|
-
// }
|
|
351
|
-
// devLog(`${lc} Registering replica space: ${url}`);
|
|
352
|
-
|
|
353
|
-
// // Add to UI list for verification
|
|
354
|
-
// const replicaItem = document.createElement('div');
|
|
355
|
-
// replicaItem.className = 'address-code';
|
|
356
|
-
// replicaItem.style.marginTop = '0.5rem';
|
|
357
|
-
// replicaItem.textContent = url;
|
|
358
|
-
// this.elements!.replicasListEl.appendChild(replicaItem);
|
|
359
|
-
|
|
360
|
-
// this.elements!.inputReplicaUrlEl.value = '';
|
|
361
|
-
// this.setVerificationStatus(`Registered replica endpoint: ${url}`, "success");
|
|
362
|
-
// }
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* dispatches the event to set {@link activeAddr} (if truthy) as the active
|
|
366
|
-
* identity. IOW, this "logs it in".
|
|
367
|
-
*/
|
|
368
|
-
protected async handleSetActiveIdentity() {
|
|
369
|
-
if (!this.activeAddr) { return; }
|
|
370
|
-
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
|
|
371
|
-
detail: { activeIdentityAddr: this.activeAddr },
|
|
372
|
-
bubbles: true,
|
|
373
|
-
composed: true
|
|
374
|
-
}));
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
private setVerificationStatus(msg: string, type: 'info' | 'success' | 'error') {
|
|
378
|
-
const statusEl = this.elements!.verificationStatusEl;
|
|
379
|
-
statusEl.textContent = msg;
|
|
380
|
-
statusEl.className = `status-msg ${type}`;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
private async viewIdentityDetails(addr: string): Promise<void> {
|
|
384
|
-
this.activeAddr = addr;
|
|
385
|
-
await this.renderUI();
|
|
386
|
-
}
|
|
387
|
-
|
|
388
312
|
private async resolveActiveIdentity() {
|
|
389
313
|
const lc = `${this.lc}[resolveActiveIdentity]`;
|
|
390
314
|
try {
|
|
391
315
|
if (!this.settings) {
|
|
392
|
-
this.activeAddr = null;
|
|
393
316
|
this.globalActiveAddr = null;
|
|
394
317
|
return;
|
|
395
318
|
}
|
|
@@ -400,17 +323,22 @@ export class IdentityManagerComponentInstance
|
|
|
400
323
|
const activeAddrInSettings = (generalSettings as any)?.activeIdentityAddr;
|
|
401
324
|
|
|
402
325
|
const registeredKeystones = this.ibGib?.rel8ns?.keystone ?? [];
|
|
403
|
-
|
|
326
|
+
const detailsPromises = registeredKeystones.map(async addr => {
|
|
327
|
+
const details = await this.getKeystoneDetails(addr);
|
|
328
|
+
return { addr, isPrimary: details?.isPrimary ?? false };
|
|
329
|
+
});
|
|
330
|
+
const resolvedDetails = await Promise.all(detailsPromises);
|
|
331
|
+
const primaryKeystones = resolvedDetails
|
|
332
|
+
.filter(item => item.isPrimary)
|
|
333
|
+
.map(item => item.addr);
|
|
334
|
+
|
|
335
|
+
if (activeAddrInSettings && primaryKeystones.includes(activeAddrInSettings)) {
|
|
404
336
|
this.globalActiveAddr = activeAddrInSettings;
|
|
405
|
-
} else if (
|
|
406
|
-
this.globalActiveAddr =
|
|
337
|
+
} else if (primaryKeystones.length > 0) {
|
|
338
|
+
this.globalActiveAddr = primaryKeystones[0];
|
|
407
339
|
} else {
|
|
408
340
|
this.globalActiveAddr = null;
|
|
409
341
|
}
|
|
410
|
-
|
|
411
|
-
if (!this.activeAddr) {
|
|
412
|
-
this.activeAddr = this.globalActiveAddr;
|
|
413
|
-
}
|
|
414
342
|
} catch (error) {
|
|
415
343
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
416
344
|
this.globalActiveAddr = null;
|
|
@@ -421,406 +349,291 @@ export class IdentityManagerComponentInstance
|
|
|
421
349
|
const lc = `${this.lc}[${this.renderUI.name}]`;
|
|
422
350
|
if (!this.elements) { return; }
|
|
423
351
|
|
|
424
|
-
// always resolve the current active identity, even if we aren't
|
|
425
|
-
// necessarily rendering the details for that identity (if it isn't
|
|
426
|
-
// this.activeAddr)
|
|
427
352
|
await this.resolveActiveIdentity();
|
|
428
353
|
|
|
429
354
|
const keystones = this.ibGib?.rel8ns?.keystone ?? [];
|
|
430
|
-
|
|
431
|
-
if (keystones.length === 0) {
|
|
432
|
-
this.elements.tabsListEl.innerHTML = '';
|
|
355
|
+
if (keystones.length === 0 && this.childInfos.length === 0) {
|
|
433
356
|
this.elements.noIdentityPlaceholderEl.classList.remove('hidden');
|
|
434
|
-
this.elements.
|
|
435
|
-
|
|
436
|
-
const existing = this.elements.contentEl.querySelector('ibgib-keystone-creator');
|
|
437
|
-
if (existing && !this.elements.noIdentityPlaceholderEl.classList.contains('hidden')) {
|
|
438
|
-
existing.remove();
|
|
439
|
-
}
|
|
440
|
-
return; /* <<<< returns early */
|
|
357
|
+
this.elements.contentEl.innerHTML = '';
|
|
358
|
+
return;
|
|
441
359
|
}
|
|
442
360
|
|
|
443
361
|
this.elements.noIdentityPlaceholderEl.classList.add('hidden');
|
|
444
362
|
|
|
445
|
-
// Render
|
|
446
|
-
this.
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
// Initial fallback label and tooltip
|
|
452
|
-
let displayTab = addr;
|
|
453
|
-
if (displayTab.length > 12) {
|
|
454
|
-
displayTab = displayTab.substring(0, 5) + '...' + displayTab.substring(displayTab.length - 4);
|
|
455
|
-
}
|
|
456
|
-
tabEl.textContent = displayTab;
|
|
457
|
-
tabEl.title = addr;
|
|
363
|
+
// Render tab highlights
|
|
364
|
+
for (const info of this.childInfos) {
|
|
365
|
+
const btn = info.childBtnEl;
|
|
366
|
+
btn.className = `tab-btn ${info.active ? 'active' : ''} ${info.addr === this.globalActiveAddr ? 'global-active' : ''}`;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
458
369
|
|
|
459
|
-
|
|
370
|
+
private async loadDefaultPrimaryIdentityTabs() {
|
|
371
|
+
const keystones = (this.ibGib?.rel8ns?.keystone ?? []).filter(addr => {
|
|
372
|
+
if (!addr || addr === '^' || addr === 'gib') return false;
|
|
373
|
+
const { gib } = getIbAndGib({ ibGibAddr: addr });
|
|
374
|
+
return !!gib && gib !== 'gib' && gib !== '^';
|
|
375
|
+
});
|
|
376
|
+
const detailsPromises = keystones.map(async addr => {
|
|
460
377
|
const details = await this.getKeystoneDetails(addr);
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
tabEl.textContent = name;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
const tooltipParts: string[] = [];
|
|
471
|
-
if (details.username) {
|
|
472
|
-
tooltipParts.push(`User: ${details.username}`);
|
|
473
|
-
}
|
|
474
|
-
if (details.description) {
|
|
475
|
-
const desc = details.description.length > 100
|
|
476
|
-
? details.description.substring(0, 97) + '...'
|
|
477
|
-
: details.description;
|
|
478
|
-
tooltipParts.push(`Desc: ${desc}`);
|
|
479
|
-
}
|
|
480
|
-
tooltipParts.push(`Addr: ${addr}`);
|
|
481
|
-
tabEl.title = tooltipParts.join('\n');
|
|
378
|
+
return { addr, isPrimary: details?.isPrimary ?? false };
|
|
379
|
+
});
|
|
380
|
+
const resolvedDetails = await Promise.all(detailsPromises);
|
|
381
|
+
const primaryKeystones = resolvedDetails
|
|
382
|
+
.filter(item => item.isPrimary)
|
|
383
|
+
.map(item => item.addr);
|
|
482
384
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
this.elements.tabsListEl.appendChild(tabEl);
|
|
385
|
+
if (primaryKeystones.length === 0) {
|
|
386
|
+
this.elements!.noIdentityPlaceholderEl.classList.remove('hidden');
|
|
387
|
+
return;
|
|
487
388
|
}
|
|
488
389
|
|
|
489
|
-
|
|
490
|
-
const existing = this.elements.contentEl.querySelector('ibgib-keystone-creator');
|
|
491
|
-
if (existing) { existing.remove(); }
|
|
492
|
-
|
|
493
|
-
this.elements.identityDetailsViewEl.classList.remove('hidden');
|
|
390
|
+
this.elements!.noIdentityPlaceholderEl.classList.add('hidden');
|
|
494
391
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
this.
|
|
499
|
-
this.elements.btnSetActiveEl.classList.add('active-primary');
|
|
500
|
-
} else {
|
|
501
|
-
this.elements.btnSetActiveEl.disabled = false;
|
|
502
|
-
this.elements.btnSetActiveEl.textContent = "Set as Active Identity";
|
|
503
|
-
this.elements.btnSetActiveEl.classList.remove('active-primary');
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
if (this.activeAddr !== this.lastLoadedHistoryAddr) {
|
|
507
|
-
await this.loadHistory(this.activeAddr);
|
|
508
|
-
this.lastLoadedHistoryAddr = this.activeAddr;
|
|
392
|
+
this.reloadingTabs = true;
|
|
393
|
+
try {
|
|
394
|
+
for (const addr of primaryKeystones) {
|
|
395
|
+
await this.activateIbGib({ addr });
|
|
509
396
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
} else {
|
|
513
|
-
this.elements.identityDetailsViewEl.classList.add('hidden');
|
|
514
|
-
this.clearActiveDetails();
|
|
397
|
+
} finally {
|
|
398
|
+
this.reloadingTabs = false;
|
|
515
399
|
}
|
|
516
|
-
}
|
|
517
400
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
this.
|
|
523
|
-
this.elements.identityNameEl.textContent = '-';
|
|
524
|
-
this.elements.identityDescriptionEl.textContent = '-';
|
|
525
|
-
this.elements.identityFrameDetailsEl.textContent = '{}';
|
|
526
|
-
this.elements.identityAggrDetailsEl.textContent = '{}';
|
|
527
|
-
this.elements.scrubberStatusEl.textContent = 'Frame - / -';
|
|
528
|
-
this.elements.poolsContainerEl.innerHTML = '';
|
|
529
|
-
if (this.elements.delegatesListEl) {
|
|
530
|
-
this.elements.delegatesListEl.innerHTML = '';
|
|
531
|
-
}
|
|
532
|
-
this.history = [];
|
|
533
|
-
this.currentFrameIndex = -1;
|
|
401
|
+
// Activate the global active identity (if open), or the first primary one
|
|
402
|
+
const activeToOpen = primaryKeystones.includes(this.globalActiveAddr || '')
|
|
403
|
+
? this.globalActiveAddr!
|
|
404
|
+
: primaryKeystones[0];
|
|
405
|
+
await this.activateIbGib({ addr: activeToOpen });
|
|
534
406
|
}
|
|
535
407
|
|
|
536
|
-
|
|
537
|
-
const lc = `${this.lc}[
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const metaspace = getIbGibGlobalThis_SpaceGib(APP_CONFIG).metaspace;
|
|
542
|
-
if (!metaspace) return;
|
|
543
|
-
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
544
|
-
if (!space) return;
|
|
545
|
-
|
|
546
|
-
let currentAddr: string | undefined = tipAddr;
|
|
547
|
-
const tempHistory: KeystoneIbGib_V1[] = [];
|
|
548
|
-
|
|
549
|
-
while (currentAddr) {
|
|
550
|
-
const res = await metaspace.get({ addr: currentAddr, space });
|
|
551
|
-
if (!res.success || !res.ibGibs || res.ibGibs.length === 0) {
|
|
552
|
-
console.warn(`${lc} Could not find frame at ${currentAddr}`);
|
|
553
|
-
break;
|
|
554
|
-
}
|
|
555
|
-
const keystone = res.ibGibs[0] as KeystoneIbGib_V1;
|
|
556
|
-
tempHistory.push(keystone);
|
|
557
|
-
|
|
558
|
-
if (keystone.data?.n === 0) {
|
|
559
|
-
break;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
const past = keystone.rel8ns?.past;
|
|
563
|
-
currentAddr = (past && past.length > 0) ? past[past.length - 1] : undefined;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
this.history = tempHistory.reverse();
|
|
567
|
-
this.currentFrameIndex = this.history.length - 1;
|
|
568
|
-
}
|
|
408
|
+
public override async activateIbGib({ addr, ibGib }: { addr?: IbGibAddr; ibGib?: IbGib_V1; }): Promise<void> {
|
|
409
|
+
const lc = `${this.lc}[activateIbGib]`;
|
|
410
|
+
try {
|
|
411
|
+
if (!this.metaspace) { throw new Error(`(UNEXPECTED) this.metaspace falsy? (E: f9e0e9a1427899eba8e469c18d7ae826)`); }
|
|
569
412
|
|
|
570
|
-
|
|
571
|
-
if (this.history.length === 0) return;
|
|
572
|
-
this.currentFrameIndex = Math.max(0, Math.min(index, this.history.length - 1));
|
|
573
|
-
this.updateFrameDetailsView();
|
|
574
|
-
}
|
|
413
|
+
await super.activateIbGib({ addr, ibGib });
|
|
575
414
|
|
|
576
|
-
private scrubFirst() {
|
|
577
|
-
this.scrubTo(0);
|
|
578
|
-
}
|
|
579
415
|
|
|
580
|
-
|
|
581
|
-
this.scrubTo(this.currentFrameIndex - 10);
|
|
582
|
-
}
|
|
416
|
+
if (!this.activeChildInfo) { throw new Error(`(UNEXPECTED) activeChildInfo falsy after activateIbGib? (E: d76bd8bc300f3fdc486d50c8b2644826)`); }
|
|
583
417
|
|
|
584
|
-
|
|
585
|
-
this.scrubTo(this.currentFrameIndex - 1);
|
|
586
|
-
}
|
|
418
|
+
ibGib ??= this.activeChildInfo.component?.ibGib;
|
|
587
419
|
|
|
588
|
-
|
|
589
|
-
this.scrubTo(this.currentFrameIndex + 1);
|
|
590
|
-
}
|
|
420
|
+
if (!ibGib) { throw new Error(`(UNEXPECTED) ibGib falsy? (E: 5b6ec745dd32fd2128635728e3f35e26)`); }
|
|
591
421
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
422
|
+
if (!ibGib.ib.startsWith(KEYSTONE_ATOM)) {
|
|
423
|
+
throw new Error(`ibGib.ib (${ibGib.ib}) does not start with keystone atom (${KEYSTONE_ATOM}) (E: e0df410381c8e569eb6da996e79b6826)`);
|
|
424
|
+
}
|
|
595
425
|
|
|
596
|
-
|
|
597
|
-
this.scrubTo(this.history.length - 1);
|
|
598
|
-
}
|
|
426
|
+
this.elements!.noIdentityPlaceholderEl.classList.add('hidden');
|
|
599
427
|
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
428
|
+
if (!this.reloadingTabs) {
|
|
429
|
+
const settings_current = await this.getSettings<Settings_IdentityManager>({
|
|
430
|
+
settingsType: this.settingsType,
|
|
431
|
+
useCase: 'current',
|
|
432
|
+
});
|
|
433
|
+
if (settings_current) {
|
|
434
|
+
let modified = false;
|
|
435
|
+
const tjpAddr = getTjpAddr({ ibGib: this.activeChildInfo.component?.ibGib || ibGib!, defaultIfNone: 'incomingAddr' });
|
|
436
|
+
if (tjpAddr) {
|
|
437
|
+
if (!settings_current.openChildTjpAddrs.includes(tjpAddr)) {
|
|
438
|
+
settings_current.openChildTjpAddrs.push(tjpAddr);
|
|
439
|
+
modified = true;
|
|
440
|
+
}
|
|
441
|
+
if (settings_current.activeChildTjpAddr !== tjpAddr) {
|
|
442
|
+
settings_current.activeChildTjpAddr = tjpAddr;
|
|
443
|
+
modified = true;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (modified) {
|
|
447
|
+
const metaspace = getIbGibGlobalThis_SpaceGib(APP_CONFIG).metaspace;
|
|
448
|
+
if (metaspace) {
|
|
449
|
+
const sectionName_current = await getSectionName({
|
|
450
|
+
settingsType: this.settingsType,
|
|
451
|
+
useCase: 'current',
|
|
452
|
+
});
|
|
453
|
+
await mut8Timeline({
|
|
454
|
+
timeline: this.settings!.ibGib!,
|
|
455
|
+
metaspace,
|
|
456
|
+
mut8Opts: {
|
|
457
|
+
dataToAddOrPatch: {
|
|
458
|
+
sections: {
|
|
459
|
+
[sectionName_current]: settings_current,
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
603
468
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
469
|
+
await this.renderUI();
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
607
472
|
}
|
|
473
|
+
}
|
|
608
474
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
475
|
+
protected async getLoadedChildInfo({
|
|
476
|
+
addr,
|
|
477
|
+
ibGib,
|
|
478
|
+
}: {
|
|
479
|
+
addr: IbGibAddr,
|
|
480
|
+
ibGib?: IbGib_V1,
|
|
481
|
+
}): Promise<IdentityTabInfo> {
|
|
482
|
+
const lc = `${this.lc}[getLoadedChildInfo]`;
|
|
483
|
+
try {
|
|
484
|
+
if (!addr) { throw new Error(`(UNEXPECTED) addr falsy?`); }
|
|
485
|
+
if (addr === '^' || addr === 'gib' || getIbAndGib({ ibGibAddr: addr }).gib === '^') {
|
|
486
|
+
throw new Error(`Cannot load child info for primitive address ${addr}`);
|
|
487
|
+
}
|
|
488
|
+
const tjpGib = getGibInfo({ ibGibAddr: addr }).tjpGib ?? getIbAndGib({ ibGibAddr: addr }).gib;
|
|
489
|
+
|
|
490
|
+
const fnCreateAndLoadChildComponent = async () => {
|
|
491
|
+
const componentSvc = await getComponentSvc();
|
|
492
|
+
const detailsComponent = await componentSvc.getComponentInstance({
|
|
493
|
+
path: 'ibgib-keystone-scrubber',
|
|
494
|
+
ibGibAddr: addr,
|
|
495
|
+
useRegExpPrefilter: true,
|
|
496
|
+
});
|
|
497
|
+
if (!detailsComponent) {
|
|
498
|
+
throw new Error(`(UNEXPECTED) detailsComponent falsy?`);
|
|
499
|
+
}
|
|
500
|
+
return detailsComponent;
|
|
627
501
|
}
|
|
628
|
-
}
|
|
629
|
-
this.elements.identityTimestampEl.textContent = formattedTimestamp;
|
|
630
|
-
|
|
631
|
-
// Update UUID
|
|
632
|
-
this.elements.identityUuidEl.textContent = keystone.data?.uuid || 'N/A';
|
|
633
|
-
|
|
634
|
-
// Update Scrubber Status
|
|
635
|
-
this.elements.scrubberStatusEl.textContent = `Frame ${this.currentFrameIndex + 1} / ${this.history.length}`;
|
|
636
|
-
|
|
637
|
-
// Disable/enable scrubber buttons based on boundaries
|
|
638
|
-
this.elements.btnScrubFirstEl.disabled = this.currentFrameIndex === 0;
|
|
639
|
-
this.elements.btnScrubPrev10El.disabled = this.currentFrameIndex === 0;
|
|
640
|
-
this.elements.btnScrubPrevEl.disabled = this.currentFrameIndex === 0;
|
|
641
|
-
this.elements.btnScrubNextEl.disabled = this.currentFrameIndex === this.history.length - 1;
|
|
642
|
-
this.elements.btnScrubNext10El.disabled = this.currentFrameIndex === this.history.length - 1;
|
|
643
|
-
this.elements.btnScrubLatestEl.disabled = this.currentFrameIndex === this.history.length - 1;
|
|
644
|
-
|
|
645
|
-
// Show Frame Details
|
|
646
|
-
const frameDetails = keystone.data?.frameDetails;
|
|
647
|
-
this.elements.identityFrameDetailsEl.textContent = frameDetails ? pretty(frameDetails) : '{}';
|
|
648
502
|
|
|
649
|
-
|
|
650
|
-
const metaspace = getIbGibGlobalThis_SpaceGib(APP_CONFIG).metaspace;
|
|
651
|
-
if (metaspace) {
|
|
652
|
-
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
653
|
-
if (space) {
|
|
654
|
-
try {
|
|
655
|
-
const keystoneSvc = new KeystoneService_V1();
|
|
656
|
-
const aggregated = await keystoneSvc.getAggregateDetails({
|
|
657
|
-
latestKeystone: keystone,
|
|
658
|
-
metaspace,
|
|
659
|
-
space
|
|
660
|
-
});
|
|
503
|
+
let tabInfo: IdentityTabInfo;
|
|
661
504
|
|
|
662
|
-
|
|
505
|
+
const filtered = this.childInfos.filter(x => {
|
|
506
|
+
const tabGibInfo = getGibInfo({ ibGibAddr: x.addr });
|
|
507
|
+
const tabTjpGib = tabGibInfo.tjpGib ?? getIbAndGib({ ibGibAddr: x.addr }).gib;
|
|
508
|
+
return tabTjpGib === tjpGib;
|
|
509
|
+
});
|
|
663
510
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
this.elements.identityAggrDetailsEl.textContent = '{}';
|
|
670
|
-
this.elements.identityNameEl.textContent = '-';
|
|
671
|
-
this.elements.identityDescriptionEl.textContent = '-';
|
|
511
|
+
if (filtered.length > 0) {
|
|
512
|
+
if (filtered.length !== 1) { throw new Error(`(UNEXPECTED) filtered.length !== 1?`); }
|
|
513
|
+
tabInfo = filtered[0];
|
|
514
|
+
if (!tabInfo.component) {
|
|
515
|
+
tabInfo.component = await fnCreateAndLoadChildComponent();
|
|
672
516
|
}
|
|
673
517
|
} else {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
518
|
+
const detailsComponent = await fnCreateAndLoadChildComponent();
|
|
519
|
+
let i = 0;
|
|
520
|
+
while (!detailsComponent.ibGib!) {
|
|
521
|
+
await delay(100);
|
|
522
|
+
i++;
|
|
523
|
+
if (i > 50) { // 5 seconds
|
|
524
|
+
debugger; // error loading details component ibgib
|
|
525
|
+
throw new Error(`(UNEXPECTED) detailsComponent.ibGib falsy? didn't load? (E: de50689834124914f770520f1eccb826)`);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
ibGib = detailsComponent.ibGib!;
|
|
529
|
+
addr = getIbGibAddr({ ibGib });
|
|
530
|
+
const tabBtnEl = await this.addChild({ addr, ibGib });
|
|
531
|
+
tabInfo = {
|
|
532
|
+
addr,
|
|
533
|
+
childBtnEl: tabBtnEl,
|
|
534
|
+
component: detailsComponent,
|
|
535
|
+
active: false,
|
|
536
|
+
};
|
|
537
|
+
this.childInfos.push(tabInfo);
|
|
677
538
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
539
|
+
|
|
540
|
+
return tabInfo;
|
|
541
|
+
} catch (error) {
|
|
542
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
543
|
+
throw error;
|
|
682
544
|
}
|
|
545
|
+
}
|
|
683
546
|
|
|
684
|
-
|
|
685
|
-
|
|
547
|
+
protected override async addChild({
|
|
548
|
+
addr,
|
|
549
|
+
ibGib,
|
|
550
|
+
}: {
|
|
551
|
+
ibGib: IbGib_V1,
|
|
552
|
+
addr?: IbGibAddr,
|
|
553
|
+
}): Promise<HTMLElement> {
|
|
554
|
+
const lc = `${this.lc}[addChild]`;
|
|
555
|
+
try {
|
|
556
|
+
addr ??= getIbGibAddr({ ibGib });
|
|
557
|
+
if (addr === '^' || addr === 'gib' || getIbAndGib({ ibGibAddr: addr }).gib === '^') {
|
|
558
|
+
throw new Error(`Cannot add child tab for primitive address ${addr}`);
|
|
559
|
+
}
|
|
560
|
+
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy?`); }
|
|
561
|
+
const { tabsListEl } = this.elements;
|
|
686
562
|
|
|
687
|
-
|
|
688
|
-
this.renderChallengePools(keystone.data?.challengePools || []);
|
|
563
|
+
addr ??= getIbGibAddr({ ibGib });
|
|
689
564
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
565
|
+
const childBtnEl = document.createElement('button');
|
|
566
|
+
childBtnEl.className = 'tab-btn';
|
|
567
|
+
childBtnEl.id = `identity-tab-button-${addr}`;
|
|
693
568
|
|
|
694
|
-
|
|
695
|
-
if (!this.elements) return;
|
|
696
|
-
const container = this.elements.poolsContainerEl;
|
|
697
|
-
container.innerHTML = '';
|
|
569
|
+
await this.updateTabTitleAndText({ span: childBtnEl, ibGib, addr });
|
|
698
570
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
571
|
+
const details = await this.getKeystoneDetails(addr);
|
|
572
|
+
if (!details.isPrimary) {
|
|
573
|
+
const closeBtnEl = document.createElement('span');
|
|
574
|
+
closeBtnEl.className = 'close-tab-button';
|
|
575
|
+
closeBtnEl.textContent = ' ×';
|
|
576
|
+
closeBtnEl.style.marginLeft = '0.5rem';
|
|
577
|
+
closeBtnEl.style.cursor = 'pointer';
|
|
578
|
+
childBtnEl.appendChild(closeBtnEl);
|
|
579
|
+
closeBtnEl.addEventListener('click', async (event) => {
|
|
580
|
+
event.stopPropagation(); // Prevent activating the tab
|
|
581
|
+
await this.closeTab({ ibGib });
|
|
582
|
+
});
|
|
583
|
+
}
|
|
703
584
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
// Generate HTML for the challenges list
|
|
715
|
-
const challenges = pool.challenges || {};
|
|
716
|
-
const challengeListHtml = Object.entries(challenges).map(([id, challenge]: [string, any]) => {
|
|
717
|
-
const truncatedHash = challenge.hash && challenge.hash.length > 20
|
|
718
|
-
? challenge.hash.substring(0, 10) + '...' + challenge.hash.substring(challenge.hash.length - 8)
|
|
719
|
-
: challenge.hash || 'N/A';
|
|
720
|
-
return `
|
|
721
|
-
<div class="pool-challenge-item">
|
|
722
|
-
<span class="challenge-id">${id}</span>
|
|
723
|
-
<span class="challenge-hash" title="${challenge.hash || ''}">${truncatedHash}</span>
|
|
724
|
-
</div>
|
|
725
|
-
`;
|
|
726
|
-
}).join('');
|
|
727
|
-
|
|
728
|
-
card.innerHTML = `
|
|
729
|
-
<div class="pool-header">
|
|
730
|
-
<span class="pool-title">${pool.id || 'Unnamed Pool'}</span>
|
|
731
|
-
<span class="pool-tag ${isForeign ? 'foreign' : 'native'}">${isForeign ? 'Foreign' : 'Native'}</span>
|
|
732
|
-
</div>
|
|
733
|
-
<div class="pool-grid">
|
|
734
|
-
<div class="pool-field">
|
|
735
|
-
<label>Challenge Type</label>
|
|
736
|
-
<span>${config.type || 'N/A'}</span>
|
|
737
|
-
</div>
|
|
738
|
-
<div class="pool-field">
|
|
739
|
-
<label>Target Size</label>
|
|
740
|
-
<span>${behavior.size ?? 'N/A'}</span>
|
|
741
|
-
</div>
|
|
742
|
-
<div class="pool-field">
|
|
743
|
-
<label>Active Challenges</label>
|
|
744
|
-
<span>${activeCount}</span>
|
|
745
|
-
</div>
|
|
746
|
-
<div class="pool-field">
|
|
747
|
-
<label>Replenish Strategy</label>
|
|
748
|
-
<span>${behavior.replenish || 'N/A'}</span>
|
|
749
|
-
</div>
|
|
750
|
-
<div class="pool-field">
|
|
751
|
-
<label>Allowed Verbs</label>
|
|
752
|
-
<span>${allowedVerbs.length > 0 ? allowedVerbs.join(', ') : 'Any'}</span>
|
|
753
|
-
</div>
|
|
754
|
-
<div class="pool-field">
|
|
755
|
-
<label>FIFO / Random cost</label>
|
|
756
|
-
<span>FIFO: ${behavior.selectSequentially ?? 0}, Rand: ${behavior.selectRandomly ?? 0}</span>
|
|
757
|
-
</div>
|
|
758
|
-
</div>
|
|
759
|
-
|
|
760
|
-
<!-- Collapsible Challenges List -->
|
|
761
|
-
<details class="pool-details">
|
|
762
|
-
<summary class="pool-details-summary">Challenges (${activeCount})</summary>
|
|
763
|
-
<div class="pool-challenges-list">
|
|
764
|
-
${challengeListHtml || '<p class="placeholder-text" style="padding: 0.5rem; text-align: center;">No challenges active.</p>'}
|
|
765
|
-
</div>
|
|
766
|
-
</details>
|
|
767
|
-
`;
|
|
768
|
-
container.appendChild(card);
|
|
585
|
+
tabsListEl.appendChild(childBtnEl);
|
|
586
|
+
childBtnEl.addEventListener('click', async (event) => {
|
|
587
|
+
await this.activateIbGib({ addr });
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
return childBtnEl;
|
|
591
|
+
} catch (error) {
|
|
592
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
593
|
+
throw error;
|
|
769
594
|
}
|
|
770
595
|
}
|
|
771
596
|
|
|
772
|
-
private async
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
597
|
+
private async updateTabTitleAndText({
|
|
598
|
+
span,
|
|
599
|
+
ibGib,
|
|
600
|
+
addr,
|
|
601
|
+
}: {
|
|
602
|
+
span: HTMLElement,
|
|
603
|
+
ibGib: IbGib_V1,
|
|
604
|
+
addr: string,
|
|
605
|
+
}): Promise<void> {
|
|
606
|
+
const details = await this.getKeystoneDetails(addr);
|
|
607
|
+
let name = details.username;
|
|
608
|
+
const maxTabLen = 16;
|
|
609
|
+
if (name) {
|
|
610
|
+
if (name.length > maxTabLen) {
|
|
611
|
+
name = name.substring(0, maxTabLen - 3) + '...';
|
|
612
|
+
}
|
|
613
|
+
span.textContent = name;
|
|
614
|
+
} else {
|
|
615
|
+
let displayTab = addr;
|
|
616
|
+
if (displayTab.length > 12) {
|
|
617
|
+
displayTab = displayTab.substring(0, 5) + '...' + displayTab.substring(displayTab.length - 4);
|
|
618
|
+
}
|
|
619
|
+
span.textContent = displayTab;
|
|
786
620
|
}
|
|
787
621
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
const tdName = document.createElement('td');
|
|
792
|
-
tdName.textContent = 'Loading...';
|
|
793
|
-
|
|
794
|
-
const tdTjp = document.createElement('td');
|
|
795
|
-
tdTjp.textContent = delegateTjpAddr;
|
|
796
|
-
tdTjp.title = delegateTjpAddr;
|
|
797
|
-
|
|
798
|
-
const tdVerbs = document.createElement('td');
|
|
799
|
-
tdVerbs.textContent = info.allowedVerbs ? info.allowedVerbs.join(', ') : '-';
|
|
800
|
-
tdVerbs.title = tdVerbs.textContent;
|
|
801
|
-
|
|
802
|
-
tr.appendChild(tdName);
|
|
803
|
-
tr.appendChild(tdTjp);
|
|
804
|
-
tr.appendChild(tdVerbs);
|
|
805
|
-
listEl.appendChild(tr);
|
|
806
|
-
|
|
807
|
-
if (info.delegateAddr) {
|
|
808
|
-
this.getKeystoneDetails(info.delegateAddr).then(details => {
|
|
809
|
-
const textParts: string[] = [];
|
|
810
|
-
if (details.username) textParts.push(details.username);
|
|
811
|
-
if (details.description) textParts.push(details.description);
|
|
812
|
-
tdName.textContent = textParts.join(' / ') || 'Unnamed Delegate';
|
|
813
|
-
tdName.title = `Addr: ${info.delegateAddr}\n` + textParts.join('\n');
|
|
814
|
-
}).catch(err => {
|
|
815
|
-
tdName.textContent = 'Unknown Delegate';
|
|
816
|
-
});
|
|
817
|
-
} else {
|
|
818
|
-
tdName.textContent = 'No Address';
|
|
819
|
-
}
|
|
622
|
+
const tooltipParts: string[] = [];
|
|
623
|
+
if (details.username) {
|
|
624
|
+
tooltipParts.push(`User: ${details.username}`);
|
|
820
625
|
}
|
|
626
|
+
if (details.description) {
|
|
627
|
+
const desc = details.description.length > 100
|
|
628
|
+
? details.description.substring(0, 97) + '...'
|
|
629
|
+
: details.description;
|
|
630
|
+
tooltipParts.push(`Desc: ${desc}`);
|
|
631
|
+
}
|
|
632
|
+
tooltipParts.push(`Addr: ${addr}`);
|
|
633
|
+
span.title = tooltipParts.join('\n');
|
|
821
634
|
}
|
|
822
635
|
|
|
823
|
-
|
|
824
|
-
|
|
636
|
+
protected async removeTabBtn({ tabInfo }: { tabInfo: IdentityTabInfo }): Promise<void> {
|
|
637
|
+
this.elements!.tabsListEl.removeChild(tabInfo.childBtnEl);
|
|
825
638
|
}
|
|
826
639
|
}
|