tsondb 0.5.8 → 0.5.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/bin/tsondb.d.ts +1 -9
- package/dist/src/bin/tsondb.js +7 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/node/index.d.ts +2 -2
- package/dist/src/node/index.js +8 -2
- package/dist/src/node/renderers/jsonschema/index.d.ts +1 -1
- package/dist/src/node/renderers/ts/index.d.ts +1 -1
- package/dist/src/node/{Schema.d.ts → schema/Schema.d.ts} +2 -2
- package/dist/src/node/{Schema.js → schema/Schema.js} +10 -7
- package/dist/src/node/schema/declarations/EntityDecl.d.ts +31 -30
- package/dist/src/node/schema/declarations/EntityDecl.js +1 -0
- package/dist/src/node/server/api/declarations.js +3 -4
- package/dist/src/node/server/api/git.js +1 -2
- package/dist/src/node/server/api/instances.js +2 -3
- package/dist/src/node/server/index.d.ts +7 -2
- package/dist/src/node/server/index.js +10 -10
- package/dist/src/node/server/init.d.ts +1 -1
- package/dist/src/node/server/init.js +10 -0
- package/dist/src/node/utils/displayName.d.ts +3 -0
- package/dist/src/node/utils/displayName.js +19 -0
- package/dist/src/shared/config.d.ts +11 -0
- package/dist/src/{node/renderers/Output.d.ts → shared/output.d.ts} +1 -1
- package/dist/src/shared/output.js +1 -0
- package/dist/src/shared/utils/compare.js +6 -1
- package/dist/src/shared/utils/displayName.d.ts +1 -1
- package/dist/src/shared/utils/displayName.js +1 -1
- package/dist/src/shared/utils/instances.d.ts +3 -2
- package/dist/src/shared/utils/instances.js +3 -3
- package/dist/src/shared/utils/markdown.js +1 -1
- package/dist/src/web/components/Git.js +1 -1
- package/dist/src/web/components/typeInputs/ArrayTypeInput.js +4 -4
- package/dist/src/web/components/typeInputs/NestedEntityMapTypeInput.js +16 -11
- package/dist/src/web/components/typeInputs/ObjectTypeInput.js +3 -3
- package/dist/src/web/components/typeInputs/ReferenceIdentifierTypeInput.js +1 -1
- package/dist/src/web/components/typeInputs/StringTypeInput.js +7 -3
- package/dist/src/web/components/typeInputs/TypeInput.d.ts +2 -2
- package/dist/src/web/components/typeInputs/TypeInput.js +5 -1
- package/dist/src/web/hooks/useInstanceNamesByEntity.d.ts +1 -1
- package/dist/src/web/hooks/useInstanceNamesByEntity.js +1 -1
- package/dist/src/web/hooks/useSecondaryDeclarations.d.ts +1 -1
- package/dist/src/web/hooks/useSecondaryDeclarations.js +3 -3
- package/dist/src/web/routes/CreateInstance.js +26 -12
- package/dist/src/web/routes/Entity.js +27 -13
- package/dist/src/web/routes/Home.js +15 -1
- package/dist/src/web/routes/Instance.js +26 -12
- package/dist/src/web/routes/NotFound.js +4 -0
- package/package.json +6 -6
- package/public/css/styles.css +128 -34
- /package/dist/src/{node/renderers/Output.js → shared/config.js} +0 -0
|
@@ -5,9 +5,13 @@ import { ValidationErrors } from "./utils/ValidationErrors.js";
|
|
|
5
5
|
export const StringTypeInput = ({ type, value, onChange }) => {
|
|
6
6
|
const { minLength, maxLength, pattern, isMarkdown } = type;
|
|
7
7
|
const errors = validateStringConstraints(type, value);
|
|
8
|
-
return (_jsx("div", { class: "field field--string", children: isMarkdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "editor", children: [_jsx("textarea", { value: value, minLength: minLength, maxLength: maxLength, onInput: event => {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
return (_jsx("div", { class: "field field--string", children: isMarkdown ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "editor", children: [_jsx("div", { class: "textarea-grow-wrap", "data-value": value, children: _jsx("textarea", { value: value, minLength: minLength, maxLength: maxLength, onInput: event => {
|
|
9
|
+
onChange(event.currentTarget.value);
|
|
10
|
+
}, "aria-invalid": errors.length > 0 }) }), _jsx(ValidationErrors, { errors: errors })] }), _jsx("div", { className: "preview", children: _jsx(Markdown, { string: value }) })] })) : (_jsxs("div", { className: "editor", children: [_jsx("input", { type: "text", value: value, minLength: minLength, maxLength: maxLength, pattern: pattern === undefined
|
|
11
|
+
? undefined
|
|
12
|
+
: pattern.startsWith("^(?:") && pattern.endsWith(")$")
|
|
13
|
+
? pattern.slice(4, -2)
|
|
14
|
+
: `.*${pattern}.*`, onInput: event => {
|
|
11
15
|
onChange(event.currentTarget.value);
|
|
12
16
|
}, "aria-invalid": errors.length > 0 }), _jsx(ValidationErrors, { errors: errors })] })) }));
|
|
13
17
|
};
|
|
@@ -9,5 +9,5 @@ type Props = {
|
|
|
9
9
|
getDeclFromDeclName: GetDeclFromDeclName;
|
|
10
10
|
onChange: (value: unknown) => void;
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
export {};
|
|
12
|
+
declare const MemoizedTypeInput: FunctionComponent<Props>;
|
|
13
|
+
export { MemoizedTypeInput as TypeInput };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "preact/jsx-runtime";
|
|
2
|
+
import { memo } from "preact/compat";
|
|
3
|
+
import { deepEqual } from "../../../shared/utils/compare.js";
|
|
2
4
|
import { assertExhaustive } from "../../../shared/utils/typeSafety.js";
|
|
3
5
|
import { ArrayTypeInput } from "./ArrayTypeInput.js";
|
|
4
6
|
import { BooleanTypeInput } from "./BooleanTypeInput.js";
|
|
@@ -13,7 +15,7 @@ import { ObjectTypeInput } from "./ObjectTypeInput.js";
|
|
|
13
15
|
import { ReferenceIdentifierTypeInput } from "./ReferenceIdentifierTypeInput.js";
|
|
14
16
|
import { StringTypeInput } from "./StringTypeInput.js";
|
|
15
17
|
import { MismatchingTypeError } from "./utils/MismatchingTypeError.js";
|
|
16
|
-
|
|
18
|
+
const TypeInput = ({ type, value, instanceNamesByEntity, getDeclFromDeclName, onChange, }) => {
|
|
17
19
|
switch (type.kind) {
|
|
18
20
|
case "BooleanType":
|
|
19
21
|
if (typeof value === "boolean") {
|
|
@@ -88,3 +90,5 @@ export const TypeInput = ({ type, value, instanceNamesByEntity, getDeclFromDeclN
|
|
|
88
90
|
return assertExhaustive(type);
|
|
89
91
|
}
|
|
90
92
|
};
|
|
93
|
+
const MemoizedTypeInput = memo(TypeInput, (prevProps, nextProps) => deepEqual(prevProps.value, nextProps.value));
|
|
94
|
+
export { MemoizedTypeInput as TypeInput };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { GetAllInstancesResponseBody } from "../../shared/api.ts";
|
|
2
2
|
export type InstanceNamesByEntity = GetAllInstancesResponseBody["instances"];
|
|
3
|
-
export declare const useInstanceNamesByEntity: (locales?: string[]) => [InstanceNamesByEntity, () => void];
|
|
3
|
+
export declare const useInstanceNamesByEntity: (locales?: string[]) => [InstanceNamesByEntity | undefined, () => void];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from "preact/hooks";
|
|
2
2
|
import { getAllInstances } from "../api.js";
|
|
3
3
|
export const useInstanceNamesByEntity = (locales = []) => {
|
|
4
|
-
const [instanceNamesByEntity, setInstanceNamesByEntity] = useState(
|
|
4
|
+
const [instanceNamesByEntity, setInstanceNamesByEntity] = useState();
|
|
5
5
|
const updateInstanceNamesByEntity = useCallback(() => {
|
|
6
6
|
getAllInstances(locales)
|
|
7
7
|
.then(data => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { SerializedSecondaryDecl } from "../../node/schema/declarations/Declaration.ts";
|
|
2
2
|
export type GetDeclFromDeclName = (name: string) => SerializedSecondaryDecl | undefined;
|
|
3
|
-
export declare const useGetDeclFromDeclName: () => GetDeclFromDeclName;
|
|
3
|
+
export declare const useGetDeclFromDeclName: () => [GetDeclFromDeclName, loaded: boolean];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useState } from "preact/hooks";
|
|
2
2
|
import { getAllDeclarations } from "../api.js";
|
|
3
3
|
export const useGetDeclFromDeclName = () => {
|
|
4
|
-
const [secondaryDeclarations, setSecondaryDeclarations] = useState(
|
|
4
|
+
const [secondaryDeclarations, setSecondaryDeclarations] = useState();
|
|
5
5
|
useEffect(() => {
|
|
6
6
|
getAllDeclarations()
|
|
7
7
|
.then(data => {
|
|
@@ -15,6 +15,6 @@ export const useGetDeclFromDeclName = () => {
|
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
17
|
}, []);
|
|
18
|
-
const getDeclFromDeclName = useCallback((name) => secondaryDeclarations
|
|
19
|
-
return getDeclFromDeclName;
|
|
18
|
+
const getDeclFromDeclName = useCallback((name) => secondaryDeclarations?.find(decl => decl.name === name), [secondaryDeclarations]);
|
|
19
|
+
return [getDeclFromDeclName, secondaryDeclarations !== undefined];
|
|
20
20
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { useLocation, useRoute } from "preact-iso";
|
|
3
3
|
import { useEffect, useState } from "preact/hooks";
|
|
4
|
-
import {
|
|
4
|
+
import { getSerializedDisplayNameFromEntityInstance } from "../../shared/utils/displayName.js";
|
|
5
5
|
import { toTitleCase } from "../../shared/utils/string.js";
|
|
6
6
|
import { validateLocaleIdentifier } from "../../shared/validation/identifier.js";
|
|
7
7
|
import { createInstanceByEntityNameAndId } from "../api.js";
|
|
@@ -15,7 +15,7 @@ import { createTypeSkeleton } from "../utils/typeSkeleton.js";
|
|
|
15
15
|
import { NotFound } from "./NotFound.js";
|
|
16
16
|
export const CreateInstance = () => {
|
|
17
17
|
const { params: { name }, } = useRoute();
|
|
18
|
-
const getDeclFromDeclName = useGetDeclFromDeclName();
|
|
18
|
+
const [getDeclFromDeclName, declsLoaded] = useGetDeclFromDeclName();
|
|
19
19
|
const entityFromRoute = useEntityFromRoute();
|
|
20
20
|
const [instanceNamesByEntity] = useInstanceNamesByEntity();
|
|
21
21
|
const [instance, setInstance] = useState();
|
|
@@ -26,10 +26,15 @@ export const CreateInstance = () => {
|
|
|
26
26
|
}
|
|
27
27
|
}, [getDeclFromDeclName, entityFromRoute]);
|
|
28
28
|
const { route } = useLocation();
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const entityName = entityFromRoute?.entity.name ?? name;
|
|
31
|
+
document.title =
|
|
32
|
+
entityName === undefined ? "Not found" : "New " + toTitleCase(entityName) + " — TSONDB";
|
|
33
|
+
}, [entityFromRoute?.entity.name, name]);
|
|
29
34
|
if (!name) {
|
|
30
35
|
return _jsx(NotFound, {});
|
|
31
36
|
}
|
|
32
|
-
if (!entityFromRoute) {
|
|
37
|
+
if (!entityFromRoute || !instanceNamesByEntity || !declsLoaded) {
|
|
33
38
|
return (_jsxs("div", { children: [_jsx("h1", { children: name }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
34
39
|
}
|
|
35
40
|
const { entity, isLocaleEntity } = entityFromRoute;
|
|
@@ -39,13 +44,22 @@ export const CreateInstance = () => {
|
|
|
39
44
|
if (name) {
|
|
40
45
|
createInstanceByEntityNameAndId(entity.name, instance, isLocaleEntity ? customId : undefined)
|
|
41
46
|
.then(createdInstance => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
switch (name) {
|
|
48
|
+
case "saveandcontinue": {
|
|
49
|
+
route(`/entities/${entity.name}/instances/${createdInstance.instance.id}`);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
case "saveandaddanother": {
|
|
53
|
+
setInstance(createTypeSkeleton(getDeclFromDeclName, entity.type));
|
|
54
|
+
setCustomId("");
|
|
55
|
+
alert(`Instance of entity ${entity.name} created successfully with identifier ${createdInstance.instance.id}. You can add another instance now.`);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case "save":
|
|
59
|
+
default: {
|
|
60
|
+
route(`/entities/${entity.name}?created=${encodeURIComponent(createdInstance.instance.id)}`);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
49
63
|
}
|
|
50
64
|
})
|
|
51
65
|
.catch((error) => {
|
|
@@ -56,7 +70,7 @@ export const CreateInstance = () => {
|
|
|
56
70
|
}
|
|
57
71
|
};
|
|
58
72
|
const defaultName = customId || `New ${toTitleCase(entity.name)}`;
|
|
59
|
-
const instanceName =
|
|
73
|
+
const instanceName = getSerializedDisplayNameFromEntityInstance(entity, instance, defaultName);
|
|
60
74
|
const idErrors = isLocaleEntity ? validateLocaleIdentifier(customId) : [];
|
|
61
75
|
return (_jsxs(Layout, { breadcrumbs: [
|
|
62
76
|
{ url: "/", label: "Home" },
|
|
@@ -66,5 +80,5 @@ export const CreateInstance = () => {
|
|
|
66
80
|
}, "aria-invalid": idErrors.length > 0 }), _jsx(ValidationErrors, { errors: idErrors })] })), _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TypeInput, { type: entity.type, value: instance, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: value => {
|
|
67
81
|
console.log("onChange", value);
|
|
68
82
|
setInstance(value);
|
|
69
|
-
} }), _jsxs("div", {
|
|
83
|
+
} }), _jsxs("div", { class: "form-footer btns", children: [_jsx("button", { type: "submit", class: "primary", name: "save", children: "Save" }), _jsx("button", { type: "submit", class: "primary", name: "saveandcontinue", children: "Save and Continue" }), _jsx("button", { type: "submit", class: "primary", name: "saveandaddanother", children: "Save and Add Another" })] })] })] }));
|
|
70
84
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { useRoute } from "preact-iso";
|
|
3
|
-
import { useEffect } from "preact/hooks";
|
|
3
|
+
import { useEffect, useState } from "preact/hooks";
|
|
4
4
|
import { getGitStatusForDisplay, getLabelForGitStatus } from "../../shared/utils/git.js";
|
|
5
|
+
import { toTitleCase } from "../../shared/utils/string.js";
|
|
5
6
|
import { deleteInstanceByEntityNameAndId, getEntityByName, getInstancesByEntityName, } from "../api.js";
|
|
6
7
|
import { Layout } from "../components/Layout.js";
|
|
7
8
|
import { useAPIResource } from "../hooks/useAPIResource.js";
|
|
@@ -11,8 +12,12 @@ import { NotFound } from "./NotFound.js";
|
|
|
11
12
|
const mapInstances = (data) => data.instances;
|
|
12
13
|
export const Entity = () => {
|
|
13
14
|
const { params: { name }, query: { created }, } = useRoute();
|
|
15
|
+
const [searchText, setSearchText] = useState("");
|
|
14
16
|
const [entity] = useAPIResource(getEntityByName, name ?? "");
|
|
15
17
|
const [instances, reloadInstances] = useMappedAPIResource(getInstancesByEntityName, mapInstances, name ?? "");
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
document.title = toTitleCase(entity?.declaration.namePlural ?? name ?? "") + " — TSONDB";
|
|
20
|
+
}, [entity?.declaration.namePlural, name]);
|
|
16
21
|
useEffect(() => {
|
|
17
22
|
if (created) {
|
|
18
23
|
const instanceElement = document.getElementById(`instance-${created}`);
|
|
@@ -25,20 +30,29 @@ export const Entity = () => {
|
|
|
25
30
|
return _jsx(NotFound, {});
|
|
26
31
|
}
|
|
27
32
|
if (!entity || !instances) {
|
|
28
|
-
return (_jsxs("div", { children: [_jsx("h1", { children: name }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
33
|
+
return (_jsxs("div", { children: [_jsx("h1", { children: toTitleCase(entity?.declaration.namePlural ?? name) }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
29
34
|
}
|
|
30
|
-
|
|
35
|
+
const lowerSearchText = searchText.toLowerCase();
|
|
36
|
+
const filteredInstances = searchText.length === 0
|
|
37
|
+
? instances
|
|
38
|
+
: instances.filter(instance => instance.id.includes(searchText) ||
|
|
39
|
+
instance.displayName.toLowerCase().includes(lowerSearchText));
|
|
40
|
+
return (_jsxs(Layout, { breadcrumbs: [{ url: "/", label: "Home" }], children: [_jsxs("div", { class: "header-with-btns", children: [_jsx("h1", { children: toTitleCase(entity.declaration.namePlural) }), _jsx("a", { class: "btn btn--primary", href: `/entities/${entity.declaration.name}/instances/create`, children: "Add" })] }), entity.declaration.comment && (_jsx(Markdown, { class: "description", string: entity.declaration.comment })), _jsxs("div", { className: "list-header", children: [_jsxs("p", { class: "instance-count", children: [searchText === "" ? "" : `${filteredInstances.length.toString()} of `, instances.length, " instance", instances.length === 1 ? "" : "s"] }), _jsxs("form", { action: "", rel: "search", onSubmit: e => {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
}, children: [_jsx("label", { htmlFor: "instance-search", class: "visually-hidden", children: "Search" }), _jsx("input", { type: "text", id: "instance-search", value: searchText, onInput: event => {
|
|
43
|
+
setSearchText(event.currentTarget.value);
|
|
44
|
+
} })] })] }), _jsx("ul", { class: "entries entries--instances", children: filteredInstances.map(instance => {
|
|
31
45
|
const gitStatusForDisplay = getGitStatusForDisplay(instance.gitStatus);
|
|
32
|
-
return (_jsxs("li", { id: `instance-${instance.id}`, class: `
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
return (_jsxs("li", { id: `instance-${instance.id}`, class: `entries-item ${created === instance.id ? "entries-item--created" : ""} ${gitStatusForDisplay === undefined ? "" : `git-status--${gitStatusForDisplay}`}`, children: [_jsx("h2", { class: "entries-item__title", children: instance.displayName }), _jsx("p", { "aria-hidden": true, class: "entries-item__subtitle entries-item__subtitle--id", children: instance.id }), _jsxs("div", { class: "entries-item__side", children: [gitStatusForDisplay !== undefined && (_jsx("p", { class: `git-status git-status--${gitStatusForDisplay}`, title: getLabelForGitStatus(gitStatusForDisplay), children: gitStatusForDisplay })), _jsxs("div", { class: "btns", children: [_jsx("a", { href: `/entities/${entity.declaration.name}/instances/${instance.id}`, class: "btn", children: "Edit" }), _jsx("button", { class: "destructive", onClick: () => {
|
|
47
|
+
if (confirm("Are you sure you want to delete this instance?")) {
|
|
48
|
+
deleteInstanceByEntityNameAndId(entity.declaration.name, instance.id)
|
|
49
|
+
.then(() => reloadInstances())
|
|
50
|
+
.catch((error) => {
|
|
51
|
+
if (error instanceof Error) {
|
|
52
|
+
alert("Error deleting instance:\n\n" + error.toString());
|
|
53
|
+
}
|
|
54
|
+
});
|
|
39
55
|
}
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
}, children: "Delete" })] })] }, instance.id));
|
|
56
|
+
}, children: "Delete" })] })] })] }, instance.id));
|
|
43
57
|
}) })] }));
|
|
44
58
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "preact/hooks";
|
|
2
3
|
import { toTitleCase } from "../../shared/utils/string.js";
|
|
3
4
|
import { getAllEntities } from "../api.js";
|
|
4
5
|
import { Layout } from "../components/Layout.js";
|
|
@@ -7,5 +8,18 @@ import { Markdown } from "../utils/Markdown.js";
|
|
|
7
8
|
const mapEntities = (data) => data.declarations.sort((a, b) => a.declaration.name.localeCompare(b.declaration.name));
|
|
8
9
|
export const Home = () => {
|
|
9
10
|
const [entities] = useMappedAPIResource(getAllEntities, mapEntities);
|
|
10
|
-
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
document.title = "Entities — TSONDB";
|
|
13
|
+
}, []);
|
|
14
|
+
const [searchText, setSearchText] = useState("");
|
|
15
|
+
const lowerSearchText = searchText.toLowerCase().replaceAll(" ", "");
|
|
16
|
+
const filteredEntities = searchText.length === 0
|
|
17
|
+
? entities
|
|
18
|
+
: entities?.filter(entity => entity.declaration.name.toLowerCase().includes(lowerSearchText) ||
|
|
19
|
+
entity.declaration.namePlural.toLowerCase().includes(lowerSearchText));
|
|
20
|
+
return (_jsxs(Layout, { breadcrumbs: [{ url: "/", label: "Home" }], children: [_jsx("h1", { children: "Entities" }), _jsxs("div", { className: "list-header", children: [_jsxs("p", { class: "instance-count", children: [searchText === "" ? "" : `${(filteredEntities?.length ?? 0).toString()} of `, entities?.length ?? 0, " entit", entities?.length === 1 ? "y" : "ies"] }), _jsxs("form", { action: "", rel: "search", onSubmit: e => {
|
|
21
|
+
e.preventDefault();
|
|
22
|
+
}, children: [_jsx("label", { htmlFor: "entity-search", class: "visually-hidden", children: "Search" }), _jsx("input", { type: "text", id: "entity-search", value: searchText, onInput: event => {
|
|
23
|
+
setSearchText(event.currentTarget.value);
|
|
24
|
+
} })] })] }), _jsx("ul", { class: "entries entries--entities", children: (filteredEntities ?? []).map(entity => (_jsxs("li", { class: "entries-item", children: [_jsxs("div", { class: "entries-item__title", children: [_jsx("h2", { children: toTitleCase(entity.declaration.namePlural) }), entity.declaration.comment && (_jsx(Markdown, { class: "description", string: entity.declaration.comment }))] }), _jsxs("p", { class: "entries-item__subtitle", children: [entity.instanceCount, " instance", entity.instanceCount === 1 ? "" : "s"] }), _jsx("div", { class: "entries-item__side", children: _jsx("div", { class: "btns", children: _jsx("a", { href: `/entities/${entity.declaration.name}`, class: "btn", children: "View" }) }) })] }, entity.declaration.name))) })] }));
|
|
11
25
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
2
|
import { useLocation, useRoute } from "preact-iso";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { useCallback, useEffect, useState } from "preact/hooks";
|
|
4
|
+
import { getSerializedDisplayNameFromEntityInstance } from "../../shared/utils/displayName.js";
|
|
5
|
+
import { toTitleCase } from "../../shared/utils/string.js";
|
|
6
6
|
import { deleteInstanceByEntityNameAndId, getInstanceByEntityNameAndId, updateInstanceByEntityNameAndId, } from "../api.js";
|
|
7
7
|
import { Layout } from "../components/Layout.js";
|
|
8
8
|
import { TypeInput } from "../components/typeInputs/TypeInput.js";
|
|
@@ -12,13 +12,23 @@ import { useGetDeclFromDeclName } from "../hooks/useSecondaryDeclarations.js";
|
|
|
12
12
|
import { NotFound } from "./NotFound.js";
|
|
13
13
|
export const Instance = () => {
|
|
14
14
|
const { params: { name, id }, } = useRoute();
|
|
15
|
-
const getDeclFromDeclName = useGetDeclFromDeclName();
|
|
15
|
+
const [getDeclFromDeclName, declsLoaded] = useGetDeclFromDeclName();
|
|
16
16
|
const entityFromRoute = useEntityFromRoute();
|
|
17
17
|
const [instanceNamesByEntity] = useInstanceNamesByEntity();
|
|
18
18
|
const [instance, setInstance] = useState();
|
|
19
19
|
const [originalInstance, setOriginalInstance] = useState();
|
|
20
20
|
const { route } = useLocation();
|
|
21
|
-
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (entityFromRoute && instance && id) {
|
|
23
|
+
const defaultName = id;
|
|
24
|
+
const instanceName = getSerializedDisplayNameFromEntityInstance(entityFromRoute.entity, instance.content, defaultName);
|
|
25
|
+
const entityName = entityFromRoute.entity.name;
|
|
26
|
+
document.title = instanceName + " — " + toTitleCase(entityName) + " — TSONDB";
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
document.title = "Not found — TSONDB";
|
|
30
|
+
}
|
|
31
|
+
}, [entityFromRoute, id, instance]);
|
|
22
32
|
useEffect(() => {
|
|
23
33
|
if (name && id) {
|
|
24
34
|
getInstanceByEntityNameAndId(name, id)
|
|
@@ -33,7 +43,7 @@ export const Instance = () => {
|
|
|
33
43
|
}, [id, name]);
|
|
34
44
|
const handleSubmit = (event) => {
|
|
35
45
|
event.preventDefault();
|
|
36
|
-
if (name && id && instance) {
|
|
46
|
+
if (event.submitter?.getAttribute("name") === "save" && name && id && instance) {
|
|
37
47
|
updateInstanceByEntityNameAndId(name, id, instance.content)
|
|
38
48
|
.then(updatedInstance => {
|
|
39
49
|
setInstance(updatedInstance.instance);
|
|
@@ -46,17 +56,24 @@ export const Instance = () => {
|
|
|
46
56
|
});
|
|
47
57
|
}
|
|
48
58
|
};
|
|
59
|
+
const handleOnChange = useCallback((value) => {
|
|
60
|
+
setInstance(container => container && { ...container, content: value });
|
|
61
|
+
}, []);
|
|
49
62
|
if (!name || !id) {
|
|
50
63
|
return _jsx(NotFound, {});
|
|
51
64
|
}
|
|
52
|
-
if (!entityFromRoute ||
|
|
65
|
+
if (!entityFromRoute ||
|
|
66
|
+
!instance ||
|
|
67
|
+
!originalInstance ||
|
|
68
|
+
!instanceNamesByEntity ||
|
|
69
|
+
!declsLoaded) {
|
|
53
70
|
return (_jsxs(Layout, { breadcrumbs: [
|
|
54
71
|
{ url: "/", label: "Home" },
|
|
55
72
|
{ url: `/entities/${name}`, label: name },
|
|
56
73
|
], children: [_jsx("h1", { children: id }), _jsx("p", { className: "loading", children: "Loading \u2026" })] }));
|
|
57
74
|
}
|
|
58
75
|
const defaultName = id;
|
|
59
|
-
const instanceName =
|
|
76
|
+
const instanceName = getSerializedDisplayNameFromEntityInstance(entityFromRoute.entity, instance.content, defaultName);
|
|
60
77
|
return (_jsxs(Layout, { breadcrumbs: [
|
|
61
78
|
{ url: "/", label: "Home" },
|
|
62
79
|
{ url: `/entities/${name}`, label: entityFromRoute.entity.name },
|
|
@@ -72,8 +89,5 @@ export const Instance = () => {
|
|
|
72
89
|
}
|
|
73
90
|
});
|
|
74
91
|
}
|
|
75
|
-
}, children: "Delete" })] }), _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TypeInput, { type: entityFromRoute.entity.type, value: instance.content, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange:
|
|
76
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
77
|
-
setInstance(container => ({ ...container, content: value }));
|
|
78
|
-
} }), _jsx("button", { type: "submit", disabled: !hasChanges, class: "primary", children: "Save" })] })] }));
|
|
92
|
+
}, children: "Delete" })] }), _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TypeInput, { type: entityFromRoute.entity.type, value: instance.content, instanceNamesByEntity: instanceNamesByEntity, getDeclFromDeclName: getDeclFromDeclName, onChange: handleOnChange }), _jsx("div", { class: "form-footer btns", children: _jsx("button", { type: "submit", name: "save", class: "primary", children: "Save" }) })] })] }));
|
|
79
93
|
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useEffect } from "preact/hooks";
|
|
2
3
|
import { Layout } from "../components/Layout.js";
|
|
3
4
|
export const NotFound = () => {
|
|
5
|
+
useEffect(() => {
|
|
6
|
+
document.title = "Not found — TSONDB";
|
|
7
|
+
}, []);
|
|
4
8
|
return (_jsxs(Layout, { breadcrumbs: [{ url: "/", label: "Home" }], children: [_jsx("h1", { children: "404 Not Found" }), _jsx("p", { children: "The page you are looking for does not exist." })] }));
|
|
5
9
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsondb",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Lukas Obermann",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
".": "./dist/src/index.js",
|
|
18
18
|
"./renderer/jsonschema": "./dist/src/node/renderers/jsonschema/index.js",
|
|
19
19
|
"./renderer/ts": "./dist/src/node/renderers/ts/index.js",
|
|
20
|
-
"./schema": "./dist/src/node/Schema.js",
|
|
20
|
+
"./schema": "./dist/src/node/schema/Schema.js",
|
|
21
21
|
"./schema/def": "./dist/src/node/schema/index.js"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
@@ -31,18 +31,18 @@
|
|
|
31
31
|
"release:sign": "commit-and-tag-version --sign --signoff"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@eslint/js": "^9.
|
|
34
|
+
"@eslint/js": "^9.35.0",
|
|
35
35
|
"@types/debug": "^4.1.12",
|
|
36
36
|
"@types/express": "^5.0.3",
|
|
37
37
|
"@types/node": "^24.3.1",
|
|
38
38
|
"commit-and-tag-version": "^12.6.0",
|
|
39
|
-
"eslint": "^9.
|
|
39
|
+
"eslint": "^9.35.0",
|
|
40
40
|
"eslint-plugin-react": "^7.37.5",
|
|
41
41
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
42
42
|
"globals": "^16.3.0",
|
|
43
43
|
"prettier": "^3.6.2",
|
|
44
44
|
"typescript": "^5.9.2",
|
|
45
|
-
"typescript-eslint": "^8.
|
|
45
|
+
"typescript-eslint": "^8.43.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"debug": "^4.4.1",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"preact-iso": "^2.10.0",
|
|
52
52
|
"simple-cli-args": "^0.1.2",
|
|
53
53
|
"simple-git": "^3.28.0",
|
|
54
|
-
"uuid": "^
|
|
54
|
+
"uuid": "^13.0.0"
|
|
55
55
|
},
|
|
56
56
|
"repository": "github:elyukai/tsondb",
|
|
57
57
|
"bugs": {
|