Add version history view for timer functions

- Implement `/history/<function_id>` route in timer routes to fetch and display function versions
- Create new Mithril `DiffView` component for comparing script versions
- Add new history template for timer functions with version comparison
- Include version diff functionality using AceDiff library
- Update header and edit templates to include history URL for timer functions
This commit is contained in:
Peter Stockings
2025-02-17 19:19:45 +11:00
parent 77957a61a3
commit 17457e492e
11 changed files with 173 additions and 11 deletions

View File

@@ -0,0 +1,94 @@
const DiffView = {
oninit: function(vnode) {
// Initialize indices in state
vnode.state.leftIndex = vnode.attrs.versions.length - 1; // Earliest
vnode.state.rightIndex = 0; // Latest
},
view: function (vnode) {
const versions = vnode.attrs.versions;
return m("div", [
m("div.flex.gap-4.mb-4", [
m("div.flex-1", [
m("label.block.text-sm.font-medium.text-gray-700", "Left Version"),
m("select.mt-1.block.w-full.rounded-md.border-gray-300.shadow-sm", {
onchange: (e) => {
vnode.state.leftIndex = parseInt(e.target.value);
vnode.state.leftVersion = versions[vnode.state.leftIndex];
vnode.state.updateDiff();
},
value: vnode.state.leftIndex
}, versions.map((v, idx) =>
m("option", { value: idx }, `Version ${v.version_number} (${new Date(v.versioned_at).toLocaleString()})`)
))
]),
m("div.flex-1", [
m("label.block.text-sm.font-medium.text-gray-700", "Right Version"),
m("select.mt-1.block.w-full.rounded-md.border-gray-300.shadow-sm", {
onchange: (e) => {
vnode.state.rightIndex = parseInt(e.target.value);
vnode.state.rightVersion = versions[vnode.state.rightIndex];
vnode.state.updateDiff();
},
value: vnode.state.rightIndex
}, versions.map((v, idx) =>
m("option", { value: idx }, `Version ${v.version_number} (${new Date(v.versioned_at).toLocaleString()})`)
))
])
]),
m("div", {
id: "diff-container",
style: "height: 500px; position: relative;"
})
]);
},
oncreate: function (vnode) {
const versions = vnode.attrs.versions;
// Initialize with the earliest and most recent versions if available
if (versions.length >= 2) {
vnode.state.leftVersion = versions[versions.length - 1]; // Earliest version
vnode.state.rightVersion = versions[0]; // Latest version
} else if (versions.length === 1) {
vnode.state.leftVersion = versions[0];
vnode.state.rightVersion = versions[0];
}
vnode.state.updateDiff = function () {
if (vnode.state.aceDiffer) {
// Clean up previous instance
vnode.state.aceDiffer.destroy();
}
vnode.state.aceDiffer = new AceDiff({
element: '#diff-container',
mode: "ace/mode/javascript",
left: {
content: vnode.state.leftVersion ? vnode.state.leftVersion.script : "",
editable: false,
},
right: {
content: vnode.state.rightVersion ? vnode.state.rightVersion.script : "",
editable: false,
}
});
// Configure both editors
const editors = vnode.state.aceDiffer.getEditors();
['left', 'right'].forEach(side => {
editors[side].setOptions({
maxLines: 20,
autoScrollEditorIntoView: true,
});
editors[side].session.setOption("useWorker", false);
});
};
// Initial diff setup
vnode.state.updateDiff();
},
onremove: function (vnode) {
// Clean up AceDiff when component is removed
if (vnode.state.aceDiffer) {
vnode.state.aceDiffer.destroy();
}
}
};