@ibgib/space-gib 0.0.5 → 0.0.7
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-RXFIBFRK.mjs +42 -0
- package/dist/client/chunk-RXFIBFRK.mjs.map +7 -0
- package/dist/client/chunk-ULFNE26Y.mjs +2216 -0
- package/dist/client/chunk-ULFNE26Y.mjs.map +7 -0
- package/dist/client/index.html +35 -14
- package/dist/client/index.mjs +1 -1
- package/dist/client/script.mjs +1 -1
- package/dist/client/style.css +29 -5
- package/dist/server/server.mjs +1447 -270
- 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/bootstrap.mts +9 -0
- package/src/client/components/identity-header/identity-header.css +40 -2
- package/src/client/components/identity-header/identity-header.html +3 -2
- package/src/client/components/identity-header/identity-header.mts +127 -49
- package/src/client/components/identity-manager/identity-manager.css +57 -353
- package/src/client/components/identity-manager/identity-manager.html +0 -94
- package/src/client/components/identity-manager/identity-manager.mts +356 -484
- package/src/client/components/keystone-creator/keystone-creator.mts +90 -13
- package/src/client/components/keystone-details/keystone-details.css +472 -0
- package/src/client/components/keystone-details/keystone-details.html +99 -0
- package/src/client/components/keystone-details/keystone-details.mts +821 -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/dev-tools/common.mts +505 -10
- package/src/client/dev-tools/phase-4-1.mts +19 -4
- package/src/client/dev-tools/phase-4-10.mts +77 -305
- package/src/client/dev-tools/phase-4-2.mts +46 -212
- package/src/client/dev-tools/phase-4-3.mts +57 -198
- package/src/client/dev-tools/phase-4-4.mts +57 -170
- package/src/client/dev-tools/phase-4-5.mts +48 -204
- package/src/client/dev-tools/phase-4-6.mts +37 -103
- package/src/client/dev-tools/phase-4-7.mts +44 -228
- package/src/client/dev-tools/phase-4-8.mts +33 -136
- package/src/client/dev-tools/phase-4-9.mts +33 -137
- package/src/client/dev-tools/phase-4.mts +30 -6
- package/src/client/dev-tools.mts +18 -0
- package/src/client/index.html +35 -14
- package/src/client/style.css +29 -5
- package/src/client/types.mts +4 -1
- 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/sso-config.handler.mts +66 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-link.handler.mts +119 -0
- package/src/server/serve-gib/handlers/api/keystone/sso-login.handler.mts +189 -0
- package/src/server/server.mts +6 -0
- package/dist/client/chunk-ANGVYAEK.mjs +0 -42
- package/dist/client/chunk-ANGVYAEK.mjs.map +0 -7
- package/dist/client/chunk-IRGFDQRD.mjs +0 -1920
- package/dist/client/chunk-IRGFDQRD.mjs.map +0 -7
- package/dist/respec-gib.node.mjs +0 -5
|
@@ -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,81 +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
85
|
}
|
|
106
86
|
|
|
107
87
|
/**
|
|
108
88
|
* Concrete implementation of the Identity Manager component.
|
|
109
89
|
*/
|
|
110
90
|
export class IdentityManagerComponentInstance
|
|
111
|
-
extends
|
|
91
|
+
extends IbGibDynamicComponentInstanceBase_ParentOfTabs<Settings_IdentityManager, IbGib_V1, IdentityManagerElements, IdentityTabInfo>
|
|
112
92
|
implements IbGibDynamicComponentInstance<IbGib_V1, IdentityManagerElements> {
|
|
113
93
|
|
|
114
|
-
protected lc: string = `[IdentityManagerComponentInstance]`;
|
|
94
|
+
protected override lc: string = `[IdentityManagerComponentInstance]`;
|
|
115
95
|
|
|
116
|
-
private activeAddr: string | null = null;
|
|
117
96
|
private globalActiveAddr: string | null = null;
|
|
118
97
|
private _onIdentityChanged: ((e: any) => void) | null = null;
|
|
119
|
-
private
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
+
}
|
|
123
104
|
|
|
124
105
|
constructor() {
|
|
125
106
|
super();
|
|
126
107
|
}
|
|
127
108
|
|
|
128
|
-
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 }> {
|
|
129
110
|
const cached = this.keystoneCache.get(addr);
|
|
130
111
|
if (cached) return cached;
|
|
131
112
|
|
|
132
113
|
const metaspace = getIbGibGlobalThis_SpaceGib(APP_CONFIG).metaspace;
|
|
133
|
-
if (!metaspace) return { username: '', description: '' };
|
|
114
|
+
if (!metaspace) return { username: '', description: '', isPrimary: false, n: 0 };
|
|
134
115
|
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
135
|
-
if (!space) return { username: '', description: '' };
|
|
116
|
+
if (!space) return { username: '', description: '', isPrimary: false, n: 0 };
|
|
136
117
|
|
|
137
118
|
try {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
+
};
|
|
150
132
|
this.keystoneCache.set(addr, details);
|
|
151
133
|
return details;
|
|
152
134
|
}
|
|
@@ -154,10 +136,14 @@ export class IdentityManagerComponentInstance
|
|
|
154
136
|
console.warn(`Error getting details for keystone ${addr}: ${extractErrorMsg(err)}`);
|
|
155
137
|
}
|
|
156
138
|
|
|
157
|
-
return { username: '', description: '' };
|
|
139
|
+
return { username: '', description: '', isPrimary: false, n: 0 };
|
|
158
140
|
}
|
|
159
141
|
|
|
160
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;
|
|
161
147
|
await super.initialize(opts);
|
|
162
148
|
}
|
|
163
149
|
|
|
@@ -171,38 +157,8 @@ export class IdentityManagerComponentInstance
|
|
|
171
157
|
this.elements.btnAddIdentityEl = shadow.getElementById('btn-add-identity') as HTMLButtonElement;
|
|
172
158
|
this.elements.noIdentityPlaceholderEl = shadow.getElementById('no-identity-placeholder') as HTMLDivElement;
|
|
173
159
|
this.elements.btnCreatePlaceholderEl = shadow.getElementById('btn-create-placeholder') as HTMLButtonElement;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this.elements.identityGenEl = shadow.getElementById('identity-gen') as HTMLSpanElement;
|
|
177
|
-
this.elements.identityTimestampEl = shadow.getElementById('identity-timestamp') as HTMLSpanElement;
|
|
178
|
-
this.elements.identityUuidEl = shadow.getElementById('identity-uuid') as HTMLSpanElement;
|
|
179
|
-
this.elements.identityNameEl = shadow.getElementById('identity-name') as HTMLElement;
|
|
180
|
-
this.elements.identityDescriptionEl = shadow.getElementById('identity-description') as HTMLElement;
|
|
181
|
-
this.elements.identityFrameDetailsEl = shadow.getElementById('identity-frame-details') as HTMLPreElement;
|
|
182
|
-
this.elements.identityAggrDetailsEl = shadow.getElementById('identity-aggr-details') as HTMLPreElement;
|
|
183
|
-
|
|
184
|
-
// Scrubber elements
|
|
185
|
-
this.elements.btnScrubFirstEl = shadow.getElementById('btn-scrub-first') as HTMLButtonElement;
|
|
186
|
-
this.elements.btnScrubPrev10El = shadow.getElementById('btn-scrub-prev10') as HTMLButtonElement;
|
|
187
|
-
this.elements.btnScrubPrevEl = shadow.getElementById('btn-scrub-prev') as HTMLButtonElement;
|
|
188
|
-
this.elements.scrubberStatusEl = shadow.getElementById('scrubber-status') as HTMLSpanElement;
|
|
189
|
-
this.elements.btnScrubNextEl = shadow.getElementById('btn-scrub-next') as HTMLButtonElement;
|
|
190
|
-
this.elements.btnScrubNext10El = shadow.getElementById('btn-scrub-next10') as HTMLButtonElement;
|
|
191
|
-
this.elements.btnScrubLatestEl = shadow.getElementById('btn-scrub-latest') as HTMLButtonElement;
|
|
192
|
-
|
|
193
|
-
this.elements.poolsContainerEl = shadow.getElementById('pools-container') as HTMLDivElement;
|
|
194
|
-
this.elements.btnVerifyChainEl = shadow.getElementById('btn-verify-chain') as HTMLButtonElement;
|
|
195
|
-
// this.elements.btnSyncIdentityEl = shadow.getElementById('btn-sync-identity') as HTMLButtonElement;
|
|
196
|
-
this.elements.btnSetActiveEl = shadow.getElementById('btn-set-active') as HTMLButtonElement;
|
|
197
|
-
this.elements.verificationStatusEl = shadow.getElementById('verification-status') as HTMLDivElement;
|
|
198
|
-
this.elements.replicasListEl = shadow.getElementById('replicas-list') as HTMLDivElement;
|
|
199
|
-
// this.elements.inputReplicaUrlEl = shadow.getElementById('input-replica-url') as HTMLInputElement;
|
|
200
|
-
// this.elements.btnAddReplicaEl = shadow.getElementById('btn-add-replica') as HTMLButtonElement;
|
|
201
|
-
this.elements.rawAccordionHeaderEl = shadow.getElementById('raw-accordion-header') as HTMLDivElement;
|
|
202
|
-
this.elements.rawAccordionContentEl = shadow.getElementById('raw-accordion-content') as HTMLDivElement;
|
|
203
|
-
this.elements.rawKeystoneJsonEl = shadow.getElementById('raw-keystone-json') as HTMLPreElement;
|
|
204
|
-
|
|
205
|
-
// ElementBase requires contentEl (points to the main container/body area)
|
|
160
|
+
|
|
161
|
+
// ElementBase requires contentEl
|
|
206
162
|
this.elements.contentEl = shadow.getElementById('identity-manager-content') as HTMLDivElement;
|
|
207
163
|
|
|
208
164
|
this.initHandlers();
|
|
@@ -214,12 +170,65 @@ export class IdentityManagerComponentInstance
|
|
|
214
170
|
};
|
|
215
171
|
window.addEventListener(EVENT_IBGIB_IDENTITY_CHANGED, this._onIdentityChanged);
|
|
216
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
|
+
|
|
217
181
|
if (this.ibGibAddr === ROOT_ADDR || !this.ibGib) {
|
|
218
182
|
await this.loadKeystonesIndex();
|
|
219
183
|
} else {
|
|
220
184
|
await this.initSettings();
|
|
221
185
|
}
|
|
186
|
+
|
|
222
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
|
+
}
|
|
223
232
|
}
|
|
224
233
|
|
|
225
234
|
override async disconnected(): Promise<void> {
|
|
@@ -250,45 +259,20 @@ export class IdentityManagerComponentInstance
|
|
|
250
259
|
}
|
|
251
260
|
}
|
|
252
261
|
|
|
253
|
-
|
|
254
|
-
|
|
255
262
|
private initHandlers() {
|
|
256
|
-
// Setup raw JSON accordion toggle
|
|
257
|
-
this.elements!.rawAccordionHeaderEl.addEventListener('click', () => this.toggleAccordion());
|
|
258
|
-
|
|
259
263
|
// Buttons
|
|
260
264
|
this.elements!.btnAddIdentityEl.addEventListener('click', () => this.handleAddNewIdentityFlow());
|
|
261
265
|
this.elements!.btnCreatePlaceholderEl.addEventListener('click', () => this.handleAddNewIdentityFlow());
|
|
262
|
-
this.elements!.btnVerifyChainEl.addEventListener('click', () => this.handleVerifyIdentityChain());
|
|
263
|
-
// this.elements!.btnSyncIdentityEl.addEventListener('click', () => this.handleSyncIdentity());
|
|
264
|
-
this.elements!.btnSetActiveEl.addEventListener('click', () => this.handleSetActiveIdentity());
|
|
265
|
-
// this.elements!.btnAddReplicaEl.addEventListener('click', () => this.handleAddReplicaSpace());
|
|
266
|
-
|
|
267
|
-
// Scrubber Buttons
|
|
268
|
-
this.elements!.btnScrubFirstEl.addEventListener('click', () => this.scrubFirst());
|
|
269
|
-
this.elements!.btnScrubPrev10El.addEventListener('click', () => this.scrubPrev10());
|
|
270
|
-
this.elements!.btnScrubPrevEl.addEventListener('click', () => this.scrubPrev());
|
|
271
|
-
this.elements!.btnScrubNextEl.addEventListener('click', () => this.scrubNext());
|
|
272
|
-
this.elements!.btnScrubNext10El.addEventListener('click', () => this.scrubNext10());
|
|
273
|
-
this.elements!.btnScrubLatestEl.addEventListener('click', () => this.scrubLatest());
|
|
274
266
|
|
|
275
267
|
// Convert vertical mouse wheel scrolling into horizontal scroll for tabs
|
|
276
268
|
this.elements!.tabsListEl.addEventListener('wheel', (e: WheelEvent) => {
|
|
277
269
|
if (e.deltaY !== 0) {
|
|
278
270
|
e.preventDefault();
|
|
279
|
-
// this.elements!.tabsListEl.scrollLeft += e.deltaY;
|
|
280
271
|
this.elements!.tabsListEl.scrollBy({ left: e.deltaY, behavior: 'smooth' });
|
|
281
272
|
}
|
|
282
273
|
}, { passive: false });
|
|
283
274
|
}
|
|
284
275
|
|
|
285
|
-
private toggleAccordion() {
|
|
286
|
-
const header = this.elements!.rawAccordionHeaderEl;
|
|
287
|
-
const content = this.elements!.rawAccordionContentEl;
|
|
288
|
-
header.classList.toggle('expanded');
|
|
289
|
-
content.classList.toggle('expanded');
|
|
290
|
-
}
|
|
291
|
-
|
|
292
276
|
protected async handleAddNewIdentityFlow() {
|
|
293
277
|
const lc = `${this.lc}[${this.handleAddNewIdentityFlow.name}]`;
|
|
294
278
|
devLog(`${lc} Triggering identity creation/import flow...`);
|
|
@@ -300,14 +284,21 @@ export class IdentityManagerComponentInstance
|
|
|
300
284
|
useRegExpPrefilter: true,
|
|
301
285
|
});
|
|
302
286
|
if (creator) {
|
|
303
|
-
// Hide placeholder
|
|
287
|
+
// Hide placeholder
|
|
304
288
|
this.elements!.noIdentityPlaceholderEl.classList.add('hidden');
|
|
305
|
-
this.elements!.identityDetailsViewEl.classList.add('hidden');
|
|
306
289
|
|
|
307
|
-
// Clear any previous creator
|
|
290
|
+
// Clear any previous creator/details
|
|
308
291
|
const existing = this.elements!.contentEl.querySelector('ibgib-keystone-creator');
|
|
309
292
|
if (existing) { existing.remove(); }
|
|
310
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 = '';
|
|
311
302
|
this.elements!.contentEl.appendChild(creator as any);
|
|
312
303
|
devLog(`${lc} Mounted ibgib-keystone-creator successfully.`);
|
|
313
304
|
} else {
|
|
@@ -315,79 +306,13 @@ export class IdentityManagerComponentInstance
|
|
|
315
306
|
}
|
|
316
307
|
} catch (error) {
|
|
317
308
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
318
|
-
this.setVerificationStatus(`Failed to load creator: ${extractErrorMsg(error)}`, "error");
|
|
319
309
|
}
|
|
320
310
|
}
|
|
321
311
|
|
|
322
|
-
protected async handleVerifyIdentityChain() {
|
|
323
|
-
const lc = `${this.lc}[${this.handleVerifyIdentityChain.name}]`;
|
|
324
|
-
devLog(`${lc} Verifying identity keystone timeline...`);
|
|
325
|
-
this.setVerificationStatus("Verification request sent...", "info");
|
|
326
|
-
try {
|
|
327
|
-
// Skeleton logic placeholder
|
|
328
|
-
this.setVerificationStatus("Verification complete. Root Keystone is verified (Genesis phase 1).", "success");
|
|
329
|
-
} catch (error) {
|
|
330
|
-
this.setVerificationStatus(`Verification failed: ${extractErrorMsg(error)}`, "error");
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// leave this in
|
|
335
|
-
// protected async handleSyncIdentity() {
|
|
336
|
-
// const lc = `${this.lc}[${this.handleSyncIdentity.name}]`;
|
|
337
|
-
// devLog(`${lc} Starting Peer-to-Peer sync saga...`);
|
|
338
|
-
// this.setVerificationStatus("Starting synchronization session...", "info");
|
|
339
|
-
// }
|
|
340
|
-
|
|
341
|
-
// leave this in
|
|
342
|
-
// protected async handleAddReplicaSpace() {
|
|
343
|
-
// const lc = `${this.lc}[${this.handleAddReplicaSpace.name}]`;
|
|
344
|
-
// const url = this.elements!.inputReplicaUrlEl.value;
|
|
345
|
-
// if (!url) {
|
|
346
|
-
// this.setVerificationStatus("Please enter a valid space replication URL.", "error");
|
|
347
|
-
// return;
|
|
348
|
-
// }
|
|
349
|
-
// devLog(`${lc} Registering replica space: ${url}`);
|
|
350
|
-
|
|
351
|
-
// // Add to UI list for verification
|
|
352
|
-
// const replicaItem = document.createElement('div');
|
|
353
|
-
// replicaItem.className = 'address-code';
|
|
354
|
-
// replicaItem.style.marginTop = '0.5rem';
|
|
355
|
-
// replicaItem.textContent = url;
|
|
356
|
-
// this.elements!.replicasListEl.appendChild(replicaItem);
|
|
357
|
-
|
|
358
|
-
// this.elements!.inputReplicaUrlEl.value = '';
|
|
359
|
-
// this.setVerificationStatus(`Registered replica endpoint: ${url}`, "success");
|
|
360
|
-
// }
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* dispatches the event to set {@link activeAddr} (if truthy) as the active
|
|
364
|
-
* identity. IOW, this "logs it in".
|
|
365
|
-
*/
|
|
366
|
-
protected async handleSetActiveIdentity() {
|
|
367
|
-
if (!this.activeAddr) { return; }
|
|
368
|
-
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
|
|
369
|
-
detail: { activeIdentityAddr: this.activeAddr },
|
|
370
|
-
bubbles: true,
|
|
371
|
-
composed: true
|
|
372
|
-
}));
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
private setVerificationStatus(msg: string, type: 'info' | 'success' | 'error') {
|
|
376
|
-
const statusEl = this.elements!.verificationStatusEl;
|
|
377
|
-
statusEl.textContent = msg;
|
|
378
|
-
statusEl.className = `status-msg ${type}`;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
private async viewIdentityDetails(addr: string): Promise<void> {
|
|
382
|
-
this.activeAddr = addr;
|
|
383
|
-
await this.renderUI();
|
|
384
|
-
}
|
|
385
|
-
|
|
386
312
|
private async resolveActiveIdentity() {
|
|
387
313
|
const lc = `${this.lc}[resolveActiveIdentity]`;
|
|
388
314
|
try {
|
|
389
315
|
if (!this.settings) {
|
|
390
|
-
this.activeAddr = null;
|
|
391
316
|
this.globalActiveAddr = null;
|
|
392
317
|
return;
|
|
393
318
|
}
|
|
@@ -398,17 +323,22 @@ export class IdentityManagerComponentInstance
|
|
|
398
323
|
const activeAddrInSettings = (generalSettings as any)?.activeIdentityAddr;
|
|
399
324
|
|
|
400
325
|
const registeredKeystones = this.ibGib?.rel8ns?.keystone ?? [];
|
|
401
|
-
|
|
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)) {
|
|
402
336
|
this.globalActiveAddr = activeAddrInSettings;
|
|
403
|
-
} else if (
|
|
404
|
-
this.globalActiveAddr =
|
|
337
|
+
} else if (primaryKeystones.length > 0) {
|
|
338
|
+
this.globalActiveAddr = primaryKeystones[0];
|
|
405
339
|
} else {
|
|
406
340
|
this.globalActiveAddr = null;
|
|
407
341
|
}
|
|
408
|
-
|
|
409
|
-
if (!this.activeAddr) {
|
|
410
|
-
this.activeAddr = this.globalActiveAddr;
|
|
411
|
-
}
|
|
412
342
|
} catch (error) {
|
|
413
343
|
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
414
344
|
this.globalActiveAddr = null;
|
|
@@ -419,349 +349,291 @@ export class IdentityManagerComponentInstance
|
|
|
419
349
|
const lc = `${this.lc}[${this.renderUI.name}]`;
|
|
420
350
|
if (!this.elements) { return; }
|
|
421
351
|
|
|
422
|
-
// always resolve the current active identity, even if we aren't
|
|
423
|
-
// necessarily rendering the details for that identity (if it isn't
|
|
424
|
-
// this.activeAddr)
|
|
425
352
|
await this.resolveActiveIdentity();
|
|
426
353
|
|
|
427
354
|
const keystones = this.ibGib?.rel8ns?.keystone ?? [];
|
|
428
|
-
|
|
429
|
-
if (keystones.length === 0) {
|
|
430
|
-
this.elements.tabsListEl.innerHTML = '';
|
|
355
|
+
if (keystones.length === 0 && this.childInfos.length === 0) {
|
|
431
356
|
this.elements.noIdentityPlaceholderEl.classList.remove('hidden');
|
|
432
|
-
this.elements.
|
|
433
|
-
|
|
434
|
-
const existing = this.elements.contentEl.querySelector('ibgib-keystone-creator');
|
|
435
|
-
if (existing && !this.elements.noIdentityPlaceholderEl.classList.contains('hidden')) {
|
|
436
|
-
existing.remove();
|
|
437
|
-
}
|
|
438
|
-
return; /* <<<< returns early */
|
|
357
|
+
this.elements.contentEl.innerHTML = '';
|
|
358
|
+
return;
|
|
439
359
|
}
|
|
440
360
|
|
|
441
361
|
this.elements.noIdentityPlaceholderEl.classList.add('hidden');
|
|
442
362
|
|
|
443
|
-
// Render
|
|
444
|
-
this.
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
// Initial fallback label and tooltip
|
|
450
|
-
let displayTab = addr;
|
|
451
|
-
if (displayTab.length > 12) {
|
|
452
|
-
displayTab = displayTab.substring(0, 5) + '...' + displayTab.substring(displayTab.length - 4);
|
|
453
|
-
}
|
|
454
|
-
tabEl.textContent = displayTab;
|
|
455
|
-
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
|
+
}
|
|
456
369
|
|
|
457
|
-
|
|
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 => {
|
|
458
377
|
const details = await this.getKeystoneDetails(addr);
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
tabEl.textContent = name;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
const tooltipParts: string[] = [];
|
|
469
|
-
if (details.username) {
|
|
470
|
-
tooltipParts.push(`User: ${details.username}`);
|
|
471
|
-
}
|
|
472
|
-
if (details.description) {
|
|
473
|
-
const desc = details.description.length > 100
|
|
474
|
-
? details.description.substring(0, 97) + '...'
|
|
475
|
-
: details.description;
|
|
476
|
-
tooltipParts.push(`Desc: ${desc}`);
|
|
477
|
-
}
|
|
478
|
-
tooltipParts.push(`Addr: ${addr}`);
|
|
479
|
-
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);
|
|
480
384
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
this.elements.tabsListEl.appendChild(tabEl);
|
|
385
|
+
if (primaryKeystones.length === 0) {
|
|
386
|
+
this.elements!.noIdentityPlaceholderEl.classList.remove('hidden');
|
|
387
|
+
return;
|
|
485
388
|
}
|
|
486
389
|
|
|
487
|
-
|
|
488
|
-
const existing = this.elements.contentEl.querySelector('ibgib-keystone-creator');
|
|
489
|
-
if (existing) { existing.remove(); }
|
|
490
|
-
|
|
491
|
-
this.elements.identityDetailsViewEl.classList.remove('hidden');
|
|
492
|
-
|
|
493
|
-
// Update Set Active button state
|
|
494
|
-
if (this.activeAddr === this.globalActiveAddr) {
|
|
495
|
-
this.elements.btnSetActiveEl.disabled = true;
|
|
496
|
-
this.elements.btnSetActiveEl.textContent = "Active Identity";
|
|
497
|
-
this.elements.btnSetActiveEl.classList.add('active-primary');
|
|
498
|
-
} else {
|
|
499
|
-
this.elements.btnSetActiveEl.disabled = false;
|
|
500
|
-
this.elements.btnSetActiveEl.textContent = "Set as Active Identity";
|
|
501
|
-
this.elements.btnSetActiveEl.classList.remove('active-primary');
|
|
502
|
-
}
|
|
390
|
+
this.elements!.noIdentityPlaceholderEl.classList.add('hidden');
|
|
503
391
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
392
|
+
this.reloadingTabs = true;
|
|
393
|
+
try {
|
|
394
|
+
for (const addr of primaryKeystones) {
|
|
395
|
+
await this.activateIbGib({ addr });
|
|
507
396
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
} else {
|
|
511
|
-
this.elements.identityDetailsViewEl.classList.add('hidden');
|
|
512
|
-
this.clearActiveDetails();
|
|
397
|
+
} finally {
|
|
398
|
+
this.reloadingTabs = false;
|
|
513
399
|
}
|
|
514
|
-
}
|
|
515
400
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
this.
|
|
521
|
-
this.elements.identityNameEl.textContent = '-';
|
|
522
|
-
this.elements.identityDescriptionEl.textContent = '-';
|
|
523
|
-
this.elements.identityFrameDetailsEl.textContent = '{}';
|
|
524
|
-
this.elements.identityAggrDetailsEl.textContent = '{}';
|
|
525
|
-
this.elements.scrubberStatusEl.textContent = 'Frame - / -';
|
|
526
|
-
this.elements.poolsContainerEl.innerHTML = '';
|
|
527
|
-
this.history = [];
|
|
528
|
-
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 });
|
|
529
406
|
}
|
|
530
407
|
|
|
531
|
-
|
|
532
|
-
const lc = `${this.lc}[
|
|
533
|
-
|
|
534
|
-
|
|
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)`); }
|
|
535
412
|
|
|
536
|
-
|
|
537
|
-
if (!metaspace) return;
|
|
538
|
-
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
539
|
-
if (!space) return;
|
|
413
|
+
await super.activateIbGib({ addr, ibGib });
|
|
540
414
|
|
|
541
|
-
let currentAddr: string | undefined = tipAddr;
|
|
542
|
-
const tempHistory: KeystoneIbGib_V1[] = [];
|
|
543
415
|
|
|
544
|
-
|
|
545
|
-
const res = await metaspace.get({ addr: currentAddr, space });
|
|
546
|
-
if (!res.success || !res.ibGibs || res.ibGibs.length === 0) {
|
|
547
|
-
console.warn(`${lc} Could not find frame at ${currentAddr}`);
|
|
548
|
-
break;
|
|
549
|
-
}
|
|
550
|
-
const keystone = res.ibGibs[0] as KeystoneIbGib_V1;
|
|
551
|
-
tempHistory.push(keystone);
|
|
416
|
+
if (!this.activeChildInfo) { throw new Error(`(UNEXPECTED) activeChildInfo falsy after activateIbGib? (E: d76bd8bc300f3fdc486d50c8b2644826)`); }
|
|
552
417
|
|
|
553
|
-
|
|
554
|
-
break;
|
|
555
|
-
}
|
|
418
|
+
ibGib ??= this.activeChildInfo.component?.ibGib;
|
|
556
419
|
|
|
557
|
-
|
|
558
|
-
currentAddr = (past && past.length > 0) ? past[past.length - 1] : undefined;
|
|
559
|
-
}
|
|
420
|
+
if (!ibGib) { throw new Error(`(UNEXPECTED) ibGib falsy? (E: 5b6ec745dd32fd2128635728e3f35e26)`); }
|
|
560
421
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
private scrubTo(index: number) {
|
|
566
|
-
if (this.history.length === 0) return;
|
|
567
|
-
this.currentFrameIndex = Math.max(0, Math.min(index, this.history.length - 1));
|
|
568
|
-
this.updateFrameDetailsView();
|
|
569
|
-
}
|
|
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
|
+
}
|
|
570
425
|
|
|
571
|
-
|
|
572
|
-
this.scrubTo(0);
|
|
573
|
-
}
|
|
426
|
+
this.elements!.noIdentityPlaceholderEl.classList.add('hidden');
|
|
574
427
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
+
}
|
|
578
468
|
|
|
579
|
-
|
|
580
|
-
|
|
469
|
+
await this.renderUI();
|
|
470
|
+
} catch (error) {
|
|
471
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
472
|
+
}
|
|
581
473
|
}
|
|
582
474
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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;
|
|
501
|
+
}
|
|
586
502
|
|
|
587
|
-
|
|
588
|
-
this.scrubTo(this.currentFrameIndex + 10);
|
|
589
|
-
}
|
|
503
|
+
let tabInfo: IdentityTabInfo;
|
|
590
504
|
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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
|
+
});
|
|
594
510
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
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();
|
|
516
|
+
}
|
|
517
|
+
} else {
|
|
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);
|
|
538
|
+
}
|
|
598
539
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
540
|
+
return tabInfo;
|
|
541
|
+
} catch (error) {
|
|
542
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
543
|
+
throw error;
|
|
602
544
|
}
|
|
545
|
+
}
|
|
603
546
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
if (timestampStr) {
|
|
617
|
-
const parsed = parseInt(timestampStr);
|
|
618
|
-
if (!isNaN(parsed)) {
|
|
619
|
-
formattedTimestamp = new Date(parsed).toLocaleString();
|
|
620
|
-
} else {
|
|
621
|
-
formattedTimestamp = new Date(timestampStr).toLocaleString();
|
|
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}`);
|
|
622
559
|
}
|
|
623
|
-
|
|
624
|
-
|
|
560
|
+
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy?`); }
|
|
561
|
+
const { tabsListEl } = this.elements;
|
|
625
562
|
|
|
626
|
-
|
|
627
|
-
this.elements.identityUuidEl.textContent = keystone.data?.uuid || 'N/A';
|
|
563
|
+
addr ??= getIbGibAddr({ ibGib });
|
|
628
564
|
|
|
629
|
-
|
|
630
|
-
|
|
565
|
+
const childBtnEl = document.createElement('button');
|
|
566
|
+
childBtnEl.className = 'tab-btn';
|
|
567
|
+
childBtnEl.id = `identity-tab-button-${addr}`;
|
|
631
568
|
|
|
632
|
-
|
|
633
|
-
this.elements.btnScrubFirstEl.disabled = this.currentFrameIndex === 0;
|
|
634
|
-
this.elements.btnScrubPrev10El.disabled = this.currentFrameIndex === 0;
|
|
635
|
-
this.elements.btnScrubPrevEl.disabled = this.currentFrameIndex === 0;
|
|
636
|
-
this.elements.btnScrubNextEl.disabled = this.currentFrameIndex === this.history.length - 1;
|
|
637
|
-
this.elements.btnScrubNext10El.disabled = this.currentFrameIndex === this.history.length - 1;
|
|
638
|
-
this.elements.btnScrubLatestEl.disabled = this.currentFrameIndex === this.history.length - 1;
|
|
569
|
+
await this.updateTabTitleAndText({ span: childBtnEl, ibGib, addr });
|
|
639
570
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
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
|
+
}
|
|
643
584
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if (space) {
|
|
649
|
-
try {
|
|
650
|
-
const keystoneSvc = new KeystoneService_V1();
|
|
651
|
-
const aggregated = await keystoneSvc.getAggregateDetails({
|
|
652
|
-
latestKeystone: keystone,
|
|
653
|
-
metaspace,
|
|
654
|
-
space
|
|
655
|
-
});
|
|
585
|
+
tabsListEl.appendChild(childBtnEl);
|
|
586
|
+
childBtnEl.addEventListener('click', async (event) => {
|
|
587
|
+
await this.activateIbGib({ addr });
|
|
588
|
+
});
|
|
656
589
|
|
|
657
|
-
|
|
590
|
+
return childBtnEl;
|
|
591
|
+
} catch (error) {
|
|
592
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
658
596
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
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) + '...';
|
|
672
612
|
}
|
|
613
|
+
span.textContent = name;
|
|
673
614
|
} else {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
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;
|
|
677
620
|
}
|
|
678
621
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
// Render Challenge Pools
|
|
683
|
-
this.renderChallengePools(keystone.data?.challengePools || []);
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
private renderChallengePools(pools: any[]) {
|
|
687
|
-
if (!this.elements) return;
|
|
688
|
-
const container = this.elements.poolsContainerEl;
|
|
689
|
-
container.innerHTML = '';
|
|
690
|
-
|
|
691
|
-
if (!pools || pools.length === 0) {
|
|
692
|
-
container.innerHTML = `<p class="description">No challenge pools found in this keystone.</p>`;
|
|
693
|
-
return;
|
|
622
|
+
const tooltipParts: string[] = [];
|
|
623
|
+
if (details.username) {
|
|
624
|
+
tooltipParts.push(`User: ${details.username}`);
|
|
694
625
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
const config = pool.config || {};
|
|
701
|
-
const behavior = config.behavior || {};
|
|
702
|
-
const allowedVerbs = config.allowedVerbs || [];
|
|
703
|
-
const activeCount = pool.challenges ? Object.keys(pool.challenges).length : 0;
|
|
704
|
-
const isForeign = !!pool.isForeign;
|
|
705
|
-
|
|
706
|
-
// Generate HTML for the challenges list
|
|
707
|
-
const challenges = pool.challenges || {};
|
|
708
|
-
const challengeListHtml = Object.entries(challenges).map(([id, challenge]: [string, any]) => {
|
|
709
|
-
const truncatedHash = challenge.hash && challenge.hash.length > 20
|
|
710
|
-
? challenge.hash.substring(0, 10) + '...' + challenge.hash.substring(challenge.hash.length - 8)
|
|
711
|
-
: challenge.hash || 'N/A';
|
|
712
|
-
return `
|
|
713
|
-
<div class="pool-challenge-item">
|
|
714
|
-
<span class="challenge-id">${id}</span>
|
|
715
|
-
<span class="challenge-hash" title="${challenge.hash || ''}">${truncatedHash}</span>
|
|
716
|
-
</div>
|
|
717
|
-
`;
|
|
718
|
-
}).join('');
|
|
719
|
-
|
|
720
|
-
card.innerHTML = `
|
|
721
|
-
<div class="pool-header">
|
|
722
|
-
<span class="pool-title">${pool.id || 'Unnamed Pool'}</span>
|
|
723
|
-
<span class="pool-tag ${isForeign ? 'foreign' : 'native'}">${isForeign ? 'Foreign' : 'Native'}</span>
|
|
724
|
-
</div>
|
|
725
|
-
<div class="pool-grid">
|
|
726
|
-
<div class="pool-field">
|
|
727
|
-
<label>Challenge Type</label>
|
|
728
|
-
<span>${config.type || 'N/A'}</span>
|
|
729
|
-
</div>
|
|
730
|
-
<div class="pool-field">
|
|
731
|
-
<label>Target Size</label>
|
|
732
|
-
<span>${behavior.size ?? 'N/A'}</span>
|
|
733
|
-
</div>
|
|
734
|
-
<div class="pool-field">
|
|
735
|
-
<label>Active Challenges</label>
|
|
736
|
-
<span>${activeCount}</span>
|
|
737
|
-
</div>
|
|
738
|
-
<div class="pool-field">
|
|
739
|
-
<label>Replenish Strategy</label>
|
|
740
|
-
<span>${behavior.replenish || 'N/A'}</span>
|
|
741
|
-
</div>
|
|
742
|
-
<div class="pool-field">
|
|
743
|
-
<label>Allowed Verbs</label>
|
|
744
|
-
<span>${allowedVerbs.length > 0 ? allowedVerbs.join(', ') : 'Any'}</span>
|
|
745
|
-
</div>
|
|
746
|
-
<div class="pool-field">
|
|
747
|
-
<label>FIFO / Random cost</label>
|
|
748
|
-
<span>FIFO: ${behavior.selectSequentially ?? 0}, Rand: ${behavior.selectRandomly ?? 0}</span>
|
|
749
|
-
</div>
|
|
750
|
-
</div>
|
|
751
|
-
|
|
752
|
-
<!-- Collapsible Challenges List -->
|
|
753
|
-
<details class="pool-details">
|
|
754
|
-
<summary class="pool-details-summary">Challenges (${activeCount})</summary>
|
|
755
|
-
<div class="pool-challenges-list">
|
|
756
|
-
${challengeListHtml || '<p class="placeholder-text" style="padding: 0.5rem; text-align: center;">No challenges active.</p>'}
|
|
757
|
-
</div>
|
|
758
|
-
</details>
|
|
759
|
-
`;
|
|
760
|
-
container.appendChild(card);
|
|
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}`);
|
|
761
631
|
}
|
|
632
|
+
tooltipParts.push(`Addr: ${addr}`);
|
|
633
|
+
span.title = tooltipParts.join('\n');
|
|
762
634
|
}
|
|
763
635
|
|
|
764
|
-
|
|
765
|
-
|
|
636
|
+
protected async removeTabBtn({ tabInfo }: { tabInfo: IdentityTabInfo }): Promise<void> {
|
|
637
|
+
this.elements!.tabsListEl.removeChild(tabInfo.childBtnEl);
|
|
766
638
|
}
|
|
767
639
|
}
|