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,289 @@
1
+ <template>
2
+ <div>
3
+ <div class="kanban-scroll">
4
+ <div class="kanban-columns">
5
+ <NCard v-for="(column, index) in visibleColumns" :key="index" hoverable class="kanban-column">
6
+ <NTag size="large" :color="column.color"
7
+ style="width: 100%; justify-content: space-between; flex-direction: row-reverse; margin-bottom: 20px"
8
+ :bordered="false" round>
9
+ {{ column.label }}
10
+ <NButton circle :color="column.color?.textColor" size="tiny" :text-color="column.color?.color">
11
+ {{ column.pagination?.total || 0 }}
12
+ </NButton>
13
+ <template #icon>
14
+ <NButton circle secondary size="tiny" @click.prevent="() => {
15
+ if (!isMobile)
16
+ openDrawer(table?.slug as string, undefined, { [field?.key as string]: column.key === UNSET_KEY ? '' : column.key })
17
+ else
18
+ navigateTo(`${$route.params.database ? `/${$route.params.database}` : ''}/admin/tables/${table?.slug}/new`);
19
+ }">
20
+ <template #icon>
21
+ <NIcon :color="column.color?.textColor">
22
+ <Icon name="tabler:plus" />
23
+ </NIcon>
24
+ </template>
25
+ </NButton>
26
+ </template>
27
+ </NTag>
28
+ <NScrollbar style="max-height: 350px;">
29
+ <VueDraggable v-model="column.items" :group="{ name: 'items', pull: true, put: true }"
30
+ item-key="id" ghost-class="ghost" :sort="false" @move="({ to, from }: any) => from !== to"
31
+ @change="(e: any) => onItemDrop(e, column)">
32
+ <template v-for="(element, index) in column.items">
33
+ <NCard size="small" style="border-radius: 8px;margin-bottom: 10px;" hoverable>
34
+ <component v-if="props.slots.itemActions" :is="props.slots.itemActions(element)" />
35
+ <component v-else-if="props.slots.itemExtraActions"
36
+ :is="props.slots.itemExtraActions(element)" />
37
+ <NPopover scrollable style="max-height: 240px;border-radius:34px"
38
+ contentStyle="padding: 0">
39
+ <template #trigger>
40
+ <NButton size="tiny" round class="dotsButton" secondary type="primary">
41
+ <template #icon>
42
+ <NIcon>
43
+ <Icon name="tabler:dots" />
44
+ </NIcon>
45
+ </template>
46
+ </NButton>
47
+ </template>
48
+ <component :is="renderItemButtons(column.items[index])" />
49
+ </NPopover>
50
+ <ClientOnly v-if="props.slots.item">
51
+ <component
52
+ v-for="(slot, slotIndex) in ([] as VNode[]).concat(props.slots.item(element))"
53
+ :is="slot" :key="slotIndex" :item="element"></component>
54
+ </ClientOnly>
55
+ <div v-else v-html="renderLabel(table, element).replaceAll('\n', '<br />')"></div>
56
+ </NCard>
57
+ </template>
58
+ </VueDraggable>
59
+ <template v-if="column.items.length === 0 && column.loading">
60
+ <NSkeleton :height="calculateHeight" style="border-radius: 8px;margin-bottom: 10px;" />
61
+ <NSkeleton :height="calculateHeight" style="border-radius: 8px;" />
62
+ </template>
63
+ <NEmpty v-else-if="column.items.length === 0" style="height: 100%;justify-content: center" />
64
+ </NScrollbar>
65
+ </NCard>
66
+ </div>
67
+ </div>
68
+ </div>
69
+ </template>
70
+
71
+ <script lang="ts" setup>
72
+ import type { pageInfo } from "inibase"
73
+ import { isArrayOfArrays, isArrayOfObjects } from "inibase/utils"
74
+ import Inison from "inison"
75
+ import type { TagColor } from "naive-ui/es/tag/src/common-props"
76
+ import { VueDraggable } from "vue-draggable-plus"
77
+
78
+ const props = defineProps<{
79
+ slots: any
80
+ }>()
81
+
82
+ type columnType = {
83
+ label: string
84
+ key: string | number
85
+ items: Item[]
86
+ pagination?: pageInfo
87
+ color?: TagColor
88
+ loading?: boolean
89
+ }
90
+
91
+ // const dataModel = defineModel<apiResponse<Item[]>>("data")
92
+ const data = ref<columnType[]>()
93
+ const searchString = defineModel<string>("searchString")
94
+
95
+ const renderItemButtons = inject("renderItemButtons") as (item: Item) => VNode
96
+
97
+ const config = useRuntimeConfig()
98
+ const { isMobile } = useDevice()
99
+
100
+ const database = useState<Database>("database")
101
+ const table = useState<Table>("table")
102
+ const field = table.value?.schema?.find(({ id }) => id === table.value?.groupBy)
103
+
104
+ const UNSET_KEY = "__unset__" // internal sentinel
105
+
106
+ const visibleColumns = ref()
107
+
108
+ if (field?.options) {
109
+ if (isArrayOfArrays(field.options))
110
+ data.value = (field.options as [string | number, string][]).map(
111
+ ([label]) => ({
112
+ label: t(label),
113
+ key: label,
114
+ color: getColorObj(label, field.options as [string | number, string][]),
115
+ items: [],
116
+ loading: true,
117
+ }),
118
+ )
119
+ else if (isArrayOfObjects(field.options))
120
+ data.value = (
121
+ field.options as {
122
+ label: string
123
+ value: string | number
124
+ }[]
125
+ ).map(({ label, value }) => ({
126
+ label: t(label),
127
+ key: value,
128
+ items: [],
129
+ loading: true,
130
+ }))
131
+ else
132
+ data.value = (field.options as string[]).map((value) => ({
133
+ label: t(value),
134
+ key: value,
135
+ items: [],
136
+ loading: true,
137
+ }))
138
+
139
+ const unsetColumn: columnType = {
140
+ label: t("unspecified"),
141
+ key: UNSET_KEY,
142
+ items: [],
143
+ loading: true,
144
+ color: { color: "#f0f0f0", textColor: "#606060" } satisfies TagColor,
145
+ }
146
+
147
+ nextTick(() => {
148
+ if (data.value) {
149
+ data.value.push(unsetColumn)
150
+ visibleColumns.value = data.value.filter(
151
+ (c) => c && (c.key !== UNSET_KEY || c.items.length > 0),
152
+ )
153
+ }
154
+ nextTick(executeFetch)
155
+ })
156
+ }
157
+
158
+ const sessionID = useScopedCookie<string>("sid", database.value?.slug)
159
+
160
+ // Watch searchString changes and refetch data for Kanban view
161
+ watch(
162
+ searchString,
163
+ (value) => {
164
+ if (data.value) executeFetch()
165
+ }
166
+ )
167
+
168
+ async function executeFetch() {
169
+ for await (const column of data.value as columnType[]) {
170
+ column.loading = true
171
+ const columnWhere = Inison.stringify({
172
+ [(field as Field).key]: column.key === UNSET_KEY ? "" : column.key,
173
+ })
174
+ const _data = await $fetch<apiResponse<Item[]>>(
175
+ `${config.public.apiBase}${database.value.slug}/${table.value?.slug}`,
176
+ {
177
+ query: {
178
+ where: searchString.value
179
+ ? `${columnWhere.slice(0, -1)},${searchString.value.slice(1)}`
180
+ : columnWhere,
181
+ [`${database.value.slug}_sid`]: sessionID.value,
182
+ },
183
+ credentials: "include",
184
+ },
185
+ )
186
+ column.items = _data.result || []
187
+ column.pagination = _data.options
188
+ column.loading = false
189
+ }
190
+ }
191
+
192
+ const calculateHeight = computed(() => {
193
+ const baseHeight = 50 // Base height for skeleton
194
+ const lineHeight = 20 // Height per line
195
+ const maxHeight = 200 // Maximum height limit
196
+
197
+ const lineBreaks = (table.value?.label?.match(/\n/g) || []).length
198
+ const calculatedHeight = baseHeight + lineBreaks * lineHeight
199
+ return `${Math.min(calculatedHeight, maxHeight)}px`
200
+ })
201
+
202
+ const Language = useScopedCookie<LanguagesType>("language", database.value?.slug)
203
+
204
+ const onItemDrop = async (evt: any, targetColumn: columnType) => {
205
+ if (!evt.added || !field?.key || !data.value || !table.value?.slug) return
206
+
207
+ const card = evt.added.element as Item
208
+ const fromKey = card[field.key] // old column key
209
+ const toKey = targetColumn.key // new column key
210
+ if (fromKey === toKey) return
211
+
212
+ /* optimistic UI ------------------------------------------------- */
213
+ card[field.key] = toKey
214
+ adjustTotals(fromKey, toKey)
215
+
216
+ /* API call ------------------------------------------------------ */
217
+ const _data = await $fetch<apiResponse>(
218
+ `${config.public.apiBase}${database.value.slug}/${table.value.slug}/${card.id}`,
219
+ {
220
+ method: "PUT",
221
+ body: { [field.key]: toKey === UNSET_KEY ? "" : toKey },
222
+ params: {
223
+ return: false,
224
+ locale: Language.value,
225
+ [`${database.value.slug}_sid`]: sessionID.value,
226
+ },
227
+ credentials: "include",
228
+ },
229
+ )
230
+ if (!_data.result) {
231
+ /* rollback ---------------------------------------------------- */
232
+ card[field.key] = fromKey
233
+ adjustTotals(toKey, fromKey) // undo the optimistic counts
234
+
235
+ /* put card back visually */
236
+ const origin = data.value.find((c) => c.key === fromKey)
237
+ if (origin)
238
+ origin.items.push(targetColumn.items.splice(evt.added.newIndex, 1)[0] as Item)
239
+
240
+ window.$message.error(_data.message)
241
+ }
242
+ }
243
+
244
+ function adjustTotals(from: any, to: any) {
245
+ const dec = data.value?.find((c) => c.key === from)
246
+ const inc = data.value?.find((c) => c.key === to)
247
+ if (dec?.pagination)
248
+ dec.pagination.total = Math.max((dec.pagination.total ?? 1) - 1, 0)
249
+ if (inc?.pagination) inc.pagination.total = (inc.pagination.total ?? 0) + 1
250
+ }
251
+ </script>
252
+
253
+
254
+ <style scoped>
255
+ .dotsButton {
256
+ position: absolute;
257
+ }
258
+
259
+ .ltr .dotsButton {
260
+ right: 10px;
261
+ }
262
+
263
+ .rtl .dotsButton {
264
+ left: 10px;
265
+ }
266
+
267
+ .kanban-scroll {
268
+ overflow-x: auto;
269
+ padding-bottom: 10px;
270
+ }
271
+
272
+ .kanban-columns {
273
+ display: flex;
274
+ gap: 20px;
275
+ min-width: max-content;
276
+ }
277
+
278
+ .kanban-column {
279
+ flex: 0 0 300px;
280
+ display: flex;
281
+ flex-direction: column;
282
+ gap: 10px;
283
+ border-radius: 8px;
284
+ }
285
+
286
+ .kanban-card {
287
+ min-height: 300px;
288
+ }
289
+ </style>