import thisHtml from "./chronology.html";
import thisCss from "./chronology.css";
import stylesCss from "../../../styles.css";
import rootCss from "../../../root.css";
import { delay, extractErrorMsg, pretty } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
import { getTimestampInfo } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
import { IbGibAddr, } from "@ibgib/ts-gib/dist/types.mjs";
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
import { MetaspaceService } from "@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs";
import { isComment, parseCommentIb } from "@ibgib/core-gib/dist/common/comment/comment-helper.mjs";
import { tellUserFunctionInfo } from "@ibgib/web-gib/dist/api/commands/chat/tell-user.mjs";
import { getGlobalMetaspace_waitIfNeeded } from "@ibgib/web-gib/dist/helpers.mjs";
import { IbGibDynamicComponentInstanceBase, IbGibDynamicComponentMetaBase } from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
import { IbGibDynamicComponentInstance, IbGibDynamicComponentInstanceInitOpts } from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
import { parseAddlMetadataTextForAgentText, } from "@ibgib/web-gib/dist/witness/agent/agent-helpers.mjs";
import { AgentWitnessAny, } from "@ibgib/web-gib/dist/witness/agent/agent-one-file.mjs";
import { TextSource } from "@ibgib/web-gib/dist/witness/agent/agent-constants.mjs";
import { ProjectIbGib_V1 } from "@ibgib/web-gib/dist/common/project/project-types.mjs";
import { getAgentsSvc } from "@ibgib/web-gib/dist/witness/agent/agents-service-v1.mjs";
import { AGENT_SPECIAL_IBGIB_TYPE_PRIMARYAGENT } from '@ibgib/web-gib/dist/witness/agent/agent-constants.mjs';
import { GLOBAL_LOG_A_LOT, } from "../../../constants.mjs";
import { getComponentCtorArg, getIbGibGlobalThis_BlankGib, } from "../../../helpers.web.mjs";
import { ID_PRIMARY_AGENT_CHAT_LOG } from "../../../ui/shell/shell-constants.mjs";
import {
AGENT_GOAL_COMMON, AGENT_INITIAL_CHAT_HI_PLEASEINTRO_YOURSELF,
AGENT_SYSTEM_PROMPT_COMMON_INSTRUCTIONS,
} from "../../../agent-texts/common-agent-texts.mjs";
import { simpleIbGibRouterSingleton } from "../../../ui/router/router-one-file.mjs";
import { isMinigameIbGib_V1 } from "../../../common/minigame/minigame-helper.mjs";
import { MinigameIbGib_V1 } from "../../../common/minigame/minigame-types.mjs";
import { ProjectComponentInstance } from "../../projects/project/project-component-one-file.mjs";
const logalot = GLOBAL_LOG_A_LOT;
export const AGENT_SPECIAL_IBGIB_TYPE_CHRONOLOGYAGENT = 'chronologyagent';
export const AGENT_GOAL_CHRONOLOGYAGENT = [
AGENT_GOAL_COMMON,
`You yourself are a "chronology" agent. Your job is to help show the chronology of an ibgib.`,
`A "chronology" is just a synonym for "timeline" in our case right now. I use the word "timeline" generally when speaking about ibgibs and I wanted a different word in code. But semantically, the "chronology" is meant to give some condensed view of an ibgib's evolution.`,
`The use case right now is to show the equivalent of what others call "chats". A "chat" in their sense is a linear sequence of some context that has text, and possibly pics and other artifacts, added to it over time. In ibgib, since we create a hypergraph, the timeline aspect is a little more complicated. The context ibgib itself may add "child" items, and so may those child items effectively ad infinitum. This is truly parallel computing.`,
`So a chronology is some view on what could be a complicated timeline.`,
`Keep in mind though that we're still early dev stage so you may not be able to do much at the moment.`,
].join('\n');
export const AGENT_INITIAL_SYSTEM_TEXT_CHRONOLOGYAGENT = [
AGENT_SYSTEM_PROMPT_COMMON_INSTRUCTIONS,
AGENT_GOAL_CHRONOLOGYAGENT,
].join('\n');
export const AGENT_INITIAL_CHAT_TEXT_CHRONOLOGYAGENT = [
AGENT_INITIAL_CHAT_HI_PLEASEINTRO_YOURSELF,
].join('\n');
export const CHAT_WITH_AGENT_PLACEHOLDER_CHRONOLOGYAGENT = '';
export const AGENT_AVAILABLE_FUNCTIONS_CHRONOLOGYAGENT = [
tellUserFunctionInfo,
];
export const CHRONOLOGY_COMPONENT_NAME: string = 'ibgib-chronology';
export class ChronologyComponentMeta extends IbGibDynamicComponentMetaBase {
protected override lc: string = `[${ChronologyComponentMeta.name}]`;
/**
* temporary regexp path for our initial dev. this component will become
* attached to actual ib^gib addrs
*/
routeRegExp?: RegExp = new RegExp(CHRONOLOGY_COMPONENT_NAME);
// routeRegExp?: RegExp = /apps\/web1\/gib\/contact.html/;
componentName: string = CHRONOLOGY_COMPONENT_NAME;
constructor() {
super(getComponentCtorArg());
customElements.define(this.componentName, ChronologyComponentInstance);
}
/**
* for a chronology, 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: 19ed38829f8693c83889ff3d151b4e25)`); }
const component = document.createElement(this.componentName) as ChronologyComponentInstance;
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 ChronologyElements {
headerEl: HTMLElement;
// headerTabsEl: HTMLElement | undefined;
textEl: HTMLHeadingElement;
/**
*
*/
descEl: HTMLParagraphElement;
/**
* container element for the chronologys component
*/
contentEl: HTMLElement;
footerEl: HTMLElement;
// inputEl: HTMLTextAreaElement;
}
export class ChronologyComponentInstance
extends IbGibDynamicComponentInstanceBase
implements IbGibDynamicComponentInstance {
protected override lc: string = `[${ChronologyComponentInstance.name}]`;
metaspace: MetaspaceService | undefined;
constructor() {
super();
}
override async initialize(opts: IbGibDynamicComponentInstanceInitOpts): Promise {
const lc = `${this.lc}[${this.initialize.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 4764f8b8d8a801a008e85328752f7825)`); }
await super.initialize(opts);
await this.loadIbGib();
this.agentsInitialized = this.initAgents();
await this.agentsInitialized; // Wait for metaspace to be initialized
// await this.eoadChildIbGibs();
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async loadChildIbGibs(): Promise {
const lc = `${this.lc}[${this.loadChildIbGibs.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: beb5c41d17a52fcb53511f97c8301625)`); }
if (!this.metaspace) { throw new Error(`(UNEXPECTED) metaspace should have been initialized. (E: 3a4c4876a0904b499f09112674b8a925)`) }
if (!this.ibGib) { throw new Error(`(UNEXPECTED) this.ibGib falsy? (E: 77428a4a60f81a1a9e9d17d041e39125)`); }
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: e9802057b36b692985b7e32633e20525)`); }
const { contentEl } = this.elements;
contentEl.innerHTML = ''; //clear the content
const excludeRel8nNames: string[] = [
'ancestor', 'dna', 'past', 'tjp',
];
// const rel8nNames = ['comment', 'pic', 'minigame'];
if (!this.ibGib.rel8ns) { throw new Error(`(UNEXPECTED) this.ibGib.rel8ns falsy? (E: 5c530af755a37f89ac51810b61dc2d25)`); }
const rel8nNames = Object.keys(this.ibGib.rel8ns).filter(x => !excludeRel8nNames.includes(x));
const childAddrs: IbGibAddr[] = [];
for (const rel8nName of rel8nNames) {
const rel8dAddrs = this.ibGib.rel8ns[rel8nName] ?? [];
childAddrs.push(...rel8dAddrs);
}
const childIbGibs: IbGib_V1[] = [];
for (const childAddr of childAddrs) {
const resGet = await this.metaspace.get({ addr: childAddr });
if (resGet.errorMsg) { throw new Error(`Could not retrieve ibGib: ${resGet.errorMsg} (E: 5c77a680328c49e085557e7a7c20b425)`) }
if (!resGet.ibGibs || resGet.ibGibs.length === 0) { throw new Error(`Could not retrieve ibGib: No IbGibs returned from metaspace. (E: 4e657a262a784b339873976b3288d125)`); }
childIbGibs.push(resGet.ibGibs[0])
}
childIbGibs.sort((a, b) => {
const aRes = getTimestampInfo({ ibGib: a });
if (!aRes.valid) { throw new Error(`(UNEXPECTED) invalid a timestamp: ${aRes.emsg} (E: 81a4c81e25e65a971922626f0a08a825)`); }
const aTicks = Number.parseInt(aRes.ticks);
const bRes = getTimestampInfo({ ibGib: b });
if (!bRes.valid) { throw new Error(`(UNEXPECTED) invalid b timestamp: ${bRes.emsg} (E: 41813b26a8c92d4c8a293e426d202f25)`); }
const bTicks = Number.parseInt(bRes.ticks);
if (aTicks < bTicks) {
return -1;
} else if (aTicks > bTicks) {
return 1;
} else {
return 0;
}
});
// childIbGibs.sort((a, b) => {
// const aTicks = getTimestampInfo({ ib: a.ib }).timestampTicks;
// const bTicks = getTimestampInfo({ ib: b.ib }).timestampTicks;
// return aTicks > b.ib ? 1 : -1;
// });
for (const childIbGib of childIbGibs) {
let errored = false;
try {
const itemElement = await this.renderIbGibItem({ ibGib: childIbGib });
contentEl.appendChild(itemElement)
} catch (error) {
console.error(`${lc} Error rendering ibGib: ${extractErrorMsg(error)} (E: b2a7592d1a5743d6b4e7b9241561e325)`);
errored = true;
}
if (errored) {
try {
const itemElement = await this.renderIbGibItem_fallback({ ibGib: childIbGib });
contentEl.appendChild(itemElement)
} catch (error) {
console.error(`${lc} Error rendering ibGib during fallback?: ${extractErrorMsg(error)} (E: 7d37888dc85e37141877eb786dbaaf25)`);
errored = true;
}
}
}
} 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: 95d9e84448669a0db81410c810e83b25)`); }
// 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();
/**
* for the moment, we're just re-using the primary agent's chat log...eesh!!
*
* This is obviously the wrong thing to do in the long run...
*/
const primaryAgentChatLog =
document.getElementById(ID_PRIMARY_AGENT_CHAT_LOG) as HTMLDivElement;
if (!primaryAgentChatLog) { throw new Error(`(UNEXPECTED) primaryAgentChatLog not found in document? (E: fe663fd60a5820040d5bacb845ed1825)`); }
await this.agentsInitialized;
await this.loadChildIbGibs();
await this.renderUI();
setTimeout(() => {
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: 3a1c7d612aeadee515218cca2ad0c225)`); }
const { contentEl } = this.elements;
if (contentEl.lastElementChild) {
contentEl.lastElementChild.scrollIntoView({ behavior: 'smooth' });
}
}, 1000);
// await this.agent!.witness(ROOT); // not the responsibility of the chronology component to initiate prompt
} 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)`); }
console.log(`${lc} this.ibGib: ${pretty(this.ibGib)}`)
await super.handleContextUpdated();
await this.renderUI();
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* renders a single ibgib into the chronology content element
*/
private async renderIbGibItem({
ibGib,
}: {
ibGib: IbGib_V1;
}): Promise {
const lc = `${this.lc}[${this.renderIbGibItem.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: d59d1e05b804665e8ee9bc28d56ec825)`); }
let resEl: HTMLElement;
if (isComment({ ibGib })) {
resEl = await this.renderIbGibItem_comment({ ibGib });
} else if (isMinigameIbGib_V1(ibGib)) {
resEl = await this.renderIbGibItem_minigame({ ibGib });
} else {
resEl = await this.renderIbGibItem_fallback({ ibGib });
}
return resEl;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async renderIbGibItem_comment({
ibGib,
}: {
ibGib: IbGib_V1;
}): Promise {
const lc = `${this.lc}[${this.renderIbGibItem_comment.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: 2948f102f3a6d51d35b26a9339113325)`); }
if (!ibGib.data) { throw new Error(`(UNEXPECTED) childIbGib.data falsy? (E: a1c4e1a657f764c98e7f919663058325)`); }
let text = ibGib.data.text;
if (!text) { throw new Error(`childIbGib.data.text falsy? what kind of child are we tracking at this point? we only do comments. ${pretty(ibGib)} (E: 0e5e2e1c7b5c692f295979a03c617625)`); }
const ib = ibGib.ib;
// what is the
const { safeIbCommentMetadataText } = parseCommentIb({ ib });
let textSrc: TextSource;
try {
const resParse = parseAddlMetadataTextForAgentText({
addlMetadataText: safeIbCommentMetadataText ?? '',
ifError: 'ignore',
});
textSrc = resParse.textSrc;
} catch (error) {
textSrc = 'unknown';
}
let who: string;
switch (textSrc) {
case 'ai':
who = 'agent'; break;
case 'human':
who = 'user'; break;
case 'hardcoded':
who = 'code'; break;
case 'function':
who = 'func'; break;
default:
who = '[who?]';
}
const timestampInfo = getTimestampInfo({ ibGib });
if (!timestampInfo.valid) {
throw new Error(`(UNEXPECTED) invalid timestamp: ${timestampInfo.emsg} (E: 42643858345b58538f09a71287a19f25)`);
}
const date = timestampInfo.date;
const timestampString = date.toLocaleString(); // Use toLocaleString for a more readable format
const timestampParagraph = document.createElement('p');
timestampParagraph.textContent = timestampString;
timestampParagraph.classList.add('timestamp');
if (who === 'agent') {
who = 'An AI agent (🤖)';
} else {
who = 'A human';
}
timestampParagraph.title = `${who} created this message ${timestampString}`;
const chatEntry = document.createElement('section');
const identityInfoDiv = document.createElement('div');
identityInfoDiv.classList.add('identity-info');
const identityInfoP = document.createElement('p');
if (textSrc === 'ai') {
// right now we're encoding it in "other" agent text addl
// metadata. see tell-user.mts tellUserImpl and
// agent-helpers.mts getAddlMetadataTextForAgentText.
const agentName = safeIbCommentMetadataText?.split('_').at(2) ?? 'Agent';
identityInfoP.textContent = `🤖 ${agentName}`;
chatEntry.classList.add('agent-message');
} else if (textSrc === 'human') {
chatEntry.classList.add('human-message');
identityInfoP.textContent = `user`;
}
identityInfoDiv.appendChild(identityInfoP);
chatEntry.appendChild(identityInfoDiv)
const textContentDiv = document.createElement('div');
const textParagraphs: string[] = text.split('\n');
textParagraphs.forEach(textParagraph => {
const pElement = document.createElement('p');
pElement.textContent = textParagraph;
textContentDiv.appendChild(pElement);
});
const copyButton = document.createElement('button');
copyButton.textContent = '🗐';
copyButton.classList.add('copy-button');
copyButton.addEventListener('click', async (e) => {
e.preventDefault();
e.stopImmediatePropagation();
navigator.clipboard.writeText(text);
const feedbackSpan = document.createElement('span');
feedbackSpan.textContent = "Copied!";
feedbackSpan.classList.add('copied-feedback');
feedbackSpan.style.position = 'absolute';
feedbackSpan.style.bottom = '30px';
feedbackSpan.style.left = '20px';
chatEntry.appendChild(feedbackSpan);
await delay(100);
chatEntry.classList.add('copied-animation');
chatEntry.classList.add('highlight');
await delay(500);
chatEntry.classList.remove('copied-animation');
await delay(400);
chatEntry.classList.remove('highlight');
await delay(1000);
feedbackSpan.remove();
});
chatEntry.dataset.clicked = "false";
chatEntry.addEventListener('click', () => {
const clicked = chatEntry.dataset.clicked;
chatEntry.dataset.clicked = clicked === "true" ? "false" : "true";
if (chatEntry.dataset.clicked === "true") {
chatEntry.classList.add('show-details');
} else {
chatEntry.classList.remove('show-details');
}
});
chatEntry.addEventListener('mouseover', () => {
if (chatEntry.dataset.clicked !== "true") {
chatEntry.classList.add('show-details');
}
});
chatEntry.addEventListener('mouseout', () => {
if (chatEntry.dataset.clicked !== "true") {
chatEntry.classList.remove('show-details');
}
});
chatEntry.appendChild(copyButton);
chatEntry.appendChild(textContentDiv);
chatEntry.appendChild(timestampParagraph);
return chatEntry;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async renderIbGibItem_minigame({
ibGib,
}: {
ibGib: MinigameIbGib_V1;
}): Promise {
const lc = `${this.lc}[${this.renderIbGibItem_minigame.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
if (!ibGib.data) { throw new Error(`(UNEXPECTED) ibGib.data falsy? This is expected to be a minigame ibgib. (E: 5fe49d9c7bd87fb2284fad28f4916925)`); }
const chatEntry = document.createElement('section');
// identity
// const identityInfoDiv = document.createElement('div');
// identityInfoDiv.classList.add('identity-info');
// const identityInfoP = document.createElement('p');
// chatEntry.classList.add('code-message');
// identityInfoP.textContent = `identityhere`;
// identityInfoDiv.appendChild(identityInfoP);
// body
const textContentDiv = document.createElement('div');
const pElement = document.createElement('p');
const name = ibGib.data.name;
const iElement = document.createElement('i');
iElement.style.fontSize = 'small';
iElement.textContent = `${ibGib.data.name || '[no name?]'} minigame added.`;
pElement.appendChild(iElement);
textContentDiv.appendChild(pElement);
// timestamp footer
const timestampInfo = getTimestampInfo({ ibGib });
if (!timestampInfo.valid) {
throw new Error(`(UNEXPECTED) invalid timestamp: ${timestampInfo.emsg} (E: genuuid)`);
}
const date = timestampInfo.date;
const timestampString = date.toLocaleString(); // Use toLocaleString for a more readable format
const timestampParagraph = document.createElement('p');
timestampParagraph.textContent = timestampString;
timestampParagraph.classList.add('timestamp');
timestampParagraph.title = `This ibgib message was created ${timestampString}`;
chatEntry.dataset.clicked = "false";
chatEntry.addEventListener('click', () => {
const clicked = chatEntry.dataset.clicked;
chatEntry.dataset.clicked = clicked === "true" ? "false" : "true";
if (chatEntry.dataset.clicked === "true") {
chatEntry.classList.add('show-details');
} else {
chatEntry.classList.remove('show-details');
}
});
chatEntry.addEventListener('mouseover', () => {
if (chatEntry.dataset.clicked !== "true") {
chatEntry.classList.add('show-details');
}
});
chatEntry.addEventListener('mouseout', () => {
if (chatEntry.dataset.clicked !== "true") {
chatEntry.classList.remove('show-details');
}
});
// compose the chatEntry itself
// chatEntry.appendChild(identityInfoDiv)
chatEntry.appendChild(textContentDiv);
chatEntry.appendChild(timestampParagraph);
// when clicking the chatEntry, should activate the ibgib on the
// projects component
chatEntry.addEventListener('click', async () => {
const globalBlankGib = getIbGibGlobalThis_BlankGib();
if (!this.ibGib) { throw new Error(`(UNEXPECTED) this.ibGib falsy? (E: 5c0e3e92ea2dcdb1f1e8eaa828ad5825)`); }
const projectsComponent = globalBlankGib.projectsComponent;
if (!projectsComponent) { throw new Error(`(UNEXPECTED) globalBlankGib.projectsComponent falsy? (E: 27ec3b3738872869d80064381cebe825)`); }
if (!projectsComponent.activeProjectTabInfo) {
throw new Error(`(UNEXPECTED) projectsComponent.activeProjectTabInfo falsy? (E: a9d3de3612f858f818eb1eb85f0c7825)`);
}
const projectComponent = projectsComponent.activeProjectTabInfo.component as ProjectComponentInstance;
if (!projectComponent) { throw new Error(`(UNEXPECTED) projectComponent falsy? projectsComponent.activeProjectTabInfo.component is expected to be truthy at this point. (E: 66cc452486787f8b881a20b35333ac25)`); }
await projectComponent.activateIbGib({ ibGib });
});
return chatEntry;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
private async renderIbGibItem_fallback({
ibGib,
}: {
ibGib: IbGib_V1;
}): Promise {
const lc = `${this.lc}[${this.renderIbGibItem_fallback.name}]`;
try {
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
const chatEntry = document.createElement('section');
// identity
// const identityInfoDiv = document.createElement('div');
// identityInfoDiv.classList.add('identity-info');
// const identityInfoP = document.createElement('p');
// chatEntry.classList.add('code-message');
// identityInfoP.textContent = `identityhere`;
// identityInfoDiv.appendChild(identityInfoP);
// body
const textContentDiv = document.createElement('div');
const pElement = document.createElement('p');
pElement.textContent = getIbGibAddr({ ibGib });
textContentDiv.appendChild(pElement);
// timestamp footer
const timestampInfo = getTimestampInfo({ ibGib });
if (!timestampInfo.valid) {
throw new Error(`(UNEXPECTED) invalid timestamp: ${timestampInfo.emsg} (E: genuuid)`);
}
const date = timestampInfo.date;
const timestampString = date.toLocaleString(); // Use toLocaleString for a more readable format
const timestampParagraph = document.createElement('p');
timestampParagraph.textContent = timestampString;
timestampParagraph.classList.add('timestamp');
timestampParagraph.title = `This ibgib message was created ${timestampString}`;
chatEntry.dataset.clicked = "false";
chatEntry.addEventListener('click', () => {
const clicked = chatEntry.dataset.clicked;
chatEntry.dataset.clicked = clicked === "true" ? "false" : "true";
if (chatEntry.dataset.clicked === "true") {
chatEntry.classList.add('show-details');
} else {
chatEntry.classList.remove('show-details');
}
});
chatEntry.addEventListener('mouseover', () => {
if (chatEntry.dataset.clicked !== "true") {
chatEntry.classList.add('show-details');
}
});
chatEntry.addEventListener('mouseout', () => {
if (chatEntry.dataset.clicked !== "true") {
chatEntry.classList.remove('show-details');
}
});
// compose the chatEntry itself
// chatEntry.appendChild(identityInfoDiv)
chatEntry.appendChild(textContentDiv);
chatEntry.appendChild(timestampParagraph);
return chatEntry;
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
/**
* right now, in witnesswith context base, these children are hard-coded as
* pic/comment/link rel8ns. need to change core-gib to make this a property
* on the class that drives which rel8nNames to track for new context
* children.
*/
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)`); }
// for starters, we'll just add a new item for the child, since it's
// just a simple "chat log" right now.
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' });
// super.handleNewContextChild
// 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: 2669d84403e65a091850a118cc1e8e25)`); }
// #region header
const headerEl = shadowRoot.getElementById('chronology-header') as HTMLElement;
if (!headerEl) { throw new Error(`(UNEXPECTED) headerEl not found in shadowRoot? (E: 12ba48a30b586c7268577f8a76c0b825)`); }
const textEl = shadowRoot.getElementById('chronology-text') as HTMLHeadingElement;
if (!textEl) { throw new Error(`(UNEXPECTED) textEl not found in shadowRoot? (E: c0c11d642bc26eb224a714740f6c7225)`); }
const descEl = shadowRoot.getElementById('chronology-description') as HTMLParagraphElement;
if (!descEl) { throw new Error(`(UNEXPECTED) descEl not found in shadowRoot? (E: 8b82a81eb058ee783553b1888c1b3325)`); }
// #endregion header
const contentEl = shadowRoot.getElementById('chronology-content') as HTMLElement;
if (!contentEl) { throw new Error(`(UNEXPECTED) contentEl not found in shadowRoot? (E: aa90dd17107658d79d8e346f99085a25)`); }
const footerEl = shadowRoot.getElementById('chronology-footer') as HTMLElement;
if (!footerEl) { throw new Error(`(UNEXPECTED) footerEl not found in shadowRoot? (E: 5a4b78703d0e0547f8d8eab86d67d825)`); }
footerEl.style.display = 'none';
// this.footerEl = footerEl as HTMLElement;
this.elements = {
headerEl,
// headerTabsEl,
contentEl,
footerEl,
textEl,
descEl,
};
} 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: 2b9f6893b449d7a72861c148ec428925)`);
return; /* <<<< returns early */
}
const {
headerEl, contentEl, footerEl,
// tabBtnEl,
// inputEl,
textEl, descEl,
} = this.elements;
if (!this.ibGib) { throw new Error(`(UNEXPECTED) this.ibGib falsy? (E: a2e31a4cfcd763a5c6e5133919aa0725)`); }
// if (this.ibGib.ib.startsWith('comment --interactive')) {
if (simpleIbGibRouterSingleton.isCurrentPageWeb1) {
// the current hack is that we set the chronology's context to
// the initial comment ibgib that we hacked to bootstrap the web
// app. in the future, we just need a better mechanism for web1
// chronology, which may just be an entirely separate app for
// web1 and projects/dev
if (logalot) { console.warn(`${lc} web1 chronologys tab btn title hack. (W: bc3ed81fdd48f351580c2f7b035e6825)`); }
textEl.style.display = 'none';
descEl.style.display = 'none';
} else {
// we are in a regular project/other ibgib
textEl.textContent = this.ibGib?.data?.name ?? '[no name?]'
textEl.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: 8e0719f027b8e25dc836b4a8adbf2925)`); }
// 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: a16821cfe4d8dce0483ec60879005425)`); }
const metaspace = await getGlobalMetaspace_waitIfNeeded();
this.metaspace = metaspace;
if (!this.ibGib) { throw new Error(`(UNEXPECTED) this.ibGib falsy? (E: f09cc2b636e83410bd7a89ec954e3825)`); }
// do {
if (simpleIbGibRouterSingleton.isCurrentPageWeb1) {
let agent: AgentWitnessAny | undefined = undefined;
const agentsSvc = getAgentsSvc();
do {
let agents = await agentsSvc.getAgents({
metaspace,
type: AGENT_SPECIAL_IBGIB_TYPE_PRIMARYAGENT,
spaceId: undefined, // explicitly use default local space just to show this option bc it's early in life
});
if (agents.length > 0) {
agent = agents.at(0)!;
} else {
await delay(200);
}
} while (!agent);
this.agents = [agent];
} else {
await this.loadAgentsCoupledToIbGib();
}
if (!this.agent) {
// do we care
console.error(`(UNEXPECTED) this.agent falsy after load agents? (E: 7ab4a8a82c48c3161ab20f3c6f624b25)`);
// throw new Error(`(UNEXPECTED) this.agent falsy after load agents? (E: 7ab4a8a82c48c3161ab20f3c6f624b25)`);
}
// if (!this.agent) {
// if (logalot) { console.log(`${lc} no agents related to project? delaying and trying again... (I: 1a3acf5c8083b7f23bc665eec8256e25)`); }
// await delay(100)
// }
// } while (!this.agent)
} catch (error) {
console.error(`${lc} ${extractErrorMsg(error)}`);
throw error;
} finally {
if (logalot) { console.log(`${lc} complete.`); }
}
}
}