inicontent 1.0.0

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 (205) hide show
  1. package/.github/pull_request.yml +18 -0
  2. package/CONTRIBUTING.md +67 -0
  3. package/LICENSE +21 -0
  4. package/README.md +142 -0
  5. package/app/app.vue +106 -0
  6. package/app/assets/main.css +974 -0
  7. package/app/components/Api/EndpointCard.vue +169 -0
  8. package/app/components/Api/SchemaDocsTable.vue +208 -0
  9. package/app/components/Asset/Card.vue +1363 -0
  10. package/app/components/Asset/Grid.vue +295 -0
  11. package/app/components/Asset/Icon.vue +38 -0
  12. package/app/components/Asset/Preview.vue +486 -0
  13. package/app/components/Asset/Scanner.vue +700 -0
  14. package/app/components/Asset/Thumb.vue +708 -0
  15. package/app/components/Auth/Reset.vue +99 -0
  16. package/app/components/Auth/index.vue +346 -0
  17. package/app/components/ChatInterface.vue +2326 -0
  18. package/app/components/ChatPagePreview.vue +34 -0
  19. package/app/components/Column/Array.vue +29 -0
  20. package/app/components/Column/Asset.vue +21 -0
  21. package/app/components/Column/Boolean.vue +12 -0
  22. package/app/components/Column/Color.vue +9 -0
  23. package/app/components/Column/Date.vue +57 -0
  24. package/app/components/Column/Edit.vue +215 -0
  25. package/app/components/Column/Email.vue +9 -0
  26. package/app/components/Column/Html.vue +27 -0
  27. package/app/components/Column/Id.vue +20 -0
  28. package/app/components/Column/Locale.vue +32 -0
  29. package/app/components/Column/Object.vue +18 -0
  30. package/app/components/Column/Password.vue +7 -0
  31. package/app/components/Column/Role.vue +15 -0
  32. package/app/components/Column/S.vue +14 -0
  33. package/app/components/Column/Table/Single.vue +49 -0
  34. package/app/components/Column/Table/index.vue +42 -0
  35. package/app/components/Column/Tags.vue +31 -0
  36. package/app/components/Column/Text.vue +9 -0
  37. package/app/components/Column/Url.vue +9 -0
  38. package/app/components/Column/index.vue +41 -0
  39. package/app/components/Dashboard/Editor.vue +221 -0
  40. package/app/components/Dashboard/Grid.vue +270 -0
  41. package/app/components/Dashboard/View.vue +131 -0
  42. package/app/components/Dashboard/Widget/BarChart.vue +73 -0
  43. package/app/components/Dashboard/Widget/Counter.vue +51 -0
  44. package/app/components/Dashboard/Widget/LineChart.vue +76 -0
  45. package/app/components/Dashboard/Widget/PieChart.vue +75 -0
  46. package/app/components/Dashboard/Widget/Table.vue +94 -0
  47. package/app/components/Dashboard/WidgetEditor.vue +274 -0
  48. package/app/components/Data/Array.vue +102 -0
  49. package/app/components/Data/Html.vue +9 -0
  50. package/app/components/Data/Icon.vue +9 -0
  51. package/app/components/Data/Object.vue +10 -0
  52. package/app/components/Data/S.vue +16 -0
  53. package/app/components/Data/Table.vue +53 -0
  54. package/app/components/Data/Value.vue +34 -0
  55. package/app/components/Data/index.vue +14 -0
  56. package/app/components/Field/Array.vue +324 -0
  57. package/app/components/Field/Asset/Actions.vue +97 -0
  58. package/app/components/Field/Asset/index.vue +639 -0
  59. package/app/components/Field/Boolean.vue +26 -0
  60. package/app/components/Field/Checkbox.vue +48 -0
  61. package/app/components/Field/Color.vue +27 -0
  62. package/app/components/Field/Date.vue +30 -0
  63. package/app/components/Field/Email.vue +51 -0
  64. package/app/components/Field/EmailTemplate.vue +420 -0
  65. package/app/components/Field/Html/ColorPicker.vue +127 -0
  66. package/app/components/Field/Html/Editor.vue +544 -0
  67. package/app/components/Field/Html/index.vue +25 -0
  68. package/app/components/Field/Icon.vue +114 -0
  69. package/app/components/Field/JSON.vue +113 -0
  70. package/app/components/Field/Mention.vue +36 -0
  71. package/app/components/Field/Number.vue +27 -0
  72. package/app/components/Field/Object.vue +92 -0
  73. package/app/components/Field/Password.vue +55 -0
  74. package/app/components/Field/Radio.vue +47 -0
  75. package/app/components/Field/S.vue +44 -0
  76. package/app/components/Field/Select.vue +49 -0
  77. package/app/components/Field/Table.vue +348 -0
  78. package/app/components/Field/Tags.vue +113 -0
  79. package/app/components/Field/Text.vue +31 -0
  80. package/app/components/Field/Textarea.vue +33 -0
  81. package/app/components/Field/Url.vue +40 -0
  82. package/app/components/Field/Wrapper.vue +128 -0
  83. package/app/components/Field/index.vue +68 -0
  84. package/app/components/FloatingChatbot.vue +73 -0
  85. package/app/components/Form/Card.vue +151 -0
  86. package/app/components/Form/Drawer.vue +195 -0
  87. package/app/components/Form/index.vue +621 -0
  88. package/app/components/Header.vue +328 -0
  89. package/app/components/Offline/ConflictModal.vue +200 -0
  90. package/app/components/Offline/SyncStatus.vue +249 -0
  91. package/app/components/PlatformFeatureLanding.vue +65 -0
  92. package/app/components/Table/Backups.vue +638 -0
  93. package/app/components/Table/Flows.vue +814 -0
  94. package/app/components/Table/Grid.vue +296 -0
  95. package/app/components/Table/Icon.vue +36 -0
  96. package/app/components/Table/Logs.vue +181 -0
  97. package/app/components/Table/Schedules.vue +722 -0
  98. package/app/components/Table/Search/Button.vue +256 -0
  99. package/app/components/Table/Search/Items.vue +286 -0
  100. package/app/components/Table/Search/index.vue +87 -0
  101. package/app/components/Table/Settings/Schema.vue +801 -0
  102. package/app/components/Table/Settings/index.vue +631 -0
  103. package/app/components/Table/TranslateDrawer.vue +526 -0
  104. package/app/components/Table/Views/Kanban.vue +289 -0
  105. package/app/components/Table/Views/Table.vue +1273 -0
  106. package/app/components/Table/index.vue +890 -0
  107. package/app/composables/Translation/define.ts +41 -0
  108. package/app/composables/Translation/fetch.ts +107 -0
  109. package/app/composables/Translation/languages.ts +1 -0
  110. package/app/composables/Translation/loadCoreTranslations.ts +38 -0
  111. package/app/composables/Translation/translate.ts +250 -0
  112. package/app/composables/databaseCookies.ts +79 -0
  113. package/app/composables/fieldValidator.ts +72 -0
  114. package/app/composables/fieldsList.ts +301 -0
  115. package/app/composables/formatDatabase.ts +101 -0
  116. package/app/composables/index.ts +444 -0
  117. package/app/composables/openDrawer.ts +118 -0
  118. package/app/composables/optimizeFile.ts +287 -0
  119. package/app/composables/renderLabel.ts +88 -0
  120. package/app/composables/schemaClipboard.ts +95 -0
  121. package/app/composables/search.ts +353 -0
  122. package/app/composables/setThemeConfig.ts +48 -0
  123. package/app/composables/translationValue.ts +169 -0
  124. package/app/composables/useAssetPreview.ts +84 -0
  125. package/app/composables/useAssetUploader.ts +56 -0
  126. package/app/composables/useDashboardData.ts +310 -0
  127. package/app/composables/useDocumentThumbnail.ts +351 -0
  128. package/app/composables/useEcharts.ts +33 -0
  129. package/app/composables/useLocalDatabaseConfig.ts +51 -0
  130. package/app/composables/useOcr.ts +300 -0
  131. package/app/composables/useOfflineFetch.ts +194 -0
  132. package/app/composables/useOfflineItem.ts +107 -0
  133. package/app/composables/useOfflineQueue.ts +302 -0
  134. package/app/composables/useOfflineSync.ts +235 -0
  135. package/app/composables/usePasskeyAuth.ts +156 -0
  136. package/app/composables/usePdfCompressor.ts +180 -0
  137. package/app/composables/usePlatformRedirect.ts +72 -0
  138. package/app/composables/useRealtimeSync.ts +233 -0
  139. package/app/composables/useReferencedItems.ts +180 -0
  140. package/app/composables/useScanner.ts +664 -0
  141. package/app/composables/useSubscription.ts +650 -0
  142. package/app/composables/useThumbnailCache.ts +136 -0
  143. package/app/composables/useVideoCompressor.ts +194 -0
  144. package/app/error.vue +112 -0
  145. package/app/layouts/api.vue +188 -0
  146. package/app/layouts/dashboard.vue +91 -0
  147. package/app/layouts/default.vue +228 -0
  148. package/app/layouts/table.vue +471 -0
  149. package/app/locales/ar.ts +996 -0
  150. package/app/locales/en.ts +655 -0
  151. package/app/locales/es.ts +996 -0
  152. package/app/locales/fr.ts +997 -0
  153. package/app/middleware/dashboard.ts +33 -0
  154. package/app/middleware/database.ts +83 -0
  155. package/app/middleware/global.ts +1 -0
  156. package/app/middleware/sid-ingest.global.ts +29 -0
  157. package/app/middleware/table.ts +54 -0
  158. package/app/middleware/user.ts +26 -0
  159. package/app/pages/[[database]]/admin/api/auth/index.vue +306 -0
  160. package/app/pages/[[database]]/admin/api/index.vue +18 -0
  161. package/app/pages/[[database]]/admin/api/tables/[table]/index.vue +497 -0
  162. package/app/pages/[[database]]/admin/api/tables/index.vue +87 -0
  163. package/app/pages/[[database]]/admin/billing/index.vue +16 -0
  164. package/app/pages/[[database]]/admin/dashboards/[id]/edit.vue +66 -0
  165. package/app/pages/[[database]]/admin/dashboards/[id]/index.vue +117 -0
  166. package/app/pages/[[database]]/admin/dashboards/index.vue +20 -0
  167. package/app/pages/[[database]]/admin/index.vue +28 -0
  168. package/app/pages/[[database]]/admin/settings.vue +526 -0
  169. package/app/pages/[[database]]/admin/tables/[table]/[id]/edit.vue +143 -0
  170. package/app/pages/[[database]]/admin/tables/[table]/[id]/index.vue +146 -0
  171. package/app/pages/[[database]]/admin/tables/[table]/flows.vue +10 -0
  172. package/app/pages/[[database]]/admin/tables/[table]/index.vue +10 -0
  173. package/app/pages/[[database]]/admin/tables/[table]/new.vue +12 -0
  174. package/app/pages/[[database]]/admin/tables/[table]/schedules.vue +10 -0
  175. package/app/pages/[[database]]/admin/tables/[table]/settings.vue +30 -0
  176. package/app/pages/[[database]]/admin/tables/assets/[...path].vue +24 -0
  177. package/app/pages/[[database]]/admin/tables/assets/flows.vue +10 -0
  178. package/app/pages/[[database]]/admin/tables/backups/index.vue +10 -0
  179. package/app/pages/[[database]]/admin/tables/blocks/index.vue +16 -0
  180. package/app/pages/[[database]]/admin/tables/index.vue +20 -0
  181. package/app/pages/[[database]]/admin/tables/pages/index.vue +16 -0
  182. package/app/pages/[[database]]/admin/tables/templates/index.vue +16 -0
  183. package/app/pages/[[database]]/api/index.vue +120 -0
  184. package/app/pages/[[database]]/auth/index.vue +12 -0
  185. package/app/pages/[[database]]/auth/reset.vue +10 -0
  186. package/app/pages/[[database]]/index.vue +10 -0
  187. package/app/plugins/offline-warmup.client.ts +53 -0
  188. package/app/plugins/template-globals.ts +9 -0
  189. package/app/spa-loading-template.html +93 -0
  190. package/biome.json +53 -0
  191. package/index.d.ts +380 -0
  192. package/modules/naiveui.ts +41 -0
  193. package/nuxt.config.ts +269 -0
  194. package/package.json +56 -0
  195. package/pnpm-workspace.yaml +5 -0
  196. package/public/apple-touch-icon.png +0 -0
  197. package/public/favicon-16x16.png +0 -0
  198. package/public/favicon-32x32.png +0 -0
  199. package/public/favicon.ico +0 -0
  200. package/public/pwa-192x192.png +0 -0
  201. package/public/pwa-512x512.png +0 -0
  202. package/public/pwa-maskable-192x192.png +0 -0
  203. package/public/pwa-maskable-512x512.png +0 -0
  204. package/public/vendor/opencv.js +48 -0
  205. package/tsconfig.json +9 -0
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <NFlex vertical :size="16">
3
+ <LazyFormCard v-if="dataObject" v-model="dataObject" />
4
+
5
+ <NCard
6
+ v-if="isCurrentUserProfile"
7
+ :title="t('passkey.securityTitle')"
8
+ hoverable
9
+ >
10
+ <NFlex vertical :size="12">
11
+ <NText depth="3">
12
+ {{ t('passkey.description') }}
13
+ </NText>
14
+
15
+ <NButton
16
+ type="primary"
17
+ secondary
18
+ strong
19
+ :disabled="!isPasskeySupported"
20
+ :loading="isRegisteringPasskey"
21
+ @click="registerPasskey"
22
+ >
23
+ {{ t('passkey.register') }}
24
+ </NButton>
25
+
26
+ <NText depth="3" style="font-size: 12px;">
27
+ {{ passkeyRegisterHint }}
28
+ </NText>
29
+ </NFlex>
30
+ </NCard>
31
+
32
+ <LazyTableLogs v-if="table.config?.log && dataObject" :id="dataObject.id" />
33
+ </NFlex>
34
+ </template>
35
+
36
+ <script lang="ts" setup>
37
+ import Inison from "inison";
38
+ import { usePasskeyAuth } from "~/composables/usePasskeyAuth";
39
+
40
+ definePageMeta({
41
+ middleware: ["database", "user", "dashboard", "table", "global"],
42
+ layout: "table",
43
+ });
44
+
45
+ onBeforeRouteUpdate((route, currentRoute) => {
46
+ if (route.fullPath !== currentRoute.fullPath.slice(0, -5))
47
+ clearNuxtState("currentItem");
48
+ });
49
+
50
+ const route = useRoute();
51
+ const config = useRuntimeConfig();
52
+ const database = useState<Database>("database");
53
+ const table = useState<Table>("table");
54
+ const user = useState<User | undefined>("user");
55
+ const dataObject = ref<Item>({});
56
+ const isRegisteringPasskey = ref(false);
57
+
58
+ const { registerCurrentUserPasskey, isPasskeySupported } = usePasskeyAuth();
59
+
60
+ const isCurrentUserProfile = computed(
61
+ () =>
62
+ table.value?.slug === "users" &&
63
+ String(route.params.id) === String(user.value?.id),
64
+ );
65
+
66
+ const passkeyRegisterHint = computed(() => {
67
+ if (!isPasskeySupported.value) {
68
+ return t("passkey.notSupported");
69
+ }
70
+
71
+ return t("passkey.hint");
72
+ });
73
+
74
+ async function registerPasskey() {
75
+ if (!isPasskeySupported.value) {
76
+ window.$message.error(passkeyRegisterHint.value);
77
+ return;
78
+ }
79
+
80
+ if (isRegisteringPasskey.value) return;
81
+
82
+ isRegisteringPasskey.value = true;
83
+ try {
84
+ const response = await registerCurrentUserPasskey();
85
+ window.$message.success(
86
+ response.message || t("passkey.registeredSuccessfully"),
87
+ );
88
+ } catch (error: unknown) {
89
+ window.$message.error(
90
+ error instanceof Error ? error.message : t("passkey.registrationFailed"),
91
+ );
92
+ } finally {
93
+ isRegisteringPasskey.value = false;
94
+ }
95
+ }
96
+
97
+ const sessionID = useScopedCookie<string>("sid", database.value?.slug);
98
+
99
+ const itemUrl = `${config.public.apiBase}${database.value.slug}/${
100
+ table.value.slug
101
+ }/${route.params.id}`;
102
+ const queryParams = {
103
+ options: Inison.stringify({
104
+ columns: table.value.columns,
105
+ }),
106
+ [`${database.value.slug}_sid`]: sessionID.value,
107
+ };
108
+
109
+ // Fetch the item. Offline (or on a network that answers with junk) fall back
110
+ // to the last known copy — the user's queued offline edit, or the cached item/
111
+ // list response — so editing from outside the table keeps working.
112
+ let fetched: Item | undefined;
113
+ try {
114
+ const res = await $fetch<apiResponse<Item>>(itemUrl, {
115
+ query: queryParams,
116
+ credentials: "include",
117
+ });
118
+ fetched = res?.result;
119
+ } catch (error) {
120
+ if (isNetworkError(error) || isJunkResponse(error)) {
121
+ fetched = await getOfflineItem(
122
+ database.value.slug,
123
+ table.value.slug,
124
+ String(route.params.id),
125
+ itemUrl,
126
+ );
127
+ } else {
128
+ throw error;
129
+ }
130
+ }
131
+
132
+ if (fetched?.id) dataObject.value = fetched;
133
+
134
+ if (!dataObject.value?.id)
135
+ throw createError({
136
+ statusCode: 404,
137
+ statusMessage: "item",
138
+ fatal: true,
139
+ });
140
+
141
+ const currentItem = useState<Item>("currentItem");
142
+ currentItem.value = dataObject.value;
143
+ </script>
@@ -0,0 +1,146 @@
1
+ <template>
2
+ <NFlex vertical>
3
+ <LazyFormDrawer v-if="!$device.isMobile" />
4
+ <NCard style="height: fit-content">
5
+ <template #header>
6
+ <NPerformantEllipsis>{{ t(table.slug) }}: {{ itemLabel }}</NPerformantEllipsis>
7
+ </template>
8
+ <template v-if="table.schema && table.schema.length > 4" #header-extra>
9
+ <NButtonGroup>
10
+ <NTooltip v-if="table.allowedMethods?.includes('u')" :delay="1500">
11
+ <template #trigger>
12
+ <NButton secondary round type="info">
13
+ <template #icon>
14
+ <NuxtLink
15
+ :to="`${$route.params.database ? `/${$route.params.database}` : ''}/admin/tables/${table.slug}/${$route.params.id}/edit`">
16
+ <NIcon>
17
+ <Icon name="tabler:pencil" />
18
+ </NIcon>
19
+ </NuxtLink>
20
+ </template>
21
+ </NButton>
22
+ </template>
23
+ {{ t('edit') }}
24
+ </NTooltip>
25
+
26
+ <NTooltip :delay="1500">
27
+ <template #trigger>
28
+ <NButton type="primary" @click="PRINT" round secondary>
29
+ <template #icon>
30
+ <NIcon>
31
+ <Icon name="tabler:printer" />
32
+ </NIcon>
33
+ </template>
34
+ </NButton>
35
+ </template>
36
+ {{ t('print') }}
37
+ </NTooltip>
38
+ </NButtonGroup>
39
+ </template>
40
+ <template #action>
41
+ <NButtonGroup>
42
+ <NButton v-if="table.allowedMethods?.includes('u')" secondary round type="info">
43
+ <template #icon>
44
+ <NuxtLink
45
+ :to="`${$route.params.database ? `/${$route.params.database}` : ''}/admin/tables/${table.slug}/${$route.params.id}/edit`">
46
+ <NIcon>
47
+ <Icon name="tabler:pencil" />
48
+ </NIcon>
49
+ </NuxtLink>
50
+ </template>
51
+
52
+ {{ t('edit') }}
53
+ </NButton>
54
+
55
+ <NButton type="primary" @click="PRINT" round secondary>
56
+ <template #icon>
57
+ <NIcon>
58
+ <Icon name="tabler:printer" />
59
+ </NIcon>
60
+ </template>
61
+ {{ t('print') }}
62
+ </NButton>
63
+ </NButtonGroup>
64
+ </template>
65
+ <LazyDataS v-if="data && table.schema" :value="data" :schema="table.schema" />
66
+ </NCard>
67
+ <LazyTableLogs v-if="table.config?.log && data" :id="data.id" />
68
+ </NFlex>
69
+ </template>
70
+
71
+ <script lang="ts" setup>
72
+ import Inison from "inison";
73
+
74
+ onBeforeRouteUpdate((route, currentRoute) => {
75
+ if (`${decodeURIComponent(currentRoute.fullPath)}/edit` !== route.fullPath)
76
+ clearNuxtState("currentItem");
77
+ });
78
+
79
+ definePageMeta({
80
+ middleware: ["database", "user", "dashboard", "table", "global"],
81
+ layout: "table",
82
+ });
83
+
84
+ const config = useRuntimeConfig();
85
+ const route = useRoute();
86
+ const database = useState<Database>("database");
87
+ const table = useState<Table>("table");
88
+
89
+ const sessionID = useScopedCookie<string>("sid", database.value?.slug);
90
+
91
+ const itemUrl = `${config.public.apiBase}${database.value.slug}/${
92
+ table.value.slug
93
+ }/${route.params.id}`;
94
+ const queryParams = {
95
+ options: Inison.stringify({
96
+ columns: table.value.columns,
97
+ }),
98
+ [`${database.value.slug}_sid`]: sessionID.value,
99
+ };
100
+
101
+ // Fetch the item. Offline, fall back to the last known copy so the detail
102
+ // page (and from there edit/PRINT/logs) keep working outside the table grid.
103
+ let loaded: Item | undefined;
104
+ try {
105
+ const res = await $fetch<apiResponse<Item>>(itemUrl, {
106
+ query: queryParams,
107
+ credentials: "include",
108
+ });
109
+ loaded = res?.result;
110
+ } catch (error) {
111
+ if (isNetworkError(error) || isJunkResponse(error)) {
112
+ loaded = await getOfflineItem(
113
+ database.value.slug,
114
+ table.value.slug,
115
+ String(route.params.id),
116
+ itemUrl,
117
+ );
118
+ } else {
119
+ throw error;
120
+ }
121
+ }
122
+
123
+ const data = ref<Item>(loaded);
124
+
125
+ if (!data.value?.id)
126
+ throw createError({
127
+ statusCode: 404,
128
+ statusMessage: "item",
129
+ fatal: true,
130
+ });
131
+
132
+ function PRINT() {
133
+ window.print();
134
+ }
135
+
136
+ const currentItem = useState<Item>("currentItem");
137
+ currentItem.value = data.value;
138
+ const itemLabel = renderLabel(table.value, data.value);
139
+
140
+ useHead({
141
+ title: `${t(database.value.slug)} | ${t(table.value.slug)} : ${itemLabel}`,
142
+ link: [
143
+ { rel: "icon", href: database.value?.icon?.publicURL ?? "/favicon.ico" },
144
+ ],
145
+ });
146
+ </script>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <TableFlows />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ middleware: ["database", "user", "dashboard", "table", "global"],
8
+ layout: "table",
9
+ })
10
+ </script>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <Table></Table>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ definePageMeta({
7
+ middleware: ["database", "user", "dashboard", "table", "global"],
8
+ layout: "table",
9
+ })
10
+ </script>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <FormCard v-model="data" />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ middleware: ["database", "user", "dashboard", "table", "global"],
8
+ layout: "table",
9
+ });
10
+
11
+ const data = ref<Item>({});
12
+ </script>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <TableSchedules />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ middleware: ["database", "user", "dashboard", "table", "global"],
8
+ layout: "table",
9
+ })
10
+ </script>
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <TableSettings />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ middleware: [
8
+ "database",
9
+ "user",
10
+ "dashboard",
11
+ "table",
12
+ (route) => {
13
+ if (
14
+ ["sessions", "translations", "assets"].includes(
15
+ route.params.table as string,
16
+ )
17
+ ) {
18
+ // Same as the table middleware: a thrown error is silently
19
+ // swallowed during client-side navigation, so surface it via
20
+ // showError() and let the navigation complete.
21
+ showError(createError({
22
+ statusCode: 403,
23
+ }))
24
+ return true
25
+ }
26
+ },
27
+ ],
28
+ layout: "table",
29
+ })
30
+ </script>
@@ -0,0 +1,24 @@
1
+ <template>
2
+ <AssetCard />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ middleware: ["database", "user", "dashboard", "table", "global"],
8
+ layout: "table",
9
+ })
10
+
11
+ const route = useRoute()
12
+ const database = useState<Database>("database")
13
+
14
+ useHead({
15
+ title: `${t(database.value.slug)} | ${t("assets")}${
16
+ route.params.folder
17
+ ? ` > /${[].concat(route.params.folder as any).join("/")}`
18
+ : ""
19
+ }`,
20
+ link: [
21
+ { rel: "icon", href: database.value?.icon?.publicURL ?? "/favicon.ico" },
22
+ ],
23
+ })
24
+ </script>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <TableFlows />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ middleware: ["database", "user", "dashboard", "table", "global"],
8
+ layout: "table",
9
+ })
10
+ </script>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <TableBackups />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ middleware: ["database", "user", "dashboard", "table", "global"],
8
+ layout: "table",
9
+ });
10
+ </script>
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <PlatformFeatureLanding feature="blocks" />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ layout: "table",
8
+ middleware: ["database", "user", "dashboard", "global"],
9
+ });
10
+
11
+ const database = useState<Database>("database");
12
+
13
+ useHead({
14
+ title: `${t("blocks")} | ${t(database.value.slug)} | ${t("dashboard")}`,
15
+ });
16
+ </script>
@@ -0,0 +1,20 @@
1
+ <template>
2
+ <NCard :title="t('tables')" style="background:none" :bordered="false">
3
+ <LazyTableGrid v-model="database" />
4
+ </NCard>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ definePageMeta({
9
+ layout: "dashboard",
10
+ middleware: ["database", "user", "dashboard", "global"],
11
+ })
12
+
13
+ const database = useState<Database>("database")
14
+ useHead({
15
+ title: `${t(database.value.slug)} | ${t("tables")}`,
16
+ link: [
17
+ { rel: "icon", href: database.value?.icon?.publicURL ?? "/favicon.ico" },
18
+ ],
19
+ })
20
+ </script>
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <PlatformFeatureLanding feature="pages" />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ layout: "table",
8
+ middleware: ["database", "user", "dashboard", "global"],
9
+ });
10
+
11
+ const database = useState<Database>("database");
12
+
13
+ useHead({
14
+ title: `${t("pages")} | ${t(database.value.slug)} | ${t("dashboard")}`,
15
+ });
16
+ </script>
@@ -0,0 +1,16 @@
1
+ <template>
2
+ <PlatformFeatureLanding feature="templates" />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ layout: "table",
8
+ middleware: ["database", "user", "dashboard", "global"],
9
+ });
10
+
11
+ const database = useState<Database>("database");
12
+
13
+ useHead({
14
+ title: `${t("templates")} | ${t(database.value.slug)} | ${t("dashboard")}`,
15
+ });
16
+ </script>
@@ -0,0 +1,120 @@
1
+ <template>
2
+ <main>
3
+ <NFlex vertical size="large" style="padding: 24px 0">
4
+ <NCard :bordered="false" style="background:none">
5
+ <template #header>
6
+ <NH1 style="margin: 0">{{ t('apiDocs.publicApi.title') }}</NH1>
7
+ </template>
8
+ <NText type="secondary">{{ t('apiDocs.publicApi.description') }}</NText>
9
+ <NAlert type="info" :show-icon="false" style="margin-top: 12px">
10
+ {{ t('publicApiHint') }}
11
+ <NuxtLink :to="authPath" style="margin-inline-start: 6px">
12
+ {{ t('loginLink') }}
13
+ </NuxtLink>
14
+ </NAlert>
15
+ </NCard>
16
+
17
+ <NGrid :x-gap="12" :y-gap="12" cols="1 500:2 800:3">
18
+ <NGridItem v-for="tableOption in publicTables" :key="tableOption.slug">
19
+ <NCard hoverable>
20
+ <template #header>
21
+ <NFlex align="center">
22
+ <NIconWrapper :border-radius="50" style="font-style: normal">
23
+ <LazyTableIcon :table="tableOption" />
24
+ </NIconWrapper>
25
+ <NH4 style="margin: 0">{{ t(tableOption.slug) }}</NH4>
26
+ </NFlex>
27
+ </template>
28
+ <NFlex vertical :size="8">
29
+ <NText strong>{{ t('readAccess') }}</NText>
30
+ <NText type="secondary">{{ t('apiDocs.publicApi.collectionEndpoint') }}</NText>
31
+ <code class="api-endpoint">{{ `${tableOption.http} ${tableOption.collectionPath}` }}</code>
32
+ <NText type="secondary">{{ t('apiDocs.publicApi.singleEndpoint') }}</NText>
33
+ <code class="api-endpoint">{{ `${tableOption.http} ${tableOption.singlePath}` }}</code>
34
+ </NFlex>
35
+ </NCard>
36
+ </NGridItem>
37
+ </NGrid>
38
+ </NFlex>
39
+ </main>
40
+ </template>
41
+
42
+ <script setup lang="ts">
43
+ definePageMeta({
44
+ layout: "default",
45
+ middleware: ["database", "global"],
46
+ });
47
+
48
+ const config = useRuntimeConfig();
49
+ const database = useState<Database>("database");
50
+ const route = useRoute();
51
+ const sessionID = useScopedCookie<string>("sid", database.value?.slug);
52
+
53
+ const authPath = computed(
54
+ () => `${route.params.database ? `/${route.params.database}` : ""}/auth`,
55
+ );
56
+
57
+ const shouldRedirect = await useAsyncData("api-doc-auth", async () => {
58
+ if (!database.value?.slug || !sessionID.value) return false;
59
+ try {
60
+ const data = await $fetch<{ result: boolean }>(
61
+ `${config.public.apiBase}${database.value.slug}/auth/current`,
62
+ {
63
+ credentials: "include",
64
+ query: {
65
+ isSignedIn: true,
66
+ [`${database.value.slug}_sid`]: sessionID.value,
67
+ },
68
+ },
69
+ );
70
+ return data.result;
71
+ } catch (error) {
72
+ return false;
73
+ }
74
+ });
75
+
76
+ if (shouldRedirect.data.value) {
77
+ await navigateTo(
78
+ `${route.params.database ? `/${route.params.database}` : ""}/admin/api`,
79
+ );
80
+ }
81
+
82
+ const publicTables = computed(() =>
83
+ (database.value?.tables ?? [])
84
+ .filter(
85
+ ({ allowedMethods, show }) =>
86
+ allowedMethods?.includes("r") && show !== false,
87
+ )
88
+ .map((tableItem) => {
89
+ const baseSlug = database.value?.slug ?? "inicontent";
90
+ const basePath = `${config.public.apiBase}${baseSlug}/${tableItem.slug}`;
91
+ return {
92
+ ...tableItem,
93
+ http: "GET",
94
+ collectionPath: `${basePath}?page=1&limit=25`,
95
+ singlePath: `${basePath}/{id}`,
96
+ };
97
+ }),
98
+ );
99
+
100
+ useHead({
101
+ title: `${t(database.value?.slug ?? "inicontent")} | ${t("publicApiTitle")}`,
102
+ meta: [
103
+ {
104
+ name: "description",
105
+ content: `Public read-only API for ${database.value?.slug ?? "inicontent"}. Browse publicly accessible table endpoints.`,
106
+ },
107
+ ],
108
+ });
109
+ </script>
110
+
111
+ <style scoped>
112
+ .api-endpoint {
113
+ background-color: rgba(0, 0, 0, 0.04);
114
+ border-radius: 6px;
115
+ padding: 6px 8px;
116
+ overflow-x: auto;
117
+ display: block;
118
+ font-family: inherit;
119
+ }
120
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <div class="centerCard">
3
+ <Auth />
4
+ </div>
5
+ </template>
6
+
7
+ <script lang="ts" setup>
8
+ definePageMeta({
9
+ layout: "dashboard",
10
+ middleware: ["database", "user", "dashboard", "global"],
11
+ })
12
+ </script>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <AuthReset />
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ definePageMeta({
7
+ layout: "dashboard",
8
+ middleware: ["database", "user", "dashboard", "global"],
9
+ })
10
+ </script>
@@ -0,0 +1,10 @@
1
+ <template></template>
2
+
3
+ <script lang="ts" setup>
4
+ definePageMeta({
5
+ layout: "dashboard",
6
+ middleware: ["database", "user", "dashboard", "global"],
7
+ })
8
+
9
+ await navigateTo("admin")
10
+ </script>