Update function history view

This commit is contained in:
Peter Stockings
2025-07-24 23:00:22 +10:00
parent 54347ded89
commit 8f2838f920
7 changed files with 378 additions and 190 deletions

View File

@@ -1,96 +1,170 @@
const FunctionHistory = {
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];
}
oninit: function (vnode) {
const versions = vnode.attrs.versions;
vnode.state.mode = "view"; // 'view' or 'diff'
vnode.state.selectedVersion = versions[0];
vnode.state.leftVersion = versions.length > 1 ? versions[1] : versions[0];
vnode.state.rightVersion = versions[0];
vnode.state.editor = null;
vnode.state.aceDiffer = null;
},
vnode.state.updateDiff = function () {
if (vnode.state.aceDiffer) {
// Clean up previous instance
vnode.state.aceDiffer.destroy();
}
view: function (vnode) {
const { versions } = vnode.attrs;
const { mode, selectedVersion, leftVersion, rightVersion } = vnode.state;
vnode.state.aceDiffer = new AceDiff({
element: '#diff-container',
mode: "ace/mode/javascript",
left: {
content: vnode.state.leftVersion ? vnode.state.leftVersion.script : "",
editable: false,
return m(".flex.flex-col.md:flex-row.h-full", [
// Vertical Timeline
m(".w-full.md:w-64.border-b.md:border-r.md:border-b-0.overflow-y-auto", [
m("div.p-4.border-b.flex.justify-between.items-center", [
m("h3.text-lg.font-semibold", "History"),
m(
"button.text-sm.bg-gray-200.hover:bg-gray-300.text-gray-800.font-semibold.py-1.px-2.rounded",
{
onclick: () => {
vnode.state.mode = mode === "view" ? "diff" : "view";
},
},
mode === "view" ? "Compare" : "View"
),
]),
m(
"ul.p-2",
versions.map((version) => {
const isActive =
selectedVersion &&
version.version_number === selectedVersion.version_number;
return m(
"li.p-2.cursor-pointer",
{
class: isActive
? "bg-gray-200 rounded"
: "hover:bg-gray-100 rounded",
onclick: () => {
vnode.state.selectedVersion = version;
if (mode === "diff") {
vnode.state.rightVersion = version;
}
},
right: {
content: vnode.state.rightVersion ? vnode.state.rightVersion.script : "",
editable: false,
}
});
},
[
m("div.font-bold", `Version ${version.version_number}`),
m(
"div.text-sm.text-gray-600",
new Date(version.versioned_at).toLocaleString()
),
]
);
})
),
]),
// 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);
});
};
// Code Viewer or Differ
m(".flex-1.p-4", [
mode === "view"
? m("div", [
m(
"h3.text-lg.font-semibold.mb-2",
`Version ${selectedVersion.version_number}`
),
m("div#editor-history", { style: "height: 600px;" }),
])
: m("div", [
m(".flex.flex-col.md:flex-row.gap-4.mb-4", [
m(".flex-1", [
m("label.block.text-sm.font-medium.text-gray-700", "Left"),
m(
"select.mt-1.block.w-full.rounded-md.border-gray-300.shadow-sm",
{
onchange: (e) =>
(vnode.state.leftVersion = versions.find(
(v) => v.version_number == e.target.value
)),
value: leftVersion.version_number,
},
versions.map((v) =>
m(
"option",
{ value: v.version_number },
`Version ${v.version_number}`
)
)
),
]),
m(".flex-1", [
m("label.block.text-sm.font-medium.text-gray-700", "Right"),
m(
"select.mt-1.block.w-full.rounded-md.border-gray-300.shadow-sm",
{
onchange: (e) =>
(vnode.state.rightVersion = versions.find(
(v) => v.version_number == e.target.value
)),
value: rightVersion.version_number,
},
versions.map((v) =>
m(
"option",
{ value: v.version_number },
`Version ${v.version_number}`
)
)
),
]),
]),
m("#diff-container", { style: "height: 600px;" }),
]),
]),
]);
},
// Initial diff setup
vnode.state.updateDiff();
},
onremove: function (vnode) {
// Clean up AceDiff when component is removed
if (vnode.state.aceDiffer) {
vnode.state.aceDiffer.destroy();
}
oncreate: function (vnode) {
this.updateEditorOrDiffer(vnode);
},
onupdate: function (vnode) {
this.updateEditorOrDiffer(vnode);
},
updateEditorOrDiffer: function (vnode) {
const { mode, selectedVersion, leftVersion, rightVersion } = vnode.state;
if (mode === "view") {
if (vnode.state.aceDiffer) {
vnode.state.aceDiffer.destroy();
vnode.state.aceDiffer = null;
}
if (!vnode.state.editor) {
vnode.state.editor = ace.edit("editor-history");
vnode.state.editor.setTheme("ace/theme/monokai");
vnode.state.editor.session.setMode("ace/mode/javascript");
vnode.state.editor.setReadOnly(true);
}
vnode.state.editor.setValue(selectedVersion.script, -1);
} else {
// diff mode
if (vnode.state.editor) {
vnode.state.editor.destroy();
vnode.state.editor = null;
}
if (vnode.state.aceDiffer) {
vnode.state.aceDiffer.destroy();
}
vnode.state.aceDiffer = new AceDiff({
element: "#diff-container",
mode: "ace/mode/javascript",
left: { content: leftVersion.script, editable: false },
right: { content: rightVersion.script, editable: false },
});
}
};
},
export default FunctionHistory;
onremove: function (vnode) {
if (vnode.state.editor) {
vnode.state.editor.destroy();
}
if (vnode.state.aceDiffer) {
vnode.state.aceDiffer.destroy();
}
},
};

View File

@@ -1,94 +1,118 @@
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();
}
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();
}
},
};