change(ui): remove isjump, improve error logging for dommanager; improve healthstatus API display

This commit is contained in:
nick-delirium 2023-03-27 12:55:11 +02:00
parent d53de951ff
commit a4a2089698
9 changed files with 46 additions and 42 deletions

View file

@ -22,6 +22,7 @@ export interface IServiceStats {
function HealthStatus() {
const healthResponseSaved = localStorage.getItem(healthResponseKey) || '{}';
const [healthResponse, setHealthResponse] = React.useState(JSON.parse(healthResponseSaved));
const [isError, setIsError] = React.useState(false);
const [isLoading, setIsLoading] = React.useState(false);
const lastAskedSaved = localStorage.getItem(lastAskedKey);
const [lastAsked, setLastAsked] = React.useState(lastAskedSaved);
@ -36,6 +37,7 @@ function HealthStatus() {
setLastAsked(asked.toString());
} catch (e) {
console.error(e);
setIsError(true);
} finally {
setIsLoading(false);
}
@ -51,7 +53,7 @@ function HealthStatus() {
}
}, []);
const icon = healthResponse?.overallHealth ? 'pulse' : ('exclamation-circle-fill' as const);
const icon = !isError && healthResponse?.overallHealth ? 'pulse' : ('exclamation-circle-fill' as const);
return (
<>
<div className={'relative group h-full hover:bg-figmaColors-secondary-outlined-hover-background'}>
@ -71,6 +73,7 @@ function HealthStatus() {
isLoading={isLoading}
lastAsked={lastAsked}
setShowModal={setShowModal}
isError={isError}
/>
</div>
{showModal ? (

View file

@ -10,12 +10,14 @@ function HealthWidget({
isLoading,
lastAsked,
setShowModal,
isError,
}: {
healthResponse: { overallHealth: boolean; healthMap: Record<string, IServiceStats> };
getHealth: Function;
isLoading: boolean;
lastAsked: string | null;
setShowModal: (visible: boolean) => void;
isError?: boolean;
}) {
const [lastAskedDiff, setLastAskedDiff] = React.useState(0);
const healthOk = healthResponse?.overallHealth;
@ -28,8 +30,8 @@ function HealthWidget({
setLastAskedDiff(diffInMinutes);
}, [lastAsked]);
const title = healthOk ? 'All Systems Operational' : 'Service disruption';
const icon = healthOk ? ('check-circle-fill' as const) : ('exclamation-circle-fill' as const);
const title = !isError && healthOk ? 'All Systems Operational' : 'Service disruption';
const icon = !isError && healthOk ? ('check-circle-fill' as const) : ('exclamation-circle-fill' as const);
const problematicServices = Object.values(healthResponse?.healthMap || {}).filter(
(service: Record<string, any>) => !service.healthOk
@ -65,10 +67,12 @@ function HealthWidget({
<Icon name={'arrow-repeat'} size={16} color={'main'} />
</div>
</div>
{isError && <div className={'text-secondary text-sm'}>Error getting service health status</div>}
<div className={'divider w-full border border-b-light-gray'} />
<div className={'w-full'}>
{!healthOk ? (
{!isError && !healthOk ? (
<>
<div className={'text-secondary pb-2'}>
Observed installation Issue with the following

View file

@ -7,7 +7,7 @@ export interface Indexed {
}
export interface Moveable {
move(time: number, isJump?: boolean): void
move(time: number): void
}
export interface Cleanable {

View file

@ -1,4 +1,5 @@
import type { Store, Moveable, Interval } from '../common/types';
import MessageManager from 'App/player/web/MessageManager'
const fps = 60
const performance: { now: () => number } = window.performance || { now: Date.now.bind(Date) }
@ -54,18 +55,18 @@ export default class Animator {
private animationFrameRequestId: number = 0
constructor(private store: Store<GetState>, private mm: Moveable) {
constructor(private store: Store<GetState>, private mm: MessageManager) {
// @ts-ignore
window.playerJump = this.jump.bind(this)
}
private setTime(time: number, isJump?: boolean) {
private setTime(time: number) {
this.store.update({
time,
completed: false,
})
this.mm.move(time, isJump)
this.mm.move(time)
}
private startAnimation() {
@ -183,11 +184,11 @@ export default class Animator {
jump = (time: number) => {
if (this.store.get().playing) {
cancelAnimationFrame(this.animationFrameRequestId)
this.setTime(time, true)
this.setTime(time)
this.startAnimation()
this.store.update({ livePlay: time === this.store.get().endTime })
} else {
this.setTime(time, true)
this.setTime(time)
this.store.update({ livePlay: time === this.store.get().endTime })
}
}

View file

@ -289,7 +289,7 @@ export default class MessageManager {
this.activityManager = new ActivityManager(this.session.duration.milliseconds);
}
move(t: number, isJump?: boolean, index?: number): void {
move(t: number, index?: number): void {
const stateToUpdate: Partial<State> = {};
/* == REFACTOR_ME == */
const lastLoadedLocationMsg = this.loadedLocationManager.moveGetLast(t, index);
@ -339,7 +339,7 @@ export default class MessageManager {
if (!!lastResize) {
this.setSize(lastResize)
}
this.pagesManager.moveReady(t, isJump).then(() => {
this.pagesManager.moveReady(t).then(() => {
const lastScroll = this.scrollManager.moveGetLast(t, index);
if (!!lastScroll && this.screen.window) {

View file

@ -56,7 +56,7 @@ export default class WebLivePlayer extends WebPlayer {
const bytes = await requestEFSDom(this.session.sessionId)
const fileReader = new MFileReader(bytes, this.session.startedAt)
for (let msg = fileReader.readNext();msg !== null;msg = fileReader.readNext()) {
this.messageManager.distributeMessage(msg, msg._index)
this.messageManager.distributeMessage(msg)
}
this.wpState.update({
liveTimeTravel: true,

View file

@ -142,7 +142,7 @@ export default class DOMManager extends ListWalker<Message> {
private setNodeAttribute(msg: { id: number, name: string, value: string }) {
let { name, value } = msg;
const vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("SetNodeAttribute: Node not found", msg); return }
if (vn.node.tagName === "INPUT" && name === "name") {
// Otherwise binds local autocomplete values (maybe should ignore on the tracker level)
@ -169,7 +169,7 @@ export default class DOMManager extends ListWalker<Message> {
this.removeBodyScroll(msg.id, vn)
}
private applyMessage = (msg: Message, isJump?: boolean): Promise<any> | undefined => {
private applyMessage = (msg: Message): Promise<any> | undefined => {
let vn: VNode | undefined
let doc: Document | null
let styleSheet: CSSStyleSheet | PostponedStyleSheet | undefined
@ -230,14 +230,14 @@ export default class DOMManager extends ListWalker<Message> {
return
case MType.RemoveNode:
vn = this.vElements.get(msg.id) || this.vTexts.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn.parentNode) { logger.error("Parent node not found", msg); return }
if (!vn) { logger.error("RemoveNode: Node not found", msg); return }
if (!vn.parentNode) { logger.error("RemoveNode: Parent node not found", msg); return }
vn.parentNode.removeChild(vn)
this.vElements.delete(msg.id)
this.vTexts.delete(msg.id)
return
case MType.SetNodeAttribute:
if (isJump && msg.name === 'href') this.attrsBacktrack.push(msg)
if (msg.name === 'href') this.attrsBacktrack.push(msg)
else this.setNodeAttribute(msg)
return
case MType.StringDict:
@ -247,7 +247,7 @@ export default class DOMManager extends ListWalker<Message> {
this.stringDict[msg.nameKey] === undefined && logger.error("No dictionary key for msg 'name': ", msg)
this.stringDict[msg.valueKey] === undefined && logger.error("No dictionary key for msg 'value': ", msg)
if (this.stringDict[msg.nameKey] === undefined || this.stringDict[msg.valueKey] === undefined ) { return }
if (isJump && this.stringDict[msg.nameKey] === 'href') this.attrsBacktrack.push(msg)
if (this.stringDict[msg.nameKey] === 'href') this.attrsBacktrack.push(msg)
else {
this.setNodeAttribute({
id: msg.id,
@ -258,12 +258,12 @@ export default class DOMManager extends ListWalker<Message> {
return
case MType.RemoveNodeAttribute:
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("RemoveNodeAttribute: Node not found", msg); return }
vn.removeAttribute(msg.name)
return
case MType.SetInputValue:
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("SetInoputValue: Node not found", msg); return }
const nodeWithValue = vn.node
if (!(nodeWithValue instanceof HTMLInputElement
|| nodeWithValue instanceof HTMLTextAreaElement
@ -283,13 +283,13 @@ export default class DOMManager extends ListWalker<Message> {
return
case MType.SetInputChecked:
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("SetInputChecked: Node not found", msg); return }
(vn.node as HTMLInputElement).checked = msg.checked
return
case MType.SetNodeData:
case MType.SetCssData: // mbtodo: remove css transitions when timeflow is not natural (on jumps)
vn = this.vTexts.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("SetCssData: Node not found", msg); return }
vn.setData(msg.data)
if (vn.node instanceof HTMLStyleElement) {
doc = this.screen.document
@ -304,7 +304,7 @@ export default class DOMManager extends ListWalker<Message> {
// @deprecated since 4.0.2 in favor of adopted_ss_insert/delete_rule + add_owner as being common case for StyleSheets
case MType.CssInsertRule:
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("CssInsertRule: Node not found", msg); return }
if (!(vn instanceof VStyleElement)) {
logger.warn("Non-style node in CSS rules message (or sheet is null)", msg, vn);
return
@ -313,7 +313,7 @@ export default class DOMManager extends ListWalker<Message> {
return
case MType.CssDeleteRule:
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("CssDeleteRule: Node not found", msg); return }
if (!(vn instanceof VStyleElement)) {
logger.warn("Non-style node in CSS rules message (or sheet is null)", msg, vn);
return
@ -324,7 +324,7 @@ export default class DOMManager extends ListWalker<Message> {
case MType.CreateIFrameDocument:
vn = this.vElements.get(msg.frameID)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("CreateIFrameDocument: Node not found", msg); return }
vn.enforceInsertion()
const host = vn.node
if (host instanceof HTMLIFrameElement) {
@ -384,7 +384,7 @@ export default class DOMManager extends ListWalker<Message> {
if (!vn) {
// non-constructed case
vn = this.vElements.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("AdoptedSsAddOwner: Node not found", msg); return }
if (!(vn instanceof VStyleElement)) { logger.error("Non-style owner", msg); return }
this.ppStyleSheets.set(msg.sheetID, new PostponedStyleSheet(vn.node))
return
@ -411,13 +411,13 @@ export default class DOMManager extends ListWalker<Message> {
return
}
vn = this.vRoots.get(msg.id)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("AdoptedSsRemoveOwner: Node not found", msg); return }
//@ts-ignore
vn.node.adoptedStyleSheets = [...vn.node.adoptedStyleSheets].filter(s => s !== styleSheet)
return
case MType.LoadFontFace:
vn = this.vRoots.get(msg.parentID)
if (!vn) { logger.error("Node not found", msg); return }
if (!vn) { logger.error("LoadFontFace: Node not found", msg); return }
if (vn instanceof VShadowRoot) { logger.error(`Node ${vn} expected to be a Document`, msg); return }
let descr: Object
try {
@ -460,7 +460,7 @@ export default class DOMManager extends ListWalker<Message> {
}
}
async moveReady(t: number, isJump?: boolean): Promise<void> {
async moveReady(t: number): Promise<void> {
// MBTODO (back jump optimisation):
// - store intemediate virtual dom state
// - cancel previous moveReady tasks (is it possible?) if new timestamp is less
@ -474,16 +474,13 @@ export default class DOMManager extends ListWalker<Message> {
* */
// http://0.0.0.0:3333/5/session/8452905874437457
// 70 iframe, 8 create element - STYLE tag
await this.moveWait(t, (msg) => {
this.applyMessage(msg, isJump)
})
await this.moveWait(t, this.applyMessage)
this.attrsBacktrack.forEach(msg => {
this.applyBacktrack(msg)
})
this.attrsBacktrack = []
if (isJump) {
this.attrsBacktrack.forEach(msg => {
this.applyBacktrack(msg)
})
this.attrsBacktrack = []
}
this.vRoots.forEach(rt => rt.applyChanges()) // MBTODO (optimisation): affected set
// Thinkabout (read): css preload
// What if we go back before it is ready? We'll have two handlres?

View file

@ -33,14 +33,14 @@ export default class PagesManager extends ListWalker<DOMManager> {
this.forEach(page => page.sort(comparator))
}
moveReady(t: number, isJump?: boolean): Promise<void> {
moveReady(t: number): Promise<void> {
const requiredPage = this.moveGetLast(t)
if (requiredPage != null) {
this.currentPage = requiredPage
this.currentPage.reset() // Otherwise it won't apply create_document
}
if (this.currentPage != null) {
return this.currentPage.moveReady(t, isJump)
return this.currentPage.moveReady(t)
}
return Promise.resolve()
}

View file

@ -5,6 +5,5 @@ export default class HealthService extends BaseService {
return this.client.get('/health')
.then(r => r.json())
.then(j => j.data || {})
.catch(Promise.reject)
}
}