Files
function/static/js/mithril/FunctionHistory.js

190 lines
7.0 KiB
JavaScript

const FunctionHistory = {
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;
// Listen for theme changes
vnode.state.themeListener = (e) => {
const newTheme = e.detail.theme;
const aceTheme = newTheme === 'dark' ? "ace/theme/monokai" : "ace/theme/chrome";
if (vnode.state.editor) {
vnode.state.editor.setTheme(aceTheme);
}
// Note: AceDiff might need a full re-init to change theme properly, or we can just let it be
};
window.addEventListener('themeChanged', vnode.state.themeListener);
},
view: function (vnode) {
const { versions } = vnode.attrs;
const { mode, selectedVersion, leftVersion, rightVersion } = vnode.state;
return m(".flex.flex-col.md:flex-row.h-full.bg-white.dark:bg-gray-900.text-gray-900.dark:text-white", [
// Vertical Timeline
m(".w-full.md:w-64.border-b.md:border-r.md:border-b-0.border-gray-200.dark:border-gray-700.overflow-y-auto.bg-gray-50.dark:bg-gray-800", [
m("div.p-4.border-b.border-gray-200.dark:border-gray-700.flex.justify-between.items-center", [
m("h3.text-lg.font-semibold", "History"),
m(
"button.text-sm.bg-gray-200.hover:bg-gray-300.dark:bg-gray-700.dark:hover:bg-gray-600.text-gray-800.dark:text-gray-200.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.mb-1",
{
class: isActive
? "bg-blue-100 dark:bg-blue-900/50 rounded"
: "hover:bg-gray-200 dark:hover:bg-gray-700 rounded",
onclick: () => {
vnode.state.selectedVersion = version;
if (mode === "diff") {
vnode.state.rightVersion = version;
}
},
},
[
m("div.font-bold", `Version ${version.version_number}`),
m(
"div.text-sm.text-gray-600.dark:text-gray-400",
new Date(version.versioned_at).toLocaleString()
),
]
);
})
),
]),
// Code Viewer or Differ
m(".flex-1.p-4.bg-white.dark:bg-gray-900", [
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.dark:text-gray-300", "Left"),
m(
"select.mt-1.block.w-full.rounded-md.border-gray-300.dark:border-gray-600.shadow-sm.bg-white.dark:bg-gray-700.text-gray-900.dark:text-white",
{
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.dark:text-gray-300", "Right"),
m(
"select.mt-1.block.w-full.rounded-md.border-gray-300.dark:border-gray-600.shadow-sm.bg-white.dark:bg-gray-700.text-gray-900.dark:text-white",
{
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;" }),
]),
]),
]);
},
oncreate: function (vnode) {
this.updateEditorOrDiffer(vnode);
},
onupdate: function (vnode) {
this.updateEditorOrDiffer(vnode);
},
updateEditorOrDiffer: function (vnode) {
const { mode, selectedVersion, leftVersion, rightVersion } = vnode.state;
const isDark = document.documentElement.classList.contains('dark');
const theme = isDark ? "ace/theme/monokai" : "ace/theme/chrome";
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(theme);
vnode.state.editor.session.setMode("ace/mode/javascript");
vnode.state.editor.setReadOnly(true);
} else {
vnode.state.editor.setTheme(theme);
}
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",
theme: theme,
left: { content: leftVersion.script, editable: false },
right: { content: rightVersion.script, editable: false },
});
}
},
onremove: function (vnode) {
if (vnode.state.editor) {
vnode.state.editor.destroy();
}
if (vnode.state.aceDiffer) {
vnode.state.aceDiffer.destroy();
}
if (vnode.state.themeListener) {
window.removeEventListener('themeChanged', vnode.state.themeListener);
}
},
};