import thisHtml from './project.html';
import thisCss from './project.css';
import stylesCss from '../../../styles.css';
import rootCss from '../../../root.css';
import { clone, delay, extractErrorMsg, getSaferSubstring, getTimestampInTicks, pretty, } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
import { IbGibAddr, TjpIbGibAddr, } from "@ibgib/ts-gib/dist/types.mjs";
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
import { getGibInfo, isPrimitive } from "@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs";
import { getIbAndGib, getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
import { MetaspaceService } from "@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs";
import { createCommentIbGib } from "@ibgib/core-gib/dist/common/comment/comment-helper.mjs";
import { getTjpAddr } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
import { fnObs } from "@ibgib/core-gib/dist/common/pubsub/observer/observer-helper.mjs";
import { IbGibTimelineUpdateInfo } from "@ibgib/core-gib/dist/common/other/other-types.mjs";
import { appendToTimeline, mut8Timeline } from "@ibgib/core-gib/dist/timeline/timeline-api.mjs";
import {
getDeterministicColorInfo, getGlobalMetaspace_waitIfNeeded,
} from "@ibgib/web-gib/dist/helpers.mjs";
import {
IbGibDynamicComponentInstanceBase, IbGibDynamicComponentMetaBase,
IbGibDynamicComponentInstanceBase_ParentOfTabs,
} from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
import {
ElementsBase, ChildInfoBase, IbGibDynamicComponentInstance,
IbGibDynamicComponentInstanceInitOpts,
} from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";
import { getColorStrings, } from "@ibgib/web-gib/dist/helpers.mjs";
import {
alertUser, copyToClipboard, highlightElement, promptForText,
shadowRoot_getElementById,
} from "@ibgib/web-gib/dist/helpers.web.mjs";
import { askForPersistStorage, } from "@ibgib/web-gib/dist/storage/storage-helpers.web.mjs";
import { LensMode, ProjectIbGib_V1 } from "@ibgib/web-gib/dist/common/project/project-types.mjs";
import { isProjectIbGib_V1 } from "@ibgib/web-gib/dist/common/project/project-helper.mjs";
import { PROJECT_CHILD_TEXT_REL8N_NAME, } from "@ibgib/web-gib/dist/common/project/project-constants.mjs";
import {
AGENT_AVAILABLE_FUNCTIONS_PROJECTAGENT,
AGENT_AVAILABLE_FUNCTIONS_PROJECTCHILDTEXTAGENT,
} from "@ibgib/web-gib/dist/common/project/project-agent-functions.mjs";
import { getAgentsSvc } from "@ibgib/web-gib/dist/witness/agent/agents-service-v1.mjs";
import { GEMINI_DEFAULT_MODEL_STR, } from "@ibgib/web-gib/dist/witness/agent/gemini/gemini-constants.mjs";
import { registerDomainIbGibWithAgentIndex } from "@ibgib/web-gib/dist/witness/agent/agent-helpers.mjs";
import { Settings_General, Settings_Project, } from "@ibgib/web-gib/dist/common/settings/settings-types.mjs";
import { getSectionName, } from "@ibgib/web-gib/dist/common/settings/settings-helpers.mjs";
import { SettingsType } from "@ibgib/web-gib/dist/common/settings/settings-constants.mjs";
import { GLOBAL_LOG_A_LOT, } from "../../../constants.mjs";
import {
getComponentCtorArg,
getDefaultFnGetAPIKey,
getIbGibGlobalThis_BlankGib, getIbGibGlobalThis_Common,
} from "../../../helpers.web.mjs";
import { RAW_COMPONENT_NAME, RawComponentInstance } from "../../common/raw/raw-component-one-file.mjs";
import { TEXTEDITOR_COMPONENT_NAME, TextEditorComponentInstance } from "../../common/text-editor/text-editor-component-one-file.mjs";
import { AGENT_INITIAL_CHAT_TEXT_PROJECTCHILDTEXTAGENT, AGENT_INITIAL_SYSTEM_TEXT_PROJECTCHILDTEXTAGENT, AGENT_SPECIAL_IBGIB_TYPE_PROJECTCHILDTEXTAGENT } from "../../../agent-texts/project-child-text-agent-texts.mjs";
import { isMinigameIbGib_V1 } from "../../../common/minigame/minigame-helper.mjs";
import { MINIGAME_COMPONENT_NAME } from "../../minigame/minigame-component-one-file.mjs";
import { minigameBuilderStartFunctionInfo, MinigameBuilderStartResult } from "../../../api/commands/minigame/minigame-builder-start.mjs";
const logalot = GLOBAL_LOG_A_LOT;
export const PROJECT_COMPONENT_NAME: string = 'ibgib-project';
export class ProjectComponentMeta extends IbGibDynamicComponentMetaBase {
protected override lc: string = `[${ProjectComponentMeta.name}]`;
/**
* temporary regexp path for our initial dev. this component will become
* attached to actual ib^gib addrs
*/
// routeRegExp?: RegExp = new RegExp(PROJECT_COMPONENT_NAME);
routeRegExp?: RegExp = new RegExp(`^${PROJECT_COMPONENT_NAME}$`);
// routeRegExp?: RegExp = /apps\/web1\/gib\/contact.html/;
componentName: string = PROJECT_COMPONENT_NAME;
constructor() {
super(getComponentCtorArg());
customElements.define(this.componentName, ProjectComponentInstance);
}
/**
* for a project, we don't have any additional info in the path.
*/
async createInstance({
path,
ibGibAddr
}: {
path: string;
ibGibAddr: IbGibAddr;
}): Promise {
const lc = `${this.lc}[${this.createInstance.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
const component = document.createElement(this.componentName) as ProjectComponentInstance;
await component.initialize({
ibGibAddr,
meta: this,
html: thisHtml,
css: [rootCss, stylesCss, thisCss],
});
return component;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
}
interface ProjectElements extends ElementsBase {
headerEl: HTMLElement;
headerTabsEl: HTMLElement | undefined;
// nameEl: HTMLHeadingElement;
// descEl: HTMLParagraphElement;
footerEl: HTMLElement;
lensBarEl: HTMLElement;
rawLensBtnEl: HTMLButtonElement;
textLensBtnEl: HTMLButtonElement;
minigameLensBtnEl: HTMLButtonElement;
addBtnEl: HTMLElement | undefined;
addPopoverEl: HTMLElement | undefined;
ellipsisBtnEl: HTMLElement | undefined;
ellipsisPopoverEl: HTMLElement | undefined;
}
export type ProjectChildComponentInstance = RawComponentInstance | TextEditorComponentInstance;
/**
* A project's children are ibgibs
*/
export interface ProjectChildTabInfo
extends ChildInfoBase> {
componentCache: { [lensMode: string]: ProjectChildComponentInstance }
}
export class ProjectComponentInstance
extends IbGibDynamicComponentInstanceBase_ParentOfTabs
implements IbGibDynamicComponentInstance {
protected override lc: string = `[${ProjectComponentInstance.name}]`;
metaspace: MetaspaceService | undefined;
protected get settingsType(): SettingsType {
return SettingsType.project;
}
// private _reloadingTabs = false;
/**
* using this as a temporary hack to decide which concrete component to view
* the child ibgib with.
*/
private _lensMode: LensMode = LensMode.raw;
get lensMode(): LensMode { return this._lensMode; }
constructor() {
super();
}
public override async activateIbGib({ addr, ibGib, }: { addr?: IbGibAddr; ibGib?: IbGib_V1; }): Promise {
const lc = `${this.lc}[${this.activateIbGib.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 9b05f2064bc86002d8399af9e6e15825)`); }
if (!addr && !ibGib) { throw new Error(`(UNEXPECTED) both addr and ibGib falsy? either addr or ibGib required. (E: 1762be0d11e851dbc8d639882671c825)`); }
addr ??= getIbGibAddr({ ibGib });
await super.activateIbGib({ addr, ibGib });
// check the current settings. add the ibGib's tjpAddr to
// the project settings list of open child tjp addrs if it's not
// there already.
// let projectSettings: Settings_Project | undefined = await this.getCurrentProjectSettings();
const settings_current = await this.getSettings({
settingsType: this.settingsType,
useCase: 'current',
});
if (!settings_current) {
throw new Error(`(UNEXPECTED) couldn't get current settings? i thought this would initialized by now. (E: 065648bc2c58dfa25d58796bed6a8e25)`);
}
const metaspace = await getGlobalMetaspace_waitIfNeeded();
if (!ibGib) {
const resGet = await metaspace.get({ addrs: [addr], });
if (!resGet || resGet.errorMsg || (resGet.ibGibs ?? []).length !== 1) {
throw new Error(`couldn't get addr (${addr}) from default local user space. wrong space? i need to figure out how I want the project space handled still (atow 06/2025) (E: 37dc4cb82971bce8652bb934bd757825)`);
}
ibGib = resGet.ibGibs![0];
}
const tjpAddr = getTjpAddr({ ibGib, defaultIfNone: 'incomingAddr' });
if (!tjpAddr) { throw new Error(`(UNEXPECTED) tjpAddr falsy? 'incomingAddr' was used as the default option. (E: d42478a570da8ccc1804ea58fc5f4825)`); }
if (this._reloadingTabs) {
// we are loading the current child ibgib tabs and we shouldn't
// do any updating tothe settings
console.log(`${lc} just loading ibgib, so nothing further to do here. returning early (I: a856887a5858e6d7efc297c80e2d0825)`)
return; /* <<<< returns early */
} else {
// we are NOT loading and we should persist this change to
// settings
let modified = false;
if (!settings_current.openChildTjpAddrs.includes(tjpAddr)) {
settings_current.openChildTjpAddrs.push(tjpAddr);
modified = true;
}
if (settings_current.activeChildTjpAddr !== tjpAddr) {
settings_current.activeChildTjpAddr = tjpAddr;
modified = true;
}
if (modified) {
const sectionName_current = await getSectionName({
settingsType: this.settingsType,
useCase: 'current',
});
const _newSettings = await mut8Timeline({
timeline: this.settings!.ibGib!,
metaspace,
mut8Opts: {
dataToAddOrPatch: {
sections: {
[sectionName_current]: settings_current,
}
},
},
});
} else {
console.warn(`${lc} already activated? should this get this far if we're clicking a tab that's already activated? (W: 4c6d98e8809813a4f8a2075b113cb325)`)
}
}
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected async createAndLoadChildComponent({
addr,
}: {
addr: IbGibAddr,
}): Promise {
const lc = `${this.lc}[${this.createAndLoadChildComponent.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: a080988fa988782fe898352a3a0aa825)`); }
const componentSvc = await getComponentSvc();
let componentPath: string;
// hack to fix this last bug. take this out
// if (this.lensMode === LensMode.minigame) {
// await this.activateLensMode({ lensMode: 'raw', skipInject: true });
// }
// hack while dev to force injecting minigame component when
// activating a minigame ibgib.
let useLensMode = this.lensMode;
// if (addr.split(' ').at(0)! === MINIGAME_ATOM) {
// useLensMode = LensMode.minigame;
// }
switch (useLensMode) {
case LensMode.raw:
componentPath = RAW_COMPONENT_NAME; break;
case LensMode.text:
componentPath = TEXTEDITOR_COMPONENT_NAME; break;
case LensMode.minigame:
componentPath = MINIGAME_COMPONENT_NAME; break;
default:
throw new Error(`(UNEXPECTED) unknown lensMode (${this.lensMode})? (E: b2b8895cee48fea7c18c225d7e2b3825)`);
}
const component = await componentSvc.getComponentInstance({
path: componentPath,
ibGibAddr: addr,
useRegExpPrefilter: true,
}) as ProjectChildComponentInstance | undefined;
if (!component) {
debugger; // error couldn't create component instance for project?
throw new Error(`(UNEXPECTED) projectComponent falsy? couldn't create component instance for project? (E: efeee6b003f5b0af9b0fda679593c725)`);
}
// await projectComponent.loadIbGib();
// await projectComponent.initialized;
if (!component.ibGib) {
debugger; // error couldn't load ibGib for project?
throw new Error(`(UNEXPECTED) ibGib falsy? couldn't load ibGib for project? (E: 352f152063a97e67f769babfadfe1e25)`);
}
// if (component.agent) {
// this.loadAgentsCoupledToIbGib({dontThrowIfNone: true});
// }
// guaranteed loaded ibGib
return component;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* @internal
* gets the project tab info for the given addr.
*
* creates and loads the project ibgib component, which itself loads the
* ibgib internally (or throws) if not already loaded.
*
* @returns ProjectTabInfo with fully loaded component and ibgib.
*
* @see {@link ProjectChildTabInfo}
*/
protected async getLoadedChildInfo({
addr,
ibGib,
}: {
addr: IbGibAddr,
ibGib?: IbGib_V1,
}): Promise {
const lc = `${this.lc}[${this.getLoadedChildInfo.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 8bc42ecb105f4ca9dff6590c1a9c2f25)`); }
if (!addr) { throw new Error(`(UNEXPECTED) addr falsy? (E: 25e89572d09ae8dd581ba60bde1c9825)`); }
const tjpGib = getGibInfo({ ibGibAddr: addr }).tjpGib ?? getIbAndGib({ ibGibAddr: addr }).gib;
/** the point of this function is to populate this */
let tabInfo: ProjectChildTabInfo;
/**
* filtered for same timeline of addr via tjpGib
*/
const filtered = this.childInfos.filter(x => {
const tabGibInfo = getGibInfo({ ibGibAddr: x.addr });
const tabTjpGib = tabGibInfo.tjpGib ?? getIbAndGib({ ibGibAddr: x.addr }).gib;
return tabTjpGib === tjpGib;
});
if (filtered.length > 0) {
// already have an existing tab, but maybe not component for the current lens mode
if (filtered.length !== 1) { console.error(`(UNEXPECTED) filtered.length !== 1? logging error here but we're just going to use the first one. filtered addrs:\n${filtered.map(x => x.addr).join('\n')}(E: ef126a918a93f1c13d0c4b41d5194b25)`); }
tabInfo = filtered[0];
let component = tabInfo.componentCache[this.lensMode];
if (!component) {
component = await this.createAndLoadChildComponent({ addr });
tabInfo.componentCache[this.lensMode] = component;
}
tabInfo.component = component;
} else {
// no existing tab, so create new project tab info
// const component = await fnCreateAndLoadProjectComponent();
const component = await this.createAndLoadChildComponent({ addr });
ibGib = component.ibGib!; // guaranteed in above fn
// both addr and ibGib guaranteed now creating the child
// component could have gotten the latest ibgib which would make
// the addr be different than the ibGib's addr proper. so put
// these back in sync
addr = getIbGibAddr({ ibGib });
const tabBtnEl = await this.addChild({ addr, ibGib });
tabInfo = {
addr,
childBtnEl: tabBtnEl,
component,
active: false,
componentCache: { [this.lensMode]: component }
};
this.childInfos.push(tabInfo);
}
return tabInfo;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private updateTabTitleAndText({
span,
ibGib,
}: {
span: HTMLElement,
ibGib: IbGib_V1,
}): void {
const lc = `[${this.updateTabTitleAndText.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: d1c34e159aecc0bf06f57a759b06a625)`); }
if (!ibGib.data) { throw new Error(`(UNEXPECTED) ibGib.data falsy? (E: a22dd936f38a779c0d61489c7d7c9125)`); }
if (!ibGib.data.name) { console.warn(`${lc} ibGib.data.name falsy? (W: genuuid)`); }
const title = ibGib.data.name ?? 'untitled'
const desc = ibGib.data.description ?? '';
span.title = desc ? `${title}\n${desc}` : title;
const MAX_TAB_TEXT_LENGTH = 12;
const titleText = getSaferSubstring({
text: title, length: MAX_TAB_TEXT_LENGTH,
}) + (title.length > MAX_TAB_TEXT_LENGTH ?
'…' :
'')
const textNode = document.createTextNode(titleText);
// the span has text node child and (usually) a close "button"
// (span). we want to only update the text node.
// (the project tab is different, it has no close button atow
// 06/2025)
if (span.firstChild) {
span.replaceChild(textNode, span.firstChild);
} else {
span.appendChild(textNode);
}
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* creates a new tab element (span atow 03/2025), adds it to the
* headerTabsEl and returns the new span element.
*
* @returns the newly created tab span element
*/
protected override async addChild({
addr,
ibGib,
}: {
ibGib: IbGib_V1,
addr?: IbGibAddr,
}): Promise {
const lc = `${this.lc}[${this.addChild.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: e6657888d2b42cfdef6df03d89f3e625)`); }
// #region init/validate
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: 9f5ad8d5f35ded4496a68ac6b73ac725)`); }
const { headerTabsEl } = this.elements;
if (!headerTabsEl) { throw new Error(`(UNEXPECTED) headerTabsEl falsy? (E: 21e658ececa8a893168598b8837ba825)`); }
addr ??= getIbGibAddr({ ibGib });
if (addr !== getIbGibAddr({ ibGib })) {
throw new Error(`(UNEXPECTED) addr !== getIbGibAddr({ibGib})? (E: 1981efb1b691c154670376934336d125)`);
}
const tjpAddr = getTjpAddr({ ibGib, defaultIfNone: 'incomingAddr' });
if (!tjpAddr) {
debugger; // why is tjpAddr falsy?
}
const { gib: tjpGib } = getIbAndGib({ ibGibAddr: tjpAddr });
// #endregion init/validate
// create the tab button element
const childBtnEl = document.createElement('span');
childBtnEl.id = `project-tab-button-${addr}`;
childBtnEl.classList.add('panel-tab-button');
// if (activate) { span.classList.add('active'); }
this.updateTabTitleAndText({ span: childBtnEl, ibGib });
const {
punctiliarColor,
punctiliarColorTranslucent,
tjpColor,
tjpColorTranslucent,
tjpColorContrast,
errorMsg
} = getDeterministicColorInfo({ ibGib, translucentAlpha: 70 });
if (!errorMsg) {
childBtnEl.style.borderColor = tjpColor ?? punctiliarColor;
childBtnEl.style.backgroundColor = tjpColorTranslucent ?? punctiliarColorTranslucent;
childBtnEl.style.color = tjpColorContrast ?? getColorStrings(90, tjpGib).at(2) ?? 'red'
// this.style.setProperty('--ibgib-color', punctiliarColor);
// this.style.setProperty('--ibgib-color-translucent', punctiliarColor);
// this.style.setProperty('--tjp-color', tjpColor ?? punctiliarColor);
// this.style.setProperty('--tjp-color-translucent', tjpColorTranslucent ?? punctiliarColorTranslucent);
} else {
// don't set anything
console.error(`${lc} ${errorMsg} (E: f837c92aa2876b444707f0b229fb8e25)`);
}
// add a close button to the tab button proper, if the tab is not
// our project tab Project tab is always open atow (06/2025) but
// this is just because I want to always have a tab open right now,
// as it simplifies early dev
if (tjpAddr !== this.tjpAddr) {
const closeBtnEl = document.createElement('span');
closeBtnEl.classList.add('close-tab-button');
closeBtnEl.textContent = '❌'; // or a Font Awesome icon
childBtnEl.appendChild(closeBtnEl);
closeBtnEl.addEventListener('click', async (event) => {
event.stopPropagation(); // Prevent activating the tab
await this.closeTab({ ibGib });
});
}
headerTabsEl.appendChild(childBtnEl);
childBtnEl.addEventListener('click', async (event) => {
await this.activateIbGib({ addr });
});
if (!this.metaspace) { throw new Error(`(UNEXPECTED) this.metaspace falsy? (E: 56ed15004c98e40a95db20144e726825)`); }
if (!this.metaspace.latestObs) { throw new Error(`(UNEXPECTED) this.metaspace.latestObs falsy? (E: bab9882340fcdc29242045e8c2d2fe25)`); }
await this.metaspace.latestObs?.subscribe(fnObs({
next: async (updateInfo: IbGibTimelineUpdateInfo) => {
if (updateInfo.tjpAddr !== tjpAddr) { return; /* <<<< returns early */ }
if (updateInfo.latestIbGib) {
this.updateTabTitleAndText({ span: childBtnEl, ibGib: updateInfo.latestIbGib })
} else {
console.error(`{lc}[next] updateInfo.latestIbGib falsy? (E: a8558bdc53889ee07d8d78178328ae25)`);
}
},
complete: async () => {
console.warn(`${lc}[complete] completed executed? (W: a2df080a4f8ef87df5266888109dfe25)`);
},
error: async (error) => {
debugger; // error in metaspace.latestObs dispatch?
console.error(`${lc}[error] ${extractErrorMsg(error)}`);
},
}));
return childBtnEl;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected async removeTabBtn({ tabInfo, }: { tabInfo: ProjectChildTabInfo; }): Promise {
// throw new Error("Method not implemented.");
this.elements!.headerTabsEl!.removeChild(tabInfo.childBtnEl);
}
override async initialize(opts: IbGibDynamicComponentInstanceInitOpts): Promise {
const lc = `${this.lc}[${this.initialize.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
await super.initialize(opts);
await this.loadIbGib({ getLatest: true });
this.metaspace = await getGlobalMetaspace_waitIfNeeded();
this.agentsInitialized = this.initAgents();
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
override async created(): Promise {
const lc = `${this.lc}[${this.created.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
// const { meta, htmlPath, scriptPaths, cssPaths } = opts;
// at this point, this.ibGib should be loaded with the latest
// project ibgib
if (!this.ibGib) { throw new Error(`(UNEXPECTED) this.ibGib falsy? It is assumed at this point that we have a valid ibGib to work with. (E: 15af5db05175b88a629e52a335625b25)`); }
await this.initElements();
await this.agentsInitialized;
await this.initChronology();
await this.renderUI();
// await this.agent!.witness(ROOT); // don't auto-prompt at this time because during dev it's extremely annoying and stresses out the agents
// seems at random, and it is somewhat arbitrary, but if the user is
// creating a project, then they've used the site enough to possibly
// care enough for persistent storage. should be silent/idempotent
// (not do anything if the user has already persisted)
await askForPersistStorage();
// spin off because created has to finish
// const projectSettings = await this.getCurrentProjectSettings();
const projectSettings = await this.getSettings({
settingsType: SettingsType.project,
useCase: 'current',
});
if ((projectSettings?.openChildTjpAddrs ?? []).length === 0) {
// first run
this.showProjectInfoTab();
} else {
// not first run, so just reopen the old tabs
this.reopenOldTabs();
}
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected override async reopenOldTabs(): Promise {
const lc = `${this.lc}[${this.reopenOldTabs.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 0476d804371846b4087821cc3fdba125)`); }
await super.reopenOldTabs();
const settings = await this.getSettings({
settingsType: 'project',
useCase: 'current'
});
if (!settings) {
console.error(`${lc} couldn't get current project settings? (E: 13447c074422d32088c42c08b1a44a25)`);
return;
}
await this.activateLensMode({ lensMode: settings.lensMode, skipInject: false });
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
// private async reopenOldTabs(): Promise {
// const lc = `${this.lc}[${this.reopenOldTabs.name}]`;
// try {
// if (logalot) { console.log(`${lc} starting... (I: 195e7d34b3f8b761aa78dd384011f825)`); }
// // let projectSettings = await this.getCurrentProjectSettings();
// const projectSettings = await this.getSettings({
// settingsType: SettingsType.project,
// useCase: 'current',
// });
// if (!projectSettings) { throw new Error(`(UNEXPECTED) projectSettings falsy? these should be initialized before now. (E: 2003ab77e01448d638216fc82aff5f25)`); }
// this._reloadingTabs = true;
// let currentChildTjpAddr: IbGibAddr | undefined;
// try {
// for (const childTjpAddr of projectSettings.openChildTjpAddrs) {
// // slow kluge I think...maybe it's ok I dunno.
// currentChildTjpAddr = childTjpAddr;
// await this.activateIbGib({ addr: childTjpAddr });
// }
// } catch (error) {
// console.error(`${lc} error during activating child ibGib tabs. childTjpAddr: ${currentChildTjpAddr ?? '[unset?]'} (E: 0396b2e24d08f42ac94510bb718a1725)`);
// throw error;
// } finally {
// this._reloadingTabs = false;
// }
// // not reloading, so now we can activate the recently active one
// await this.activateIbGib({ addr: projectSettings.activeChildTjpAddr });
// await this.activateLensMode({ lensMode: projectSettings.lensMode, skipInject: false });
// } catch (error) {
// console.error(`${lc} ${extractErrorMsg(error)}`);
// throw error;
// } finally {
// if (logalot) { console.log(`${lc} complete.`); }
// }
// }
/**
* show project info tab tells the project component to load itself, which
* is like a dashboard...in the future, this should actually show a project
* dashboard/status component
*
* atow (05/2025), this will show a ibgib-raw component, the most
* rudimentary of ibgib components.
*/
private async showProjectInfoTab(): Promise {
const lc = `${this.lc}[${this.showProjectInfoTab.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 717c77253cb468d40d37e23d00da9825)`); }
await this.activateIbGib({ ibGib: this.ibGib });
await this.activateLensMode({ lensMode: 'raw', skipInject: false });
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
override async handleContextUpdated(): Promise {
const lc = `${this.lc}[${this.handleContextUpdated.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 1cec5212626b1700aa09c2e3d6966225)`); }
await super.handleContextUpdated();
await this.renderUI();
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected override async handleNewContextChild({
childIbGib,
}: {
childIbGib: IbGib_V1;
}): Promise {
const lc = `${this.lc}[${this.handleNewContextChild.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 118ee1579105ab6bae507272041e4925)`); }
// hack to get the ball rolling with minigames (drills). not sure
// how structure the workflow
// we're going to assume that if a project's timeline is updated
// with a new minigame child, that someone (the user or agent) has
// initiated a new game to play
if (isMinigameIbGib_V1(childIbGib)) {
// I'm guessing I want to spin this off after the event loop
// execution but I'm not sure on this.
setTimeout(() => {
this.activateIbGib({ ibGib: childIbGib }); // spin off?
}, 500);
} else {
if (logalot) { console.log(`${lc} new childIbGib (${childIbGib.ib}) is not a minigame ibgib, which is the only thing this is configured to handle right now. (I: 790ed8745a5736d8e6bf866a4a6d2f25)`); }
return; /* <<<< returns early */
}
// if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: 3a1c7d612aeadee515218cca2ad0c225)`); }
// const { contentEl } = this.elements;
// const chatEntry = await this.renderIbGibItem({ ibGib: childIbGib });
// contentEl.appendChild(chatEntry);
// chatEntry.scrollIntoView({ behavior: 'smooth' });
// let animation happen. we are not expecting a lot of messages to
// just come pouring in. If that becomes the case, then we need to
// reduce/remove this delay.
// await delay(500);
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async initElements(): Promise {
const lc = `${this.lc}[${this.initElements.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 98c5bd4e6796961b7672cb3258e4da25)`); }
const shadowRoot = this.shadowRoot;
if (!shadowRoot) { throw new Error(`(UNEXPECTED) shadowRoot falsy? (E: genuuid)`); }
// #region header
const headerEl = shadowRoot_getElementById(shadowRoot, 'project-header');
const headerTabsEl = shadowRoot_getElementById(shadowRoot, 'project-header-tabs');
// const nameEl = shadowRoot_getElementById(shadowRoot, 'project-name');
// const descEl = shadowRoot_getElementById(shadowRoot, 'project-description');
// addBtnEl
const addBtnEl = shadowRoot_getElementById(shadowRoot, 'project-header-add-btn');
// addPopoverEl - when user clicks add, this popover has the options
// of what exactly to add
const addPopoverEl = shadowRoot_getElementById(shadowRoot, 'add-popover');
const addPopoverOptions = addPopoverEl.querySelectorAll('.add-popover-option');
addBtnEl.addEventListener('click', async (event) => {
addPopoverEl.style.position = 'absolute';
addPopoverEl.style.top = `${addBtnEl.offsetTop + addBtnEl.clientHeight}px`;
addPopoverEl.style.left = `${addBtnEl.offsetLeft}px`;
});
// Event listeners for popover options
addPopoverOptions.forEach(option => {
option.addEventListener('click', async (event: Event) => {
const target = event.target as HTMLElement;
const optionType = target.getAttribute('data-option');
if (optionType) { await this.handleAddPopoverSelected(optionType); }
addPopoverEl.hidePopover(); // idempotent
});
});
// ellipsisBtnEl
const ellipsisBtnEl = shadowRoot_getElementById(shadowRoot, 'project-header-ellipsis-btn');
// ellipsisPopoverEl - when user clicks ellipsis, this popover has the options
// of what exactly to add
const ellipsisPopoverEl = shadowRoot_getElementById(shadowRoot, 'ellipsis-popover');
const ellipsisPopoverOptions = ellipsisPopoverEl.querySelectorAll('.ellipsis-popover-option');
ellipsisBtnEl.addEventListener('click', async (event) => {
ellipsisPopoverEl.style.position = 'absolute';
ellipsisPopoverEl.style.top = `${ellipsisBtnEl.offsetTop + ellipsisBtnEl.clientHeight}px`;
ellipsisPopoverEl.style.left = `${ellipsisBtnEl.offsetLeft}px`;
});
// Event listeners for popover options
ellipsisPopoverOptions.forEach(option => {
option.addEventListener('click', async (event: Event) => {
try {
const target = event.target as HTMLElement;
const optionType = target.getAttribute('data-option');
if (optionType) {
await this.handleEllipsisPopoverSelected(optionType);
}
} catch (error) {
const emsg = `${lc}[ellipsisPopoverOption] ${extractErrorMsg(error)} (E: 8468587582a85f00f8a71e12282a7825)`;
console.error(emsg);
alertUser({ msg: emsg, title: 'export failed...' }); // spins off
} finally {
// Hide popover after selection
// if (ellipsisPopoverEl.matches(':open')) {
ellipsisPopoverEl.hidePopover();
// }
}
});
});
// #endregion header
const contentEl = shadowRoot_getElementById(shadowRoot, 'project-content');
// #region footer
const footerEl = shadowRoot_getElementById(shadowRoot, 'project-footer');
const lensBarEl = shadowRoot_getElementById(shadowRoot, 'ibgib-lens-bar');
const rawLensBtnEl = shadowRoot_getElementById(shadowRoot, 'raw-lens-btn');
const textLensBtnEl = shadowRoot_getElementById(shadowRoot, 'text-lens-btn');
const minigameLensBtnEl = shadowRoot_getElementById(shadowRoot, 'minigame-lens-btn');
// #endregion footer
this.elements = {
headerEl,
headerTabsEl,
contentEl,
footerEl,
lensBarEl,
rawLensBtnEl,
textLensBtnEl,
minigameLensBtnEl,
// nameEl,
// descEl,
addBtnEl,
addPopoverEl,
ellipsisBtnEl,
ellipsisPopoverEl,
};
// has to run after this.elements set
await this.initSettings();
await this.initLensBarAndRelated();
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected override async initSettings(): Promise {
const lc = `${this.lc}[${this.initSettings.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 40015889cf08f03801c0ac08de4e3d25)`); }
await super.initSettings();
if (!this.settings) { throw new Error(`(UNEXPECTED) this.settings falsy after init? (E: 15ea55484aa8a9c78dd67bf88e468b25)`); }
if (!this.settings.ibGib) { throw new Error(`(UNEXPECTED) this.settings.ibGib falsy after init? (E: 048901c6c03c8c6c7400d279fdf37825)`); }
// let projectSettings = await this.getCurrentProjectSettings();
let projectSettings = await this.getSettings({
settingsType: SettingsType.project,
useCase: 'current',
});
if (!projectSettings) {
// need to create a new project settings section
projectSettings = {
type: 'project',
openChildTjpAddrs: [],
activeChildTjpAddr: undefined,
lensMode: this.lensMode,
}
// update the current settings and persist
const sectionName_default = await getSectionName({
settingsType: SettingsType.project,
useCase: 'default',
});
const sectionName_current = await getSectionName({
settingsType: SettingsType.project,
useCase: 'current',
});
const _newSettings = await mut8Timeline({
timeline: this.settings!.ibGib!,
metaspace: this.metaspace!,
mut8Opts: {
dataToAddOrPatch: {
sections: {
[sectionName_default]: projectSettings,
[sectionName_current]: projectSettings,
}
}
},
});
}
// const sectionName_generalCurrent = await getSectionName({
// settingsType: 'general',
// useCase: 'current',
// });
// data.sections[sectionName_generalDefault] = clone(DEFAULT_SETTINGS_GENERAL);
// data.sections[sectionName_generalCurrent] = clone(DEFAULT_SETTINGS_GENERAL);
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async initLensBarAndRelated(): Promise {
const lc = `${this.lc}[${this.initLensBarAndRelated.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 82f048513a35a0f1fa6b7e4803522725)`); }
for (const lensBtn of this.lensBtns) {
lensBtn.addEventListener('click', async () => {
const lensMode = lensBtn.getAttribute('data-mode') as LensMode;
await this.activateLensMode({ lensMode, skipInject: false });
// update the coupled UIInfo Settings for the domain ibgib so that
// the same viewer/editor
// const projectSettings = await this.getCurrentProjectSettings();
const projectSettings = await this.getSettings({
settingsType: SettingsType.project,
useCase: 'current',
});
if (!projectSettings) { throw new Error(`(UNEXPECTED) projectSettings falsy? (E: f7e328479b488df068abc1b28867ce25)`); }
if (projectSettings.lensMode !== lensMode) {
projectSettings.lensMode = lensMode;
const sectionName_current = await getSectionName({
settingsType: SettingsType.project,
useCase: 'current',
});
const _newSettings = await mut8Timeline({
timeline: this.settings!.ibGib!,
metaspace: this.metaspace!,
mut8Opts: {
dataToAddOrPatch: {
sections: {
[sectionName_current]: projectSettings,
}
},
},
});
}
});
}
const generalSettings = await this.getCurrentSettings({ settingsType: SettingsType.general });
if (!generalSettings) { throw new Error(`(UNEXPECTED) generalSettings falsy? settings not initialized with a general section? (E: d1f3e8c250489c548de42a55efba2825)`); }
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private get lensBtns(): HTMLButtonElement[] {
return this.elements ?
[
this.elements.rawLensBtnEl,
this.elements.textLensBtnEl,
this.elements.minigameLensBtnEl,
]
: [];
}
private updateLensBtnsUI(): void {
const lc = `${this.lc}[${this.updateLensBtnsUI.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: c20518af0bade4fde8772b91f4c88825)`); }
const lensMode = this.lensMode;
// update the lens buttons' UI
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: 2e1b5a513b6e3e0678fa8dfba5a8c825)`); }
this.lensBtns.forEach(btn => {
btn.classList.toggle('active', btn.getAttribute('data-mode') === lensMode);
});
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async activateLensMode({ lensMode, skipInject }: { lensMode: LensMode; skipInject: boolean; }) {
const lc = `${this.lc}[${this.activateLensMode.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 3687fb48fde881cf12423fb2b413f925)`); }
if (this._lensMode === lensMode) { return; /* <<<< returns early */ }
// guaranteed different lens mode
this._lensMode = lensMode;
this.updateLensBtnsUI();
// updating the project settings current general settings
if (skipInject) { return; /* <<<< returns early */ }
// instantiate or reload the tab's component
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: f1cc886fc78870d198062c88f4a78825)`); }
if (!this.activeChildInfo) { throw new Error(`(UNEXPECTED) this.activeChildInfo falsy? (E: 233fb3b04de80b8b1736fcabc0f32c25)`); }
// klugy hack loads the new component based on the lensMode, if
// required. if it's already in the componentCache for the tab
// info, then that will be set properly
await this.getLoadedChildInfo({ addr: this.activeChildInfo.addr, });
if (!this.activeChildInfo.component) { throw new Error(`(UNEXPECTED) tabInfo.component falsy? should be populated by this point in code (E: 2466c8a016e813be29a953a83b0fa525)`); }
const componentSvc = await getComponentSvc();
await componentSvc.inject({
parentEl: this.elements.contentEl,
componentToInject: this.activeChildInfo.component,
});
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* Handler for when an option is selected from the add popover.
*/
private async handleAddPopoverSelected(optionType: string): Promise {
const lc = `${this.lc}[${this.handleAddPopoverSelected.name}]`;
try {
if (logalot) { console.log(`${lc} starting... optionType: ${optionType} (I: genuuid)`); }
// TODO: Implement logic to create new ibGib based on optionType
// and add it as a tab.
switch (optionType) {
case 'text':
await this.addChildIbGib_text();
break;
case 'minigame':
await this.addChildIbGib_minigameActiveTab();
break;
default:
throw new Error(`(UNEXPECTED) invalid optionType (${optionType})? (E: 3856754562e8e7971822581899a6f825)`);
}
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async addChildIbGib_minigameActiveTab(): Promise {
const lc = `${this.lc}[${this.addChildIbGib_minigameActiveTab.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 28edda58994adcca1362419bef442e25)`); }
const name = await promptForText({
title: 'Game Title?',
msg: `What's it called?`,
cancelable: true,
});
if (!name) {
console.error(`${lc} User cancelled (E: 5d1c5eacde514b03ab6304685337e825)`);
return; /* <<<< returns early */
}
const metaspace = this.metaspace;
if (!metaspace) { throw new Error(`(UNEXPECTED) this.metaspace falsy? (E: 2bf487419e280ea32aef13b4ba7e2325)`); }
const space = await metaspace.getLocalUserSpace({ lock: false });
// {
// // gameVariant,
// name,
// description,
// instructions,
// keywords,
// }: {
// // gameVariant: MinigameGameVariant,
// name: string,
// description: string,
// instructions: string,
// keywords: string[],
// }
const activeTabIbGib = await this.getActiveTabIbGib();
if (!activeTabIbGib.data) { throw new Error(`(UNEXPECTED) activeTabIbGib.data falsy? (E: fc6e98d473ba3ee3bee9d67894640b25)`); }
const activeTjpAddr = getTjpAddr({ ibGib: activeTabIbGib, defaultIfNone: 'incomingAddr' }) ?? getIbGibAddr({ ibGib: activeTabIbGib });
const resNewMinigame = await minigameBuilderStartFunctionInfo.fnViaCmd({
cmd: minigameBuilderStartFunctionInfo.cmd,
cmdModifiers: minigameBuilderStartFunctionInfo.cmdModifiers.concat(),
// contextIbGibAddr: this.tjpAddr!,
contextIbGibAddr: activeTjpAddr,
gameType: 'typing',
name,
description: 'This is a minigame created by da human.',
instructions: 'Play!',
keywords: [],
}) as MinigameBuilderStartResult;
// necessary?
const latestMinigameAddr = await metaspace.getLatestAddr({
addr: resNewMinigame.minigameAddr,
space,
}) ?? resNewMinigame.minigameAddr;
// const resGet = await metaspace.get({ addrs: [latestMinigameAddr], space, });
// if (!resGet.success || resGet.errorMsg) {
// throw new Error(`(UNEXPECTED) couldn't get minigame that we just created? error: ${resGet.errorMsg} (E: 4f06c7e5c8884adcb895afbfac70ab25)`);
// }
// if (!resGet.ibGibs) { throw new Error(`(UNEXPECTED) resGet.ibGibs falsy? (E: babb1d865a9e4512784e9b96b1b7d825)`); }
// if (resGet.ibGibs.length !== 1) {
// throw new Error(`(UNEXPECTED) resGet.ibGibs length !== 1 for latestMinigameAddr (${latestMinigameAddr})? (E: b94736ace7589dc8191de6de5e8ff725)`);
// }
// const latestMinigameIbGib = resGet.ibGibs.at(0)! as MinigameIbGib_V1;
await this.activateIbGib({ addr: latestMinigameAddr });
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async addChildIbGib_text(): Promise {
const lc = `${this.lc}[${this.addChildIbGib_text.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 02800232ba6d5d16187e8f938fc80225)`); }
const { metaspace } = this;
if (!metaspace) { throw new Error(`(UNEXPECTED) metaspace falsy? (E: 8ec06d4d8608ead318e3538870059825)`); }
const space = await metaspace.getLocalUserSpace({ lock: false });
if (!space) { throw new Error(`(UNEXPECTED) space falsy? couldn't even get default local user space? (E: a81178540d08a3dbd9e0552826abc825)`); }
const title = await promptForText({
title: `title`,
msg: `what's it all about? this can be a filename.ext or just your intent about what the thing is. or just hit enter`,
cancelable: true,
});
if (!title) {
// await alertUser({ msg: 'cancelled, got it.', title: 'cancelled' });
console.log(`${lc} user cancelled. (I: a999335c4acf58eb6825af28f1733d25)`);
return; /* <<<< returns early */
}
// create the comment ibgib
const resCommentIbGib = await createCommentIbGib({
text: title,
addlMetadataText: `${getTimestampInTicks()}_${getSaferSubstring({ text: title, length: 16 })}`,
saveInSpace: true,
space,
});
let commentIbGib = resCommentIbGib.newIbGib;
commentIbGib = await mut8Timeline({
timeline: commentIbGib,
mut8Opts: {
dataToAddOrPatch: { name: title, description: title, },
},
metaspace,
space,
});
// create an agent for the new child
const agentsSvc = getAgentsSvc(); // Assuming getAgentsSvc is available
const newAgentIbGib = await agentsSvc.createNewAgent({
metaspace,
superSpace: undefined, // uses default local user space as the super space
name: `TextAgent-${this.instanceId}`,
api: 'gemini',
model: GEMINI_DEFAULT_MODEL_STR,
availableFunctions: clone(AGENT_AVAILABLE_FUNCTIONS_PROJECTCHILDTEXTAGENT),
initialSystemText: [
AGENT_INITIAL_SYSTEM_TEXT_PROJECTCHILDTEXTAGENT,
].join('\n'),
initialChatText: [
AGENT_INITIAL_CHAT_TEXT_PROJECTCHILDTEXTAGENT,
].join('\n'),
// fnGetAPIKey: this.getFnGetAPIKey(),
fnGetAPIKey: getDefaultFnGetAPIKey(),
type: AGENT_SPECIAL_IBGIB_TYPE_PROJECTCHILDTEXTAGENT,
addToAgentsTag: true,
});
await registerDomainIbGibWithAgentIndex({
domainIbGib: commentIbGib,
agentIbGib: newAgentIbGib,
metaspace,
space,
});
if (!this.ibGib) { throw new Error(`(UNEXPECTED) this.ibGib falsy? should be truthy and a project at that. (E: 23d1b4dcda88940c68c9a08df843b825)`); }
if (!isProjectIbGib_V1(this.ibGib)) { throw new Error(`(UNEXPECTED) this.ibGib is not a project ibgib? (E: 4004c8156dbdf6e40855ad54b3d00525)`); }
// append the comment to the project's timeline
await appendToTimeline({
timeline: this.ibGib,
rel8nInfos: [{
ibGibs: [commentIbGib],
rel8nName: PROJECT_CHILD_TEXT_REL8N_NAME,
}],
metaspace,
space,
});
// this.lensMode = 'text';
await this.activateLensMode({ lensMode: 'text', skipInject: true });
await this.activateIbGib({ ibGib: commentIbGib });
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected async getActiveTabIbGib(): Promise {
const lc = `${this.lc}[${this.getActiveTabIbGib.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 10e8819318c842e417523fbdf6956a25)`); }
if (!this.activeChildInfo) { throw new Error(`this.activeChildInfo falsy (E: 3ade8fe5f95b2ddb286d5008f17aff25)`); }
if (!this.activeChildInfo.component) { throw new Error(`this.activeChildInfo.component falsy. (E: 49ba441797b1595ce9b8e7cc62b53825)`); }
const ibGib = this.activeChildInfo.component.ibGib;
if (!ibGib) { throw new Error(`(UNEXPECTED) active tab's component's ibgib falsy? (E: a6917818f2ee9bf51326982886347825)`); }
return ibGib;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected async openChronology({
ibGibAddr,
ibGib,
}: {
ibGibAddr?: IbGibAddr,
ibGib?: IbGib_V1,
}): Promise {
const lc = `${this.lc}[${this.openChronology.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 14059d1a68c83b0c28da18f876c9b825)`); }
if (!ibGibAddr && !ibGib) { throw new Error(`(UNEXPECTED) both ibGibAddr and ibGib falsy? (E: 2ef0c8e5c7ed3b6a4b88cfd2974e8725)`); }
if (ibGibAddr && ibGib) {
if (ibGibAddr !== getIbGibAddr({ ibGib })) {
console.warn(`${lc} ibGibAddr !== getIbGibAddr({ibGib}) ? This is expectd to be equal, but maybe it's a tjp thing? (W: cd1842c17a082173ca28e908cb25a825). Overriding/Going with ibGib itself`)
ibGibAddr = getIbGibAddr({ ibGib }); // override
}
}
ibGibAddr ??= getIbGibAddr({ ibGib });
let chronologysComponent = getIbGibGlobalThis_Common().chronologysComponent;
// wait for it if it isn't defined yet
let count = 0;
while (!chronologysComponent) {
console.warn(`${lc} global chronologysComponent is expected to be truthy by now. delaying (W: e43b814165489d87e8865451c66d5825)`)
count++;
if (count > 100) {
debugger; // error in web1 component expectation
throw new Error(`(UNEXPECTED) global chronologysComponent is falsy? (E: 407c48599e385fe10beb695849e7f125)`);
}
await delay(100);
}
await chronologysComponent.openIbGibAddr({ ibGibAddr, });
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* Handler for when an option is selected from the add popover.
*/
private async handleEllipsisPopoverSelected(optionType: string): Promise {
const lc = `${this.lc}[${this.handleEllipsisPopoverSelected.name}]`;
try {
if (logalot) { console.log(`${lc} starting... optionType: ${optionType} (I: genuuid)`); }
// const getActiveTabIbGib: () => IbGib_V1 = () => {
// if (!this.activeChildInfo) { throw new Error(`this.activeChildInfo falsy (E: 3ade8fe5f95b2ddb286d5008f17aff25)`); }
// if (!this.activeChildInfo.component) { throw new Error(`this.activeChildInfo.component falsy. (E: 49ba441797b1595ce9b8e7cc62b53825)`); }
// const ibGib = this.activeChildInfo.component.ibGib;
// if (!ibGib) { throw new Error(`(UNEXPECTED) active tab's component's ibgib falsy? (E: a6917818f2ee9bf51326982886347825)`); }
// return ibGib;
// }
switch (optionType) {
case 'chat-active-tab':
if (this.activeChildInfo?.addr) {
await this.openChronology({ ibGibAddr: this.activeChildInfo.addr });
} else {
await alertUser({ title: 'No Active Tab??', msg: `There was no active tab found. This seems like a bug so you should report it please. (E: 7304e579bd5e398468e8cd333e5f9825)` });
}
break;
case 'copy-project-address':
const addr = getIbGibAddr({ ibGib: this.ibGib });
copyToClipboard({ data: { text: addr }, });
highlightElement({ el: this.elements!.contentEl, magicHighlightTimingMs: 1_000, }); // spin off so options disappear
break;
case 'copy-active-tab-address':
if (this.activeChildInfo?.addr) {
copyToClipboard({ data: { text: this.activeChildInfo.addr }, });
highlightElement({ el: this.activeChildInfo.component?.elements?.contentEl, magicHighlightTimingMs: 1_000, }); // spin off so options disappear
} else {
await alertUser({ title: 'No Active Tab??', msg: `There was no active tab found. This seems like a bug so you should report it please. (E: 4451dd7d60381f8f08557b479eb5bb25)` });
}
break;
case 'export-project':
await this.exportProject({ compress: false });
break;
case 'export-project-gzip':
await this.exportProject({ compress: true });
break;
case 'export-active-tab':
await this.exportIbGib({
ibGib: await this.getActiveTabIbGib(),
compress: false
});
break;
case 'export-active-tab-gzip':
await this.exportIbGib({
ibGib: await this.getActiveTabIbGib(),
compress: true,
});
break;
default:
throw new Error(`(UNEXPECTED) invalid optionType (${optionType})? (E: 3856754562e8e7971822581899a6f825)`);
}
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* exports the current project. If more than one is open, exports the currently active project.
*
* Should this also include exporting the project's agent? As a flag
*/
private async exportProject({ compress }: { compress: boolean }): Promise {
const lc = `${this.lc}[${this.exportProject.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 719052c3bb285cdfd8d2b21258c71825)`); }
if (!this.ibGib) { throw new Error(`(UNEXPECTED) this.ibGib falsy? (E: bf40bc1beae6b34c9c8544b888b51425)`); }
await this.exportIbGib({
ibGib: this.ibGib,
compress,
});
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* rerender
*/
protected override async renderUI(): Promise {
const lc = `${this.lc}[${this.renderUI.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 5415ec9be03ca640cb1a3d6a17d22625)`); }
await super.renderUI();
if (!this.elements) {
console.warn(`${lc} (UNEXPECTED) tried to render but haven't initialized elements? (W: genuuid)`);
return; /* <<<< returns early */
}
const {
headerEl, contentEl, footerEl,
// nameEl,
// descEl,
} = this.elements;
// const projectSettings = await this.getCurrentProjectSettings();
const projectSettings = await this.getSettings({
settingsType: SettingsType.project,
useCase: 'current',
});
if (!projectSettings) { throw new Error(`(UNEXPECTED) projectSettings falsy? (E: 052b322abcc5856f28e44cc89c373825)`); }
this.updateLensBtnsUI();
// nameEl.textContent = this.ibGib?.data?.name ?? '[project no name?]'
// nameEl.textContent += ` (v${this.ibGib?.data?.n ?? '?'})`
// const description = this.ibGib?.data?.description;
// if (description) {
// descEl.textContent = description;
// } else {
// descEl.style.display = 'none';
// }
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
override async disconnected(): Promise {
const lc = `${this.lc}[${this.disconnected.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
// no action atow
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
protected override async initAgents(): Promise {
const lc = `${this.lc}[${this.initAgents.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
await this.loadAgentsCoupledToIbGib();
if (!this.agent) { throw new Error(`(UNEXPECTED) agent falsy after createNewAgent? (E: 4a5042d2e1b2de0eb15d39e406549125)`); }
await this.agent.updateAvailableFunctions({
availableFunctions: AGENT_AVAILABLE_FUNCTIONS_PROJECTAGENT,
});
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* inits the chronology in the right panel for web1 components
*/
private async initChronology(): Promise {
const lc = `${this.lc}[${this.initChronology.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
const globalIbGib = getIbGibGlobalThis_BlankGib();
let chronologysComponent = globalIbGib.chronologysComponent;
let count = 0;
while (!chronologysComponent) {
console.warn(`${lc} global chronologysComponent is expected to be truthy by now. delaying (W: genuuid)`)
count++;
if (count > 100) {
debugger; // error in web1 component expectation
throw new Error(`(UNEXPECTED) global chronologysComponent is falsy? (E: 3d68459066ee7ef9fbdfea4ea3904825)`);
}
await delay(100);
}
if (!this.ibGibProxy) { throw new Error(`(UNEXPECTED) this.ibGibProxy falsy? (E: 4e91911bf6ce45d398c04a256fceb825)`); }
// ibGibProxy.ibGib is a comment ibgib that is data.n=2. the 2 is
// because it is already related to an agent.
await chronologysComponent.openIbGibAddr({
ibGibAddr: getIbGibAddr({ ibGib: this.ibGibProxy.ibGib }),
});
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
}