Skip to content
Snippets Groups Projects
Verified Commit aa789863 authored by Dorian Koch's avatar Dorian Koch
Browse files

More changelog improvements, closes #12

parent cdfd1821
No related branches found
No related tags found
No related merge requests found
Pipeline #6421 failed
......@@ -7,7 +7,262 @@ import { useFilteredDataView, PagingNavigation, FilterInput } from "@/components
import { DateTime } from "luxon";
import { showError, ErrorPage } from "@/misc/ErrorHandlers";
import type { GetChangelogResponse, int } from "@/api/api_v1_types";
import type { changelog_entry, GetChangelogResponse, int } from "@/api/api_v1_types";
import { useEffect, useState } from "react";
function ValToStr({ val }: { val: any }) {
const [expand, setExpand] = useState(false);
if (val === null) {
return <span className="fst-italic text-muted">null</span>;
}
if (val === undefined) {
return <span className="fst-italic text-muted">undefined</span>;
}
const stringifiedVal = JSON.stringify(val);
if (stringifiedVal.length > 100) {
if (!expand) {
return (
<span>
{stringifiedVal.substring(0, 100)}
<button
type="button"
className="btn btn-link p-0 align-baseline text-decoration-underline"
onClick={(e) => {
setExpand(true);
}}
>
...
</button>
</span>
);
}
return (
<span>
{stringifiedVal} <br />
<button
type="button"
className="btn btn-secondary btn-sm"
onClick={(e) => {
setExpand(false);
}}
>
Hide
</button>
</span>
);
}
return stringifiedVal;
}
function Modification({
i,
filterLevel,
formattedDate,
resolveUser,
}: {
i: changelog_entry;
filterLevel: (lvl: number) => () => void;
formattedDate: string;
resolveUser: (id: number) => string;
}) {
const reloadFunc = useReloadBoundary();
const api = useBackendContext();
const undo = () => {
if (i.type !== "modification") {
alert("TODO: Not implemented");
return;
}
if (!confirm("Wirklich zurücksetzen?")) {
return;
}
let updates: { [key: string]: any } = {};
updates[i.field_description!.id] = i.old_value;
api.updateOMObject(i.object_type!, i.object_id!, {
updates: updates,
expected_current_values: {}, //TODO have something here?
})
.then(reloadFunc)
.catch((e) => {
showError(e, "Exception while reverting change");
});
};
return (
<tr key={i.id}>
<td>{formattedDate}</td>
<td>{resolveUser(i.modifying_user_id)}</td>
<td>{i.type}</td>
<td>
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(1)}
>
{`${i.object_type}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(2)}
>
{`${i.object_id}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(3)}
>{`${i.field_description!.id}`}</button>
{` (${i.field_description?.type})`}
</td>
<td>
<ValToStr val={i.old_value} />
</td>
<td>
<ValToStr val={i.new_value} />
</td>
<td>
<button className="btn btn-warning" onClick={undo}>
revert to old
</button>
</td>
</tr>
);
}
function DeletionChange({
i,
filterLevel,
formattedDate,
resolveUser,
}: {
i: changelog_entry;
filterLevel: (lvl: number) => () => void;
formattedDate: string;
resolveUser: (id: number) => string;
}) {
const reloadFunc = useReloadBoundary();
const api = useBackendContext();
const undelete = () => {
if (i.type !== "deletion_change" || i.is_now_deleted === false) {
alert("invalid action!");
return;
}
if (!confirm("Wirklich wiederherstellen?")) {
return;
}
api.resurrectOMObject(i.object_type!, i.object_id!)
.then(reloadFunc)
.catch((e) => {
showError(e, "Exception while reverting change");
});
};
return (
<tr key={i.id}>
<td>{formattedDate}</td>
<td>{resolveUser(i.modifying_user_id)}</td>
<td>{i.type}</td>
<td>
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(1)}
>
{`${i.object_type}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(2)}
>
{`${i.object_id}`}
</button>
</td>
{i.is_now_deleted ? (
<>
<td>
<span className="fst-italic text-muted">not deleted</span>
</td>
<td>
<span className="fst-italic text-danger">deleted</span>
</td>
</>
) : (
<>
<td>
<span className="fst-italic text-danger">deleted</span>
</td>
<td>
<span className="fst-italic text-muted">not deleted</span>
</td>
</>
)}
<td>
{i.is_now_deleted === true && (
<button className="btn btn-warning" onClick={undelete}>
undelete
</button>
)}
</td>
</tr>
);
}
function Creation({
i,
filterLevel,
formattedDate,
resolveUser,
}: {
i: changelog_entry;
filterLevel: (lvl: number) => () => void;
formattedDate: string;
resolveUser: (id: number) => string;
}) {
const reloadFunc = useReloadBoundary();
const api = useBackendContext();
return (
<tr key={i.id}>
<td>{formattedDate}</td>
<td>{resolveUser(i.modifying_user_id)}</td>
<td>{i.type}</td>
<td>
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(1)}
>
{`${i.object_type}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(2)}
>
{`${i.object_id}`}
</button>
{typeof i.variant === "string" && ` (variant:${i.variant})`}
</td>
<td>
<ValToStr val={i.old_value} />
</td>
<td>
<ValToStr val={i.new_value} />
</td>
<td></td>
</tr>
);
}
function ChangelogList({
changelog,
......@@ -21,8 +276,25 @@ function ChangelogList({
updateNow: boolean,
) => void;
}) {
const reloadFunc = useReloadBoundary();
const api = useBackendContext();
const [usersData, setUsersData] = useState<{ [key: number]: string }>({});
useEffect(() => {
api.getUsers().then((data) => {
let users: { [key: number]: string } = {};
data.users.forEach((u) => {
users[u.id] = u.name;
});
setUsersData(users);
});
}, [api]);
const resolveUser = (id: number) => {
if (usersData[id]) {
return `${usersData[id]} (${id})`;
}
return id + "";
};
return (
<>
......@@ -76,79 +348,38 @@ function ChangelogList({
};
};
let pfad = <></>;
const formattedDate = DateTime.fromISO(i.change_time).toFormat(
"yyyy-MM-dd HH:mm:ss",
);
switch (i.type) {
case "modification":
pfad = (
<>
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(1)}
>
{`${i.object_type}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(2)}
>
{`${i.object_id}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(3)}
>{`${i.field_description!.id}`}</button>
{` (${i.field_description?.type})`}
</>
return (
<Modification
i={i}
filterLevel={filterLevel}
formattedDate={formattedDate}
resolveUser={resolveUser}
/>
);
break;
case "creation":
pfad = (
<>
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(1)}
>
{`${i.object_type}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(2)}
>
{`${i.object_id}`}
</button>
{typeof i.variant === "string" &&
` (variant:${i.variant})`}
</>
return (
<Creation
i={i}
filterLevel={filterLevel}
formattedDate={formattedDate}
resolveUser={resolveUser}
/>
);
break;
case "deletion_change":
pfad = (
<>
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(1)}
>
{`${i.object_type}`}
</button>
.
<button
type="button"
className="btn btn-link p-0 align-baseline"
onClick={filterLevel(2)}
>
{`${i.object_id}`}
</button>
</>
return (
<DeletionChange
i={i}
filterLevel={filterLevel}
formattedDate={formattedDate}
resolveUser={resolveUser}
/>
);
break;
case "unknown":
pfad = (
<>{`${i.unknown_type}.${i.unknown_field}, id=${i.object_id}`}</>
......@@ -157,53 +388,20 @@ function ChangelogList({
default:
pfad = <>{i.type}</>;
}
const valToStr = (val: any) => {
if (val === null) {
return <span className="fst-italic text-muted">null</span>;
}
if (val === undefined) {
return <span className="fst-italic text-muted">undefined</span>;
}
return JSON.stringify(val);
};
const formattedDate = DateTime.fromISO(i.change_time).toFormat(
"yyyy-MM-dd HH:mm:ss",
);
const undo = () => {
if (i.type !== "modification") {
alert("TODO: Not implemented");
return;
}
if (!confirm("Wirklich zurücksetzen?")) {
return;
}
let updates: { [key: string]: any } = {};
updates[i.field_description!.id] = i.old_value;
api.updateOMObject(i.object_type!, i.object_id!, {
updates: updates,
expected_current_values: {}, //TODO have something here?
})
.then(reloadFunc)
.catch((e) => {
showError(e, "Exception while reverting change");
});
};
return (
<tr key={i.id}>
<td>{formattedDate}</td>
<td>{i.modifying_user_id}</td>
<td>{resolveUser(i.modifying_user_id)}</td>
<td>{i.type}</td>
<td>{pfad}</td>
<td>{valToStr(i.old_value)}</td>
<td>{valToStr(i.new_value)}</td>
<td>
{i.type === "modification" && (
<button className="btn btn-warning" onClick={undo}>
revert to old
</button>
)}
<ValToStr val={i.old_value} />
</td>
<td>
<ValToStr val={i.new_value} />
</td>
<td></td>
</tr>
);
})}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment