tsondb 0.7.7 → 0.7.9

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.
Files changed (49) hide show
  1. package/dist/src/node/server/api/git.js +156 -24
  2. package/dist/src/node/server/index.js +4 -0
  3. package/dist/src/node/utils/instanceOperations.d.ts +1 -1
  4. package/dist/src/node/utils/instanceOperations.js +2 -2
  5. package/dist/src/shared/api.d.ts +17 -1
  6. package/dist/src/shared/utils/git.d.ts +4 -0
  7. package/dist/src/shared/utils/git.js +6 -1
  8. package/dist/src/shared/utils/markdown.d.ts +36 -17
  9. package/dist/src/shared/utils/markdown.js +79 -23
  10. package/dist/src/shared/utils/object.d.ts +1 -0
  11. package/dist/src/shared/utils/object.js +1 -0
  12. package/dist/src/web/api/git.d.ts +5 -1
  13. package/dist/src/web/api/git.js +6 -2
  14. package/dist/src/web/components/ContextProviderWrapper.d.ts +7 -0
  15. package/dist/src/web/components/ContextProviderWrapper.js +5 -0
  16. package/dist/src/web/components/InstanceRouteSkeleton.d.ts +1 -0
  17. package/dist/src/web/components/InstanceRouteSkeleton.js +8 -4
  18. package/dist/src/web/components/LoadingOverlay.d.ts +1 -0
  19. package/dist/src/web/components/LoadingOverlay.js +3 -0
  20. package/dist/src/web/components/ModalDialog.js +4 -3
  21. package/dist/src/web/components/git/Git.js +47 -0
  22. package/dist/src/web/components/git/GitBranchManager.d.ts +7 -0
  23. package/dist/src/web/components/git/GitBranchManager.js +17 -0
  24. package/dist/src/web/components/git/GitFileList.d.ts +17 -0
  25. package/dist/src/web/components/git/GitFileList.js +11 -0
  26. package/dist/src/web/components/git/GitFileManager.d.ts +8 -0
  27. package/dist/src/web/components/git/GitFileManager.js +34 -0
  28. package/dist/src/web/components/git/GitStatusIndicator.d.ts +7 -0
  29. package/dist/src/web/components/git/GitStatusIndicator.js +6 -0
  30. package/dist/src/web/components/typeInputs/StringTypeInput.js +1 -1
  31. package/dist/src/web/context/entities.d.ts +6 -5
  32. package/dist/src/web/context/git.d.ts +2 -1
  33. package/dist/src/web/context/gitClient.d.ts +2 -0
  34. package/dist/src/web/context/gitClient.js +2 -0
  35. package/dist/src/web/hooks/useGitClient.d.ts +37 -0
  36. package/dist/src/web/hooks/useGitClient.js +313 -0
  37. package/dist/src/web/index.js +6 -2
  38. package/dist/src/web/routes/CreateInstance.js +2 -1
  39. package/dist/src/web/routes/Entity.js +10 -4
  40. package/dist/src/web/routes/Instance.js +2 -1
  41. package/dist/src/web/signals/loading.d.ts +2 -0
  42. package/dist/src/web/signals/loading.js +11 -0
  43. package/dist/src/web/utils/BlockMarkdown.js +1 -1
  44. package/dist/src/web/utils/debug.d.ts +1 -0
  45. package/dist/src/web/utils/debug.js +4 -0
  46. package/package.json +3 -3
  47. package/public/css/styles.css +319 -229
  48. package/dist/src/web/components/Git.js +0 -164
  49. /package/dist/src/web/components/{Git.d.ts → git/Git.d.ts} +0 -0
@@ -0,0 +1,313 @@
1
+ import { useCallback, useContext, useEffect, useMemo, useState } from "preact/hooks";
2
+ import { isSerializedEntityDecl, isSerializedEntityDeclWithParentReference, } from "../../shared/schema/declarations/EntityDecl.js";
3
+ import { isChangedInIndex, isChangedInWorkingDir, splitBranchName, } from "../../shared/utils/git.js";
4
+ import { deleteInstanceByEntityNameAndId } from "../api/declarations.js";
5
+ import * as GitApi from "../api/git.js";
6
+ import { EntitiesContext } from "../context/entities.js";
7
+ import { runWithLoading } from "../signals/loading.js";
8
+ import { logAndAlertError } from "../utils/debug.js";
9
+ import { useSetting } from "./useSettings.js";
10
+ const filterFilesForDisplay = (predicate, entities, data) => Object.entries(data.instances)
11
+ .map(([entityName, instances]) => [
12
+ entityName,
13
+ entities.find(entity => entity.declaration.name === entityName)?.declaration.namePlural ??
14
+ entityName,
15
+ instances
16
+ .filter(instance => instance.gitStatus !== undefined && predicate(instance.gitStatus))
17
+ .sort((a, b) => a.displayName.localeCompare(b.displayName, undefined, { numeric: true })),
18
+ ])
19
+ .filter(([_1, _2, instances]) => instances.length > 0)
20
+ .sort((a, b) => a[1].localeCompare(b[1]));
21
+ export const useGitClient = () => {
22
+ const [locales] = useSetting("displayedLocales");
23
+ const { entities } = useContext(EntitiesContext);
24
+ const [isRepo, setIsRepo] = useState(false);
25
+ const [commitsAhead, setCommitsAhead] = useState(0);
26
+ const [commitsBehind, setCommitsBehind] = useState(0);
27
+ const [indexFiles, setIndexFiles] = useState([]);
28
+ const [workingTreeFiles, setWorkingTreeFiles] = useState([]);
29
+ const [allBranches, setAllBranches] = useState([]);
30
+ const [currentBranch, setCurrentBranch] = useState("");
31
+ const [branches, setBranches] = useState({});
32
+ const [isDetached, setIsDetached] = useState(false);
33
+ const updateGitStatus = useCallback(async () => {
34
+ const { isRepo } = await GitApi.isRepo(locales);
35
+ setIsRepo(isRepo);
36
+ if (isRepo && entities.length > 0) {
37
+ try {
38
+ const [statusData, branchesData] = await Promise.all([
39
+ GitApi.getStatus(locales),
40
+ GitApi.getBranches(locales),
41
+ ]);
42
+ setIndexFiles(filterFilesForDisplay(isChangedInIndex, entities, statusData));
43
+ setWorkingTreeFiles(filterFilesForDisplay(isChangedInWorkingDir, entities, statusData));
44
+ setCommitsAhead(statusData.commitsAhead);
45
+ setCommitsBehind(statusData.commitsBehind);
46
+ setAllBranches(branchesData.allBranches);
47
+ setCurrentBranch(branchesData.currentBranch);
48
+ setBranches(Object.fromEntries(Object.entries(branchesData.branches).map(([branch, branchSummary]) => {
49
+ const { remote, name } = splitBranchName(branch);
50
+ return [
51
+ branch,
52
+ {
53
+ ...branchSummary,
54
+ remote,
55
+ name,
56
+ },
57
+ ];
58
+ })));
59
+ setIsDetached(branchesData.isDetached);
60
+ }
61
+ catch (error) {
62
+ logAndAlertError(error, "Error updating git status: ");
63
+ }
64
+ }
65
+ }, [entities, locales]);
66
+ useEffect(() => {
67
+ void updateGitStatus();
68
+ }, [updateGitStatus]);
69
+ const getGitStatusOfInstance = useCallback((entityName, instanceId) => {
70
+ const entity = indexFiles.find(([name]) => name === entityName);
71
+ const instanceInIndex = entity?.[2].find(instance => instance.id === instanceId);
72
+ if (instanceInIndex?.gitStatus !== undefined) {
73
+ return instanceInIndex.gitStatus;
74
+ }
75
+ const workingTreeEntity = workingTreeFiles.find(([name]) => name === entityName);
76
+ const instanceInWorkingTree = workingTreeEntity?.[2].find(instance => instance.id === instanceId);
77
+ return instanceInWorkingTree?.gitStatus;
78
+ }, [indexFiles, workingTreeFiles]);
79
+ const fetch = useCallback(async () => {
80
+ await runWithLoading(async () => {
81
+ try {
82
+ await GitApi.fetch(locales);
83
+ await updateGitStatus();
84
+ }
85
+ catch (error) {
86
+ logAndAlertError(error, "Error fetching from remote: ");
87
+ }
88
+ });
89
+ }, [locales, updateGitStatus]);
90
+ const stage = useCallback(async (entityName, instance) => {
91
+ await runWithLoading(async () => {
92
+ try {
93
+ await GitApi.stageFileOfEntity(locales, entityName, instance.id);
94
+ await updateGitStatus();
95
+ }
96
+ catch (error) {
97
+ logAndAlertError(error, "Error staging instance: ");
98
+ }
99
+ });
100
+ }, [locales, updateGitStatus]);
101
+ const stageAll = useCallback(async (entityName) => {
102
+ await runWithLoading(async () => {
103
+ try {
104
+ if (entityName) {
105
+ await GitApi.stageAllFilesOfEntity(locales, entityName);
106
+ }
107
+ else {
108
+ await GitApi.stageAllFiles(locales);
109
+ }
110
+ await updateGitStatus();
111
+ }
112
+ catch (error) {
113
+ logAndAlertError(error, "Error staging all instances: ");
114
+ }
115
+ });
116
+ }, [locales, updateGitStatus]);
117
+ const unstage = useCallback(async (entityName, instance) => {
118
+ await runWithLoading(async () => {
119
+ try {
120
+ await GitApi.unstageFileOfEntity(locales, entityName, instance.id);
121
+ await updateGitStatus();
122
+ }
123
+ catch (error) {
124
+ logAndAlertError(error, "Error unstaging instance: ");
125
+ }
126
+ });
127
+ }, [locales, updateGitStatus]);
128
+ const unstageAll = useCallback(async (entityName) => {
129
+ await runWithLoading(async () => {
130
+ try {
131
+ if (entityName) {
132
+ await GitApi.unstageAllFilesOfEntity(locales, entityName);
133
+ }
134
+ else {
135
+ await GitApi.unstageAllFiles(locales);
136
+ }
137
+ await updateGitStatus();
138
+ }
139
+ catch (error) {
140
+ logAndAlertError(error, "Error unstaging all instances: ");
141
+ }
142
+ });
143
+ }, [locales, updateGitStatus]);
144
+ const reset = useCallback(async (entityName, instance) => {
145
+ await runWithLoading(async () => {
146
+ if (!confirm(`Are you sure you want to reset instance "${instance.displayName}" (${instance.id})?`)) {
147
+ return;
148
+ }
149
+ const entity = entities.find(e => e.declaration.name === entityName)?.declaration;
150
+ if (instance.gitStatus?.workingDir === "D" &&
151
+ entity &&
152
+ isSerializedEntityDecl(entity) &&
153
+ isSerializedEntityDeclWithParentReference(entity) &&
154
+ !confirm(`If you deleted the parent of "${instance.displayName}" (${instance.id}) before, make sure to restore it as well. Continue?`)) {
155
+ return;
156
+ }
157
+ try {
158
+ if (instance.gitStatus?.workingDir === "?") {
159
+ await deleteInstanceByEntityNameAndId(locales, entityName, instance.id);
160
+ }
161
+ else {
162
+ await GitApi.resetFileOfEntity(locales, entityName, instance.id);
163
+ }
164
+ await updateGitStatus();
165
+ }
166
+ catch (error) {
167
+ logAndAlertError(error, "Error resetting instance: ");
168
+ }
169
+ });
170
+ }, [entities, locales, updateGitStatus]);
171
+ const commit = useCallback(async (commitMessage) => {
172
+ await runWithLoading(async () => {
173
+ if (commitMessage.length > 0 &&
174
+ indexFiles.length > 0 &&
175
+ confirm("Do you want to commit all staged files?")) {
176
+ try {
177
+ await GitApi.commitStagedFiles(locales, commitMessage);
178
+ await updateGitStatus();
179
+ }
180
+ catch (error) {
181
+ logAndAlertError(error, "Error committing instances: ");
182
+ }
183
+ }
184
+ });
185
+ }, [indexFiles.length, locales, updateGitStatus]);
186
+ const push = useCallback(async () => {
187
+ await runWithLoading(async () => {
188
+ try {
189
+ await GitApi.pushCommits(locales);
190
+ alert("Pushed commits successfully");
191
+ await updateGitStatus();
192
+ }
193
+ catch (error) {
194
+ logAndAlertError(error, "Error pushing commits: ");
195
+ }
196
+ });
197
+ }, [locales, updateGitStatus]);
198
+ const pull = useCallback(async () => {
199
+ await runWithLoading(async () => {
200
+ try {
201
+ await GitApi.pullCommits(locales);
202
+ alert("Pulled commits successfully");
203
+ await updateGitStatus();
204
+ }
205
+ catch (error) {
206
+ logAndAlertError(error, "Error pulling commits: ");
207
+ }
208
+ });
209
+ }, [locales, updateGitStatus]);
210
+ const createBranch = useCallback(async (newBranchName) => {
211
+ await runWithLoading(async () => {
212
+ if (newBranchName.length === 0) {
213
+ alert("Branch name cannot be empty");
214
+ return;
215
+ }
216
+ if (allBranches.includes(newBranchName)) {
217
+ alert("Branch name already exists");
218
+ return;
219
+ }
220
+ try {
221
+ await GitApi.createBranch(locales, newBranchName);
222
+ alert(`Created branch "${newBranchName}" successfully`);
223
+ await updateGitStatus();
224
+ }
225
+ catch (error) {
226
+ logAndAlertError(error, "Error creating branch: ");
227
+ }
228
+ });
229
+ }, [allBranches, locales, updateGitStatus]);
230
+ const switchBranch = useCallback(async (targetBranch) => {
231
+ await runWithLoading(async () => {
232
+ try {
233
+ await GitApi.switchBranch(locales, targetBranch);
234
+ await updateGitStatus();
235
+ }
236
+ catch (error) {
237
+ logAndAlertError(error, "Error switching branch: ");
238
+ }
239
+ });
240
+ }, [locales, updateGitStatus]);
241
+ const deleteBranch = useCallback(async (targetBranch) => {
242
+ await runWithLoading(async () => {
243
+ if (targetBranch === currentBranch) {
244
+ alert("Cannot delete the current branch");
245
+ return;
246
+ }
247
+ if (!allBranches.includes(targetBranch)) {
248
+ alert(`Branch "${targetBranch}" does not exist`);
249
+ return;
250
+ }
251
+ if (!confirm(`Are you sure you want to delete branch "${targetBranch}"?`)) {
252
+ return;
253
+ }
254
+ try {
255
+ await GitApi.deleteBranch(locales, targetBranch);
256
+ alert(`Deleted branch "${targetBranch}" successfully`);
257
+ await updateGitStatus();
258
+ }
259
+ catch (error) {
260
+ logAndAlertError(error, "Error deleting branch: ");
261
+ }
262
+ });
263
+ }, [allBranches, currentBranch, locales, updateGitStatus]);
264
+ return useMemo(() => ({
265
+ isRepo,
266
+ commitsAhead,
267
+ commitsBehind,
268
+ indexFiles,
269
+ workingTreeFiles,
270
+ allBranches,
271
+ currentBranch,
272
+ branches,
273
+ isDetached,
274
+ getGitStatusOfInstance,
275
+ updateLocalState: updateGitStatus,
276
+ fetch,
277
+ stage,
278
+ stageAll,
279
+ unstage,
280
+ unstageAll,
281
+ reset,
282
+ commit,
283
+ push,
284
+ pull,
285
+ createBranch,
286
+ switchBranch,
287
+ deleteBranch,
288
+ }), [
289
+ allBranches,
290
+ branches,
291
+ commit,
292
+ commitsAhead,
293
+ commitsBehind,
294
+ createBranch,
295
+ currentBranch,
296
+ deleteBranch,
297
+ fetch,
298
+ getGitStatusOfInstance,
299
+ indexFiles,
300
+ isDetached,
301
+ isRepo,
302
+ pull,
303
+ push,
304
+ reset,
305
+ stage,
306
+ stageAll,
307
+ switchBranch,
308
+ unstage,
309
+ unstageAll,
310
+ updateGitStatus,
311
+ workingTreeFiles,
312
+ ]);
313
+ };
@@ -4,11 +4,15 @@ import { LocationProvider, Route, Router, useLocation } from "preact-iso";
4
4
  import { useEffect, useState } from "preact/hooks";
5
5
  import { getAllEntities } from "./api/declarations.js";
6
6
  import { getWebConfig } from "./api/index.js";
7
- import { Git } from "./components/Git.js";
7
+ import { ContextProviderWrapper } from "./components/ContextProviderWrapper.js";
8
+ import { Git } from "./components/git/Git.js";
9
+ import { LoadingOverlay } from "./components/LoadingOverlay.js";
8
10
  import { ConfigContext } from "./context/config.js";
9
11
  import { EntitiesContext } from "./context/entities.js";
10
12
  import { GitContext } from "./context/git.js";
13
+ import { GitClientContext } from "./context/gitClient.js";
11
14
  import { SettingsContext } from "./context/settings.js";
15
+ import { useGitClient } from "./hooks/useGitClient.js";
12
16
  import { useMappedAPIResource } from "./hooks/useMappedAPIResource.js";
13
17
  import { useSettings } from "./hooks/useSettings.js";
14
18
  import { CreateInstance } from "./routes/CreateInstance.js";
@@ -29,7 +33,7 @@ const App = ({ config }) => {
29
33
  alert("Error reloading entities: " + String(error));
30
34
  });
31
35
  }, [location.path, reloadEntities]);
32
- return (_jsx(ConfigContext.Provider, { value: config, children: _jsx(SettingsContext.Provider, { value: settingsContext, children: _jsx(GitContext.Provider, { value: [isGitOpen, setIsGitOpen], children: _jsx(LocationProvider, { children: _jsxs(EntitiesContext.Provider, { value: { entities: entities ?? [], reloadEntities }, children: [_jsxs(Router, { children: [_jsx(Route, { path: "/", component: Home }), _jsx(Route, { path: "/entities/:name", component: Entity }), _jsx(Route, { path: "/entities/:name/instances/create", component: CreateInstance }), _jsx(Route, { path: "/entities/:name/instances/:id", component: Instance }), _jsx(Route, { default: true, component: NotFound })] }), _jsx(Git, {})] }) }) }) }) }));
36
+ return (_jsx(ConfigContext.Provider, { value: config, children: _jsx(SettingsContext.Provider, { value: settingsContext, children: _jsx(GitContext.Provider, { value: [isGitOpen, setIsGitOpen], children: _jsx(LocationProvider, { children: _jsx(EntitiesContext.Provider, { value: { entities: entities ?? [], reloadEntities }, children: _jsxs(ContextProviderWrapper, { context: GitClientContext, useValue: useGitClient, children: [_jsx(LoadingOverlay, {}), _jsxs(Router, { children: [_jsx(Route, { path: "/", component: Home }), _jsx(Route, { path: "/entities/:name", component: Entity }), _jsx(Route, { path: "/entities/:name/instances/create", component: CreateInstance }), _jsx(Route, { path: "/entities/:name/instances/:id", component: Instance }), _jsx(Route, { default: true, component: NotFound })] }), _jsx(Git, {})] }) }) }) }) }) }));
33
37
  };
34
38
  const config = await getWebConfig();
35
39
  const root = document.getElementById("app");
@@ -11,7 +11,7 @@ const titleBuilder = ({ entity }) => {
11
11
  const entityName = entity.name;
12
12
  return "New " + toTitleCase(entityName) + " — TSONDB";
13
13
  };
14
- const onSubmit = async ({ locales, entity, buttonName, instanceContent, isLocaleEntity, customId, childInstances, setInstanceContent, setCustomId, route, getDeclFromDeclName, }) => {
14
+ const onSubmit = async ({ locales, entity, buttonName, instanceContent, isLocaleEntity, customId, childInstances, setInstanceContent, setCustomId, route, getDeclFromDeclName, updateLocalGitState, }) => {
15
15
  try {
16
16
  if (buttonName) {
17
17
  const createdInstance = await createInstanceByEntityNameAndId(locales, entity.name, {
@@ -20,6 +20,7 @@ const onSubmit = async ({ locales, entity, buttonName, instanceContent, isLocale
20
20
  content: instanceContent,
21
21
  id: undefined,
22
22
  }, isLocaleEntity ? customId : undefined);
23
+ await updateLocalGitState?.();
23
24
  switch (buttonName) {
24
25
  case "saveandcontinue": {
25
26
  route(`/entities/${entity.name}/instances/${createdInstance.instance.id}`);
@@ -1,12 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
2
  import { useRoute } from "preact-iso";
3
3
  import { useContext, useEffect, useState } from "preact/hooks";
4
- import { getGitStatusForDisplay, getLabelForGitStatus } from "../../shared/utils/git.js";
4
+ import { getGitStatusForDisplay } from "../../shared/utils/git.js";
5
5
  import { toTitleCase } from "../../shared/utils/string.js";
6
6
  import { deleteInstanceByEntityNameAndId, getInstancesByEntityName, getLocaleInstances, } from "../api/declarations.js";
7
+ import { GitStatusIndicator } from "../components/git/GitStatusIndicator.js";
7
8
  import { Layout } from "../components/Layout.js";
8
9
  import { ConfigContext } from "../context/config.js";
9
10
  import { EntitiesContext } from "../context/entities.js";
11
+ import { GitClientContext } from "../context/gitClient.js";
10
12
  import { useEntityFromRoute } from "../hooks/useEntityFromRoute.js";
11
13
  import { useMappedAPIResource } from "../hooks/useMappedAPIResource.js";
12
14
  import { useSetting } from "../hooks/useSettings.js";
@@ -21,6 +23,7 @@ export const Entity = () => {
21
23
  const [searchText, setSearchText] = useState("");
22
24
  const entityFromRoute = useEntityFromRoute();
23
25
  const config = useContext(ConfigContext);
26
+ const gitClient = useContext(GitClientContext);
24
27
  const { reloadEntities } = useContext(EntitiesContext);
25
28
  const { declaration: entity, isLocaleEntity } = entityFromRoute ?? {};
26
29
  const [instances, reloadInstances] = useMappedAPIResource(getInstancesByEntityName, mapInstances, locales, name ?? "");
@@ -43,10 +46,13 @@ export const Entity = () => {
43
46
  return (_jsxs(Layout, { breadcrumbs: [{ url: "/", label: homeTitle }], children: [_jsxs("div", { class: "header-with-btns", children: [_jsx("h1", { children: toTitleCase(entity?.namePlural ?? name) }), _jsx("a", { class: "btn btn--primary", "aria-disabled": true, children: "Add" })] }), _jsx("p", { class: "loading", children: "Loading \u2026" })] }));
44
47
  }
45
48
  const lowerSearchText = searchText.toLowerCase();
46
- const filteredInstances = searchText.length === 0
49
+ const filteredInstances = (searchText.length === 0
47
50
  ? instances
48
51
  : instances.filter(instance => instance.id.includes(searchText) ||
49
- instance.displayName.toLowerCase().includes(lowerSearchText));
52
+ instance.displayName.toLowerCase().includes(lowerSearchText))).map(instance => ({
53
+ ...instance,
54
+ gitStatus: gitClient?.getGitStatusOfInstance(entity.name, instance.id),
55
+ }));
50
56
  const instancesByLocale = Object.groupBy(filteredInstances, instance => instance.displayNameLocaleId ?? "undefined");
51
57
  const groupedInstances = [...locales, "undefined"]
52
58
  .map(key => ({
@@ -59,7 +65,7 @@ export const Entity = () => {
59
65
  .filter(group => group.instances.length > 0);
60
66
  const instanceMapper = (instance) => {
61
67
  const gitStatusForDisplay = getGitStatusForDisplay(instance.gitStatus);
62
- 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.name}/instances/${instance.id}`, class: "btn", children: "Edit" }), _jsx("button", { class: "destructive", onClick: () => {
68
+ 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: [_jsx(GitStatusIndicator, { status: instance.gitStatus }), _jsxs("div", { class: "btns", children: [_jsx("a", { href: `/entities/${entity.name}/instances/${instance.id}`, class: "btn", children: "Edit" }), _jsx("button", { class: "destructive", onClick: () => {
63
69
  if (confirm("Are you sure you want to delete this instance?")) {
64
70
  deleteInstanceByEntityNameAndId(locales, entity.name, instance.id)
65
71
  .then(() => reloadInstances())
@@ -21,7 +21,7 @@ const titleBuilder = ({ locales, entity, instanceId, instanceContent, }) => {
21
21
  }
22
22
  return undefined;
23
23
  };
24
- const onSubmit = async ({ locales, entity, instanceId, instanceContent, buttonName, childInstances, route, }) => {
24
+ const onSubmit = async ({ locales, entity, instanceId, instanceContent, buttonName, childInstances, route, updateLocalGitState, }) => {
25
25
  try {
26
26
  if (instanceId && buttonName) {
27
27
  await updateInstanceByEntityNameAndId(locales, entity.name, instanceId, {
@@ -30,6 +30,7 @@ const onSubmit = async ({ locales, entity, instanceId, instanceContent, buttonNa
30
30
  content: instanceContent,
31
31
  id: instanceId,
32
32
  });
33
+ await updateLocalGitState?.();
33
34
  switch (buttonName) {
34
35
  case "saveandcontinue": {
35
36
  break;
@@ -0,0 +1,2 @@
1
+ export declare const loading: import("@preact/signals-core").Signal<boolean>;
2
+ export declare const runWithLoading: <T>(fn: () => Promise<T>) => Promise<T>;
@@ -0,0 +1,11 @@
1
+ import { signal } from "@preact/signals";
2
+ export const loading = signal(false);
3
+ export const runWithLoading = async (fn) => {
4
+ loading.value = true;
5
+ try {
6
+ return await fn();
7
+ }
8
+ finally {
9
+ loading.value = false;
10
+ }
11
+ };
@@ -15,7 +15,7 @@ export const BlockMarkdown = ({ node, outerHeadingLevel = 0 }) => {
15
15
  return (_jsx("ul", { children: node.content.map((item, ii) => (_jsx("li", { children: item.content.map((inline, iii) => (_jsx(InlineMarkdown, { node: inline }, iii))) }, ii))) }));
16
16
  }
17
17
  case "table":
18
- return (_jsxs("table", { children: [_jsx("thead", { children: _jsx("tr", { children: node.header.map((th, hi) => (_jsx("th", { children: th.map((inline, hii) => (_jsx(InlineMarkdown, { node: inline }, hii))) }, hi))) }) }), _jsx("tbody", { children: node.rows.map((tr, ri) => (_jsx("tr", { children: tr.map((tc, ci) => (_jsx("td", { children: tc.map((inline, cii) => (_jsx(InlineMarkdown, { node: inline }, cii))) }, ci))) }, ri))) })] }));
18
+ return (_jsxs("table", { children: [node.caption !== undefined && (_jsx("caption", { children: node.caption.map((inline, ci) => (_jsx(InlineMarkdown, { node: inline }, ci))) })), _jsx("thead", { children: _jsx("tr", { children: node.header.map((th, hi) => (_jsx("th", { children: th.map((inline, hii) => (_jsx(InlineMarkdown, { node: inline }, hii))) }, hi))) }) }), _jsx("tbody", { children: node.rows.map((tr, ri) => (_jsx("tr", { children: tr.map((tc, ci) => (_jsx("td", { children: tc.map((inline, cii) => (_jsx(InlineMarkdown, { node: inline }, cii))) }, ci))) }, ri))) })] }));
19
19
  default:
20
20
  return null;
21
21
  }
@@ -1 +1,2 @@
1
1
  export declare const printJson: (data: unknown) => string;
2
+ export declare const logAndAlertError: (error: unknown, prependedMessage?: string) => void;
@@ -3,3 +3,7 @@ export const printJson = (data) => JSON.stringify(data, undefined, 2)
3
3
  .replace(/((?:^|\n *)[{[])\n +/g, "$1 ")
4
4
  .replace(/"(.+?)":/g, '<span style="color: darkorange">$1</span>:')
5
5
  .replace(/ "(.*?)"([ ,])/g, ' <span style="color: darkgreen">"$1"</span>$2');
6
+ export const logAndAlertError = (error, prependedMessage) => {
7
+ console.error(error);
8
+ alert((prependedMessage ?? "") + (error instanceof Error ? error.toString() : String(error)));
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsondb",
3
- "version": "0.7.7",
3
+ "version": "0.7.9",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "Lukas Obermann",
@@ -47,13 +47,13 @@
47
47
  "typescript-eslint": "^8.45.0"
48
48
  },
49
49
  "dependencies": {
50
+ "@preact/signals": "^2.3.2",
50
51
  "debug": "^4.4.3",
51
52
  "express": "^5.1.0",
52
53
  "preact": "^10.27.2",
53
54
  "preact-iso": "^2.11.0",
54
55
  "simple-cli-args": "^0.1.3",
55
- "simple-git": "^3.28.0",
56
- "uuid": "^13.0.0"
56
+ "simple-git": "^3.28.0"
57
57
  },
58
58
  "repository": "github:elyukai/tsondb",
59
59
  "bugs": {