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

ts: Implement field_description the way it was intended

parent 64f16967
No related branches found
No related tags found
No related merge requests found
......@@ -175,24 +175,12 @@ export class BackendImpl {
this.fetch(
`${this.baseUrl()}/object_management/${object_type}/${object_id}/configuration`,
),
).then((res) => {
// patch object to use the expected format
res.fields = res.fields?.map((entr: any) => {
if (entr.description) {
// take all keys and values of the description and put them in the original object
Object.keys(entr.description).forEach((key) => {
entr[key] = entr.description[key];
});
}
return entr;
});
return res;
});
);
}
// GET /object_management/{object_type}/new/configuration
getNewOMConfiguration(object_type: string): Promise<GetConfigurationResponse> {
return this.processResponse<GetConfigurationResponse>(
getNewOMConfiguration(object_type: string): Promise<GetNewConfigurationResponse> {
return this.processResponse<GetNewConfigurationResponse>(
this.fetch(`${this.baseUrl()}/object_management/${object_type}/new/configuration`),
);
}
......
......@@ -286,7 +286,7 @@ export class DummyBackend {
return Promise.reject("Not implemented");
}
getNewOMConfiguration(object_type: string): Promise<GetConfigurationResponse> {
getNewOMConfiguration(object_type: string): Promise<GetNewConfigurationResponse> {
return Promise.reject("Not implemented");
}
......
......@@ -128,7 +128,7 @@ interface permission {
password?: string;
}
interface field_entry_description {
interface field_description {
id: id_string;
type: id_string;
may_be_null?: boolean;
......@@ -141,20 +141,10 @@ interface field_entry_description {
max_length?: int;
}
interface field_entry {
interface field_value {
value: any;
id: id_string;
type: id_string;
may_be_null?: boolean;
min_value?: int | long;
max_value?: int | long;
min_length?: int;
max_length?: int;
default_value?: any;
// description?: field_entry_description;
description: field_description;
}
interface changelog_entry {
......@@ -289,8 +279,8 @@ interface GetConfigurationRequest {
// Response Interface
interface GetConfigurationResponse {
permissions?: permission[];
fields?: field_entry[];
variant_fields?: { [key: string]: field_entry[] };
fields?: field_value[];
variant_fields?: { [key: string]: field_value[] };
}
/// GET /object_management/{object_type}/new/configuration
......@@ -307,8 +297,8 @@ interface GetNewConfigurationRequest {
}
// Response Interface
interface GetNewConfigurationResponse {
fields: field_entry[];
variant_fields: { [key: string]: field_entry[] };
fields: field_description[];
variant_fields: { [key: string]: field_description[] };
}
/// PUT /object_management/{object_type}/new
......
......@@ -483,7 +483,7 @@ export function LectureListItem({
let date_str = `${date_parsed.toLocaleDateString([], { weekday: "short", year: "numeric", month: "2-digit", day: "2-digit" })}, ${date_parsed.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}`;
let content = <></>;
if (lecture.thumbnail_url || (lecture.media_sources && lecture.media_sources.length > 0)) {
if (lecture.media_sources && lecture.media_sources.length > 0) {
let thumbUrl = lecture.thumbnail_url ?? `${api.assetUrl()}/thumbnail/l_${lecture.id}.jpg`;
content = (
......
......@@ -13,35 +13,41 @@ interface SimpleOMPatch {
export function OMFieldComponent({
object_type,
field,
field_desc,
field_value,
patch,
patchNotify,
hideLabel = false,
...props
}: {
object_type: string;
field: field_entry;
field_value?: any;
field_desc: field_description;
patch: MutableRefObject<SimpleOMPatch>;
patchNotify: () => void;
hideLabel?: boolean;
[key: string]: any;
}) {
const [val, setVal] = useState(field.value ?? field.default_value);
const [val, setVal] = useState(field_value ?? field_desc.default_value);
const language = useLanguage();
const hasChanged = val !== (field.value ?? field.default_value) && val !== "unchosen";
const hasChanged = val !== (field_value ?? field_desc.default_value) && val !== "unchosen";
if (field.default_value !== undefined && patch.current[field.id] === undefined) {
patch.current[field.id] = field.default_value;
if (
field_value === undefined &&
field_desc.default_value !== undefined &&
patch.current[field_desc.id] === undefined
) {
patch.current[field_desc.id] = field_desc.default_value;
}
useEffect(() => {
if (hasChanged) {
setVal(field.value ?? field.default_value);
patch.current[field.id] = field.value ?? field.default_value;
setVal(field_value ?? field_desc.default_value);
patch.current[field_desc.id] = field_value ?? field_desc.default_value;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [field.value, field.default_value]);
}, [field_value, field_desc.default_value]);
let inpElement = <></>;
......@@ -54,7 +60,7 @@ export function OMFieldComponent({
className="form-select"
value={val ?? "unchosen"}
onChange={(e) => {
patch.current[field.id] = e.target.value;
patch.current[field_desc.id] = e.target.value;
patchNotify();
setVal(e.target.value);
}}
......@@ -73,13 +79,13 @@ export function OMFieldComponent({
};
let resetElement = <></>;
if (field.may_be_null === true) {
if (field_desc.may_be_null === true) {
resetElement = (
<button
type="button"
className="ms-2 btn btn-outline-danger"
onClick={() => {
patch.current[field.id] = null;
patch.current[field_desc.id] = null;
setVal(undefined);
patchNotify();
}}
......@@ -90,17 +96,17 @@ export function OMFieldComponent({
);
}
switch (field.type) {
switch (field_desc.type) {
case "lecture_id":
case "course_id_string":
case "semester_string":
case "string":
const onChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
patch.current[field.id] = e.target.value;
patch.current[field_desc.id] = e.target.value;
patchNotify();
setVal(e.target.value);
};
if (field.max_length && field.max_length < 300)
if (field_desc.max_length && field_desc.max_length < 300)
inpElement = (
<input
className="flex-fill"
......@@ -132,7 +138,7 @@ export function OMFieldComponent({
type="checkbox"
checked={val ?? false}
onChange={(e) => {
patch.current[field.id] = e.target.checked;
patch.current[field_desc.id] = e.target.checked;
patchNotify();
setVal(e.target.checked);
}}
......@@ -147,7 +153,7 @@ export function OMFieldComponent({
type="number"
value={val ?? 0}
onChange={(e) => {
patch.current[field.id] = parseInt(e.target.value);
patch.current[field_desc.id] = parseInt(e.target.value);
patchNotify();
setVal(e.target.value);
}}
......@@ -164,8 +170,8 @@ export function OMFieldComponent({
const date = new Date(e.target.value);
// YYYY-MM-ddTHH:mm:ss, surely this will never stop working in the future
// TODO: fix
patch.current[field.id] = date.toISOString().slice(0, 19);
console.log(patch.current[field.id]);
patch.current[field_desc.id] = date.toISOString().slice(0, 19);
console.log(patch.current[field_desc.id]);
patchNotify();
setVal(e.target.value);
}}
......@@ -192,12 +198,14 @@ export function OMFieldComponent({
break;
default:
if (hideLabel)
throw new Error(`TODO: Field type not implemented for hideLabel: ${field.type}`);
throw new Error(
`TODO: Field type not implemented for hideLabel: ${field_desc.type}`,
);
return (
<tr {...props}>
<td>{!hideLabel && `${field.id}(${field.type}): `}</td>
<td>{!hideLabel && `${field_desc.id}(${field_desc.type}): `}</td>
<td>
<small className="text-info">{JSON.stringify(field.value)}</small>
<small className="text-info">{JSON.stringify(field_value)}</small>
</td>
</tr>
);
......@@ -225,7 +233,7 @@ export function OMFieldComponent({
style={{ color: "orange", width: "4px" }}
/>
{!hideLabel && (
<div className="me-2">{`${language.getObjectField(object_type, field.id)}: `}</div>
<div className="me-2">{`${language.getObjectField(object_type, field_desc.id)}: `}</div>
)}
</div>
</td>
......@@ -258,13 +266,15 @@ export function OMPermissionComponent({ perm }: { perm: permission }) {
export function StandaloneOMFieldComponent({
object_type,
object_id,
field,
field_desc,
field_value,
debounce_ms,
...props
}: {
object_type: string;
object_id: int;
field: field_entry;
field_desc: field_description;
field_value: any;
debounce_ms?: number;
[key: string]: any;
}) {
......@@ -272,7 +282,7 @@ export function StandaloneOMFieldComponent({
const reloadFunc = useReloadBoundary();
const patch = useRef<SimpleOMPatch>({});
if (field.type === "boolean" && debounce_ms === undefined) debounce_ms = 0;
if (field_desc.type === "boolean" && debounce_ms === undefined) debounce_ms = 0;
const { deferred } = useDebounce(() => {
if (Object.keys(patch.current).length === 0) {
......@@ -288,7 +298,8 @@ export function StandaloneOMFieldComponent({
return (
<OMFieldComponent
object_type={object_type}
field={field}
field_desc={field_desc}
field_value={field_value}
patch={patch}
patchNotify={deferred}
hideLabel
......@@ -333,7 +344,7 @@ export function StandaloneOMStringComponent({
});
}, [api, isEditing, object_id, object_type, forceReload]);
const confField = conf.fields?.find((field) => field.id === field_id);
const confField = conf.fields?.find((field) => field.description.id === field_id);
const { deferred, now } = useDebounce(
() => {
......@@ -351,7 +362,7 @@ export function StandaloneOMStringComponent({
return false;
});
},
confField?.type == "boolean" ? 0 : 800,
confField?.description.type == "boolean" ? 0 : 800,
);
const disableEditing = () => {
......@@ -385,7 +396,8 @@ export function StandaloneOMStringComponent({
<div className={className}>
<OMFieldComponent
object_type={object_type}
field={confField}
field_desc={confField.description}
field_value={confField.value}
patch={patch}
patchNotify={deferred}
hideLabel
......@@ -515,9 +527,19 @@ export function OMEdit({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [api, object_type, object_id, showModal, refresh]);
const hasAnyChanges = conf.fields?.some(
(field) => patch.current[field.id] !== undefined && patch.current[field.id] !== field.value,
const hasAnyChanges = conf.fields?.some((field) => {
const val =
patch.current[field.description.id] !== undefined &&
patch.current[field.description.id] !== field.value;
if (val)
console.log(
field.description.id,
patch.current[field.description.id],
field.value,
val,
);
return val;
});
const saveChanges = () => {
if (!hasAnyChanges) {
......@@ -574,8 +596,9 @@ export function OMEdit({
{conf.fields?.map((field) => (
<OMFieldComponent
object_type={object_type}
key={field.id}
field={field}
key={field.description.id}
field_desc={field.description}
field_value={field.value}
patch={patch}
patchNotify={() => setPatchNotify(patchNotify + 1)}
/>
......@@ -676,7 +699,7 @@ export function OMCreate({
}) {
const api = useBackendContext();
const [showModal, setShowModal] = useState(false);
const [confData, setConfData] = useState<GetConfigurationResponse>();
const [confData, setConfData] = useState<GetNewConfigurationResponse>();
const [chosenVariant, setChosenVariant] = useState<string>();
const corePatch = useRef<SimpleOMPatch>({});
const variantPatch = useRef<SimpleOMPatch>({});
......@@ -743,13 +766,13 @@ export function OMCreate({
confData?.fields?.some(
(field) =>
corePatch.current[field.id] !== undefined &&
corePatch.current[field.id] !== (field.value ?? field.default_value),
corePatch.current[field.id] !== field.default_value,
) ||
(chosenVariant &&
confData?.variant_fields?.[chosenVariant]?.some(
(field) =>
variantPatch.current[field.id] !== undefined &&
variantPatch.current[field.id] !== (field.value ?? field.default_value),
variantPatch.current[field.id] !== field.default_value,
));
if (!hasAnyChanges || confirm("Do you want to discard your changes?")) {
......@@ -788,7 +811,7 @@ export function OMCreate({
<OMFieldComponent
object_type={object_type}
key={field.id}
field={field}
field_desc={field}
patch={corePatch}
patchNotify={() => {}}
/>
......@@ -812,7 +835,7 @@ export function OMCreate({
<OMFieldComponent
object_type={object_type}
key={field.id}
field={field}
field_desc={field}
patch={corePatch}
patchNotify={() => {}}
/>
......@@ -845,7 +868,7 @@ export function OMCreate({
<OMFieldComponent
object_type={object_type}
key={field.id}
field={field}
field_desc={field}
patch={variantPatch}
patchNotify={() => {}}
/>
......
......@@ -468,12 +468,12 @@ function Chapters({ chapters, seekTo }: { chapters?: chapter[]; seekTo: (time: n
<StandaloneOMFieldComponent
object_type="chapter"
object_id={c.id!}
field={{
field_desc={{
id: "is_visible",
type: "boolean",
value: c.is_visible,
is_modifiable: true,
}}
field_value={c.is_visible}
className="me-2"
/>
<OMDelete object_type="chapter" object_id={c.id!} />
......@@ -531,13 +531,6 @@ export function DownloadSources({
let bgColor = "";
if (v.is_visible === false) bgColor = "bg-danger-subtle";
let isVisibleField: field_entry = {
id: "is_visible",
type: "boolean",
value: v.is_visible,
};
return (
<li key={ind + "#" + v.quality.name} className={"d-flex " + bgColor}>
<a className="dropdown-item" href={v.download_url} download>
......@@ -548,7 +541,12 @@ export function DownloadSources({
<StandaloneOMFieldComponent
object_type="media_source"
object_id={v.id!}
field={isVisibleField}
field_desc={{
id: "is_visible",
type: "boolean",
is_modifiable: true,
}}
field_value={v.is_visible}
className="me-2"
/>
<OMDelete object_type="media_source" object_id={v.id!} />
......
......@@ -89,12 +89,12 @@ function FeatureCard({ data, all_featured }: { data: featured; all_featured: fea
<StandaloneOMFieldComponent
object_type="featured"
object_id={data.id!}
field={{
field_desc={{
id: "is_visible",
type: "boolean",
value: data.is_visible,
is_modifiable: true,
}}
field_value={data.is_visible}
/>
)}
<div className="flex-fill" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment