Files

97 lines
4.3 KiB
JavaScript

import { app } from '../../scripts/app.js';
import { api } from '../../scripts/api.js';
import { createScope, mountTheme } from './ui/core.js';
import { createColorPicker } from './ui/color-picker.js';
import { WorkflowClock } from './ui/workflow-clock.js';
const clock = new WorkflowClock(app.ui.settings);
let colorPicker;
app.registerExtension({
name: 'ComfyAssets.KikoWorkflowTimer',
async init() {
app.ui.settings.addSetting({
id: 'kikotools.workflow_timer.color',
name: '🫶 Workflow Timer: Color',
type: (name, setter, value) => {
if (!colorPicker || colorPicker.scope?.signal.aborted) {
colorPicker = createColorPicker(value, setter, app.ui.settings, 'Timer color');
}
colorPicker.onChange = setter;
return colorPicker;
},
defaultValue: '#0877bb',
tooltip: 'Color of the workflow timer display',
onChange: () => clock.refresh(),
});
app.ui.settings.addSetting({
id: 'kikotools.workflow_timer.glow',
name: '🫶 Workflow Timer: Enable Glow',
type: 'boolean',
defaultValue: true,
tooltip: 'Enable the pulsing glow unless reduced motion is preferred',
onChange: () => clock.refresh(),
});
},
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name !== 'KikoWorkflowTimer') return;
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const result = onNodeCreated?.apply(this, arguments);
this.timerScope = createScope();
this.properties = this.properties || {};
const container = document.createElement('div');
container.className = 'ca-tools ca-workflow-timer kiko-timer-container';
const header = document.createElement('header');
header.className = 'ca-timer-header';
const title = document.createElement('h3');
title.textContent = 'Workflow Timer';
const brand = document.createElement('span');
brand.textContent = 'ComfyAssets';
header.append(title, brand);
this.timerDisplay = document.createElement('div');
this.timerDisplay.className = 'kiko-timer-display';
this.timerDisplay.setAttribute('role', 'timer');
this.timerDisplay.setAttribute('aria-label', 'Elapsed workflow time');
this.timerDisplay.setAttribute('aria-live', 'off');
container.append(header, this.timerDisplay);
mountTheme(container, app.ui.settings, this.timerScope);
this.addDOMWidget('kikoTimer', 'Kiko Timer', container, {
serialize: false, hideOnZoom: false, getMinHeight: () => 90,
});
this.setSize([340, 180]);
clock.registerNode(this);
this.timerScope.cleanup(() => {
clock.unregisterNode(this);
container.remove();
});
return result;
};
const onRemoved = nodeType.prototype.onRemoved;
nodeType.prototype.onRemoved = function () {
this.timerScope.dispose();
return onRemoved?.apply(this, arguments);
};
const onSerialize = nodeType.prototype.onSerialize;
nodeType.prototype.onSerialize = function (data) {
const result = onSerialize?.apply(this, arguments);
data.properties = { ...data.properties, elapsed_time_str: this.properties.elapsed_time_str };
return result;
};
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function (data) {
const result = onConfigure?.apply(this, arguments);
this.properties = { ...(this.properties || {}), ...(data?.properties || {}) };
if (this.timerDisplay) clock.renderNode(this);
return result;
};
},
setup() {
api.addEventListener('execution_start', () => clock.start());
api.addEventListener('executing', ({ detail }) => { if (detail === null) clock.stop(); });
for (const event of ['execution_error', 'execution_interrupted']) api.addEventListener(event, () => clock.stop());
},
});