@budibase/frontend-core 3.2.28 → 3.2.30
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/package.json +9 -3
- package/src/api/ai.ts +17 -0
- package/src/api/analytics.ts +39 -0
- package/src/api/{app.js → app.ts} +84 -5
- package/src/api/attachments.ts +121 -0
- package/src/api/auditLogs.ts +35 -0
- package/src/api/{auth.js → auth.ts} +44 -7
- package/src/api/automations.ts +158 -0
- package/src/api/backups.ts +50 -0
- package/src/api/{configs.js → configs.ts} +31 -3
- package/src/api/datasources.ts +132 -0
- package/src/api/environmentVariables.ts +58 -0
- package/src/api/events.ts +21 -0
- package/src/api/flags.ts +48 -0
- package/src/api/{groups.js → groups.ts} +73 -17
- package/src/api/{index.js → index.ts} +89 -102
- package/src/api/layouts.ts +35 -0
- package/src/api/licensing.ts +107 -0
- package/src/api/{logs.js → logs.ts} +7 -1
- package/src/api/migrations.ts +19 -0
- package/src/api/{other.js → other.ts} +19 -12
- package/src/api/{permissions.js → permissions.ts} +31 -5
- package/src/api/{plugins.js → plugins.ts} +18 -1
- package/src/api/{queries.js → queries.ts} +39 -14
- package/src/api/relationships.ts +31 -0
- package/src/api/{roles.js → roles.ts} +22 -5
- package/src/api/routes.ts +30 -0
- package/src/api/{rowActions.js → rowActions.ts} +45 -27
- package/src/api/rows.ts +120 -0
- package/src/api/screens.ts +35 -0
- package/src/api/{self.js → self.ts} +20 -4
- package/src/api/tables.ts +192 -0
- package/src/api/templates.ts +57 -0
- package/src/api/types.ts +136 -0
- package/src/api/{user.js → user.ts} +111 -119
- package/src/api/{views.js → views.ts} +18 -7
- package/src/api/{viewsV2.js → viewsV2.ts} +30 -27
- package/src/components/grid/cells/AICell.svelte +1 -0
- package/src/components/grid/cells/LongFormCell.svelte +1 -0
- package/src/components/grid/cells/RelationshipCell.svelte +1 -2
- package/src/components/grid/cells/TextCell.svelte +3 -0
- package/src/components/grid/controls/MigrationModal.svelte +5 -5
- package/src/components/grid/layout/Grid.svelte +5 -8
- package/src/components/grid/lib/constants.js +1 -1
- package/src/components/grid/lib/{events.js → events.ts} +3 -3
- package/src/components/grid/lib/utils.js +2 -0
- package/src/components/grid/lib/utils.ts +32 -0
- package/src/components/grid/stores/bounds.ts +29 -0
- package/src/components/grid/stores/{cache.js → cache.ts} +21 -6
- package/src/components/grid/stores/{clipboard.js → clipboard.ts} +55 -19
- package/src/components/grid/stores/{columns.js → columns.ts} +47 -19
- package/src/components/grid/stores/{conditions.js → conditions.ts} +32 -12
- package/src/components/grid/stores/{config.js → config.ts} +16 -6
- package/src/components/grid/stores/{datasource.js → datasource.ts} +86 -36
- package/src/components/grid/stores/datasources/index.ts +31 -0
- package/src/components/grid/stores/datasources/{nonPlus.js → nonPlus.ts} +21 -11
- package/src/components/grid/stores/datasources/{table.js → table.ts} +39 -21
- package/src/components/grid/stores/datasources/{viewV2.js → viewV2.ts} +74 -28
- package/src/components/grid/stores/{filter.js → filter.ts} +39 -16
- package/src/components/grid/stores/index.ts +143 -0
- package/src/components/grid/stores/{menu.js → menu.ts} +31 -6
- package/src/components/grid/stores/{notifications.js → notifications.ts} +12 -2
- package/src/components/grid/stores/{pagination.js → pagination.ts} +2 -1
- package/src/components/grid/stores/{reorder.js → reorder.ts} +47 -15
- package/src/components/grid/stores/{resize.js → resize.ts} +28 -10
- package/src/components/grid/stores/{rows.js → rows.ts} +167 -53
- package/src/components/grid/stores/{scroll.js → scroll.ts} +28 -5
- package/src/components/grid/stores/{sort.js → sort.ts} +13 -3
- package/src/components/grid/stores/{ui.js → ui.ts} +77 -20
- package/src/components/grid/stores/{users.js → users.ts} +36 -9
- package/src/components/grid/stores/{validation.js → validation.ts} +35 -12
- package/src/components/grid/stores/{viewport.js → viewport.ts} +14 -3
- package/src/{constants.js → constants.ts} +2 -2
- package/src/fetch/QueryFetch.js +2 -2
- package/src/fetch/RelationshipFetch.js +9 -6
- package/src/fetch/TableFetch.js +1 -2
- package/src/fetch/ViewFetch.js +1 -1
- package/src/fetch/ViewV2Fetch.js +1 -2
- package/src/utils/memo.d.ts +10 -0
- package/src/utils/relatedColumns.ts +126 -0
- package/tsconfig.json +14 -0
- package/src/api/ai.js +0 -11
- package/src/api/analytics.js +0 -17
- package/src/api/attachments.js +0 -78
- package/src/api/auditLogs.js +0 -63
- package/src/api/automations.js +0 -111
- package/src/api/backups.js +0 -46
- package/src/api/datasources.js +0 -92
- package/src/api/environmentVariables.js +0 -36
- package/src/api/events.js +0 -13
- package/src/api/flags.js +0 -34
- package/src/api/hosting.js +0 -19
- package/src/api/layouts.js +0 -23
- package/src/api/licensing.js +0 -75
- package/src/api/migrations.js +0 -10
- package/src/api/relationships.js +0 -21
- package/src/api/routes.js +0 -19
- package/src/api/rows.js +0 -117
- package/src/api/screens.js +0 -23
- package/src/api/tables.js +0 -152
- package/src/api/templates.js +0 -35
- package/src/components/grid/stores/bounds.js +0 -16
- package/src/components/grid/stores/index.js +0 -73
- package/src/utils/relatedColumns.js +0 -103
- /package/src/{index.js → index.ts} +0 -0
- /package/src/utils/{index.js → index.ts} +0 -0
|
@@ -74,12 +74,14 @@
|
|
|
74
74
|
.value {
|
|
75
75
|
display: -webkit-box;
|
|
76
76
|
-webkit-line-clamp: var(--content-lines);
|
|
77
|
+
line-clamp: var(--content-lines);
|
|
77
78
|
-webkit-box-orient: vertical;
|
|
78
79
|
overflow: hidden;
|
|
79
80
|
line-height: 20px;
|
|
80
81
|
}
|
|
81
82
|
.number .value {
|
|
82
83
|
-webkit-line-clamp: 1;
|
|
84
|
+
line-clamp: 1;
|
|
83
85
|
}
|
|
84
86
|
input {
|
|
85
87
|
flex: 1 1 auto;
|
|
@@ -110,5 +112,6 @@
|
|
|
110
112
|
}
|
|
111
113
|
input[type="number"] {
|
|
112
114
|
-moz-appearance: textfield;
|
|
115
|
+
appearance: textfield;
|
|
113
116
|
}
|
|
114
117
|
</style>
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
|
|
30
30
|
const migrateUserColumn = async () => {
|
|
31
31
|
try {
|
|
32
|
-
await API.migrateColumn(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
await API.migrateColumn(
|
|
33
|
+
$definition._id,
|
|
34
|
+
column.schema.name,
|
|
35
|
+
newColumnName
|
|
36
|
+
)
|
|
37
37
|
notifications.success("Column migrated")
|
|
38
38
|
} catch (e) {
|
|
39
39
|
notifications.error(`Failed to migrate: ${e.message}`)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import { setContext, onMount } from "svelte"
|
|
3
3
|
import { writable, derived } from "svelte/store"
|
|
4
4
|
import { fade } from "svelte/transition"
|
|
@@ -47,24 +47,22 @@
|
|
|
47
47
|
export let buttonsCollapsedText = null
|
|
48
48
|
export let darkMode = false
|
|
49
49
|
export let isCloud = null
|
|
50
|
-
export let rowConditions = null
|
|
51
50
|
export let aiEnabled = false
|
|
52
51
|
|
|
53
52
|
// Unique identifier for DOM nodes inside this instance
|
|
54
53
|
const gridID = `grid-${Math.random().toString().slice(2)}`
|
|
55
54
|
|
|
56
55
|
// Store props in a store for reference in other stores
|
|
57
|
-
const props = writable($$props)
|
|
56
|
+
const props: any = writable($$props)
|
|
58
57
|
|
|
59
58
|
// Build up context
|
|
60
|
-
let context = {
|
|
59
|
+
let context = attachStores({
|
|
61
60
|
API: API || createAPIClient(),
|
|
62
61
|
Constants,
|
|
63
62
|
gridID,
|
|
64
63
|
props,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
context = attachStores(context)
|
|
64
|
+
...createEventManagers(),
|
|
65
|
+
})
|
|
68
66
|
|
|
69
67
|
// Reference some stores for local use
|
|
70
68
|
const {
|
|
@@ -106,7 +104,6 @@
|
|
|
106
104
|
darkMode,
|
|
107
105
|
isCloud,
|
|
108
106
|
aiEnabled,
|
|
109
|
-
rowConditions,
|
|
110
107
|
})
|
|
111
108
|
|
|
112
109
|
// Derive min height and make available in context
|
|
@@ -7,7 +7,7 @@ export const HPadding = 40
|
|
|
7
7
|
export const ScrollBarSize = 8
|
|
8
8
|
export const GutterWidth = 72
|
|
9
9
|
export const DefaultColumnWidth = 200
|
|
10
|
-
export const MinColumnWidth =
|
|
10
|
+
export const MinColumnWidth = 56
|
|
11
11
|
export const NewRowID = "new"
|
|
12
12
|
export const BlankRowID = "blank"
|
|
13
13
|
export const GeneratedIDPrefix = "‽‽"
|
|
@@ -2,11 +2,11 @@ import { createEventDispatcher } from "svelte"
|
|
|
2
2
|
|
|
3
3
|
export const createEventManagers = () => {
|
|
4
4
|
const svelteDispatch = createEventDispatcher()
|
|
5
|
-
let subscribers = {}
|
|
5
|
+
let subscribers: Record<string, ((...params: any) => void)[]> = {}
|
|
6
6
|
|
|
7
7
|
// Dispatches an event, notifying subscribers and also emitting a normal
|
|
8
8
|
// svelte event
|
|
9
|
-
const dispatch = (event, payload) => {
|
|
9
|
+
const dispatch = (event: string, payload: any) => {
|
|
10
10
|
svelteDispatch(event, payload)
|
|
11
11
|
const subs = subscribers[event] || []
|
|
12
12
|
for (let i = 0; i < subs.length; i++) {
|
|
@@ -15,7 +15,7 @@ export const createEventManagers = () => {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
// Subscribes to events
|
|
18
|
-
const subscribe = (event, callback) => {
|
|
18
|
+
const subscribe = (event: string, callback: () => void) => {
|
|
19
19
|
const subs = subscribers[event] || []
|
|
20
20
|
subscribers[event] = [...subs, callback]
|
|
21
21
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { GeneratedIDPrefix, CellIDSeparator } from "./constants"
|
|
2
|
+
import { Helpers } from "@budibase/bbui"
|
|
3
|
+
|
|
4
|
+
export const parseCellID = (cellId: string | null) => {
|
|
5
|
+
if (!cellId) {
|
|
6
|
+
return { rowId: undefined, field: undefined }
|
|
7
|
+
}
|
|
8
|
+
const parts = cellId.split(CellIDSeparator)
|
|
9
|
+
const field = parts.pop()
|
|
10
|
+
return { rowId: parts.join(CellIDSeparator), field }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const getCellID = (rowId: string, fieldName: string) => {
|
|
14
|
+
return `${rowId}${CellIDSeparator}${fieldName}`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const parseEventLocation = (event: MouseEvent | TouchEvent) => {
|
|
18
|
+
const e = event as MouseEvent & TouchEvent
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
x: e.clientX ?? e.touches?.[0]?.clientX,
|
|
22
|
+
y: e.clientY ?? e.touches?.[0]?.clientY,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const generateRowID = () => {
|
|
27
|
+
return `${GeneratedIDPrefix}${Helpers.uuid()}`
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const isGeneratedRowID = (id: string) => {
|
|
31
|
+
return id?.startsWith(GeneratedIDPrefix)
|
|
32
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { derived, Readable, Writable, writable } from "svelte/store"
|
|
2
|
+
|
|
3
|
+
interface BoundsStore {
|
|
4
|
+
bounds: Writable<{
|
|
5
|
+
left: number
|
|
6
|
+
top: number
|
|
7
|
+
width: number
|
|
8
|
+
height: number
|
|
9
|
+
}>
|
|
10
|
+
height: Readable<number>
|
|
11
|
+
width: Readable<number>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Store = BoundsStore
|
|
15
|
+
|
|
16
|
+
export const createStores = (): BoundsStore => {
|
|
17
|
+
const bounds = writable({
|
|
18
|
+
left: 0,
|
|
19
|
+
top: 0,
|
|
20
|
+
width: 0,
|
|
21
|
+
height: 0,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// Derive height and width as primitives to avoid wasted computation
|
|
25
|
+
const width = derived(bounds, $bounds => $bounds.width, 0)
|
|
26
|
+
const height = derived(bounds, $bounds => $bounds.height, 0)
|
|
27
|
+
|
|
28
|
+
return { bounds, height, width }
|
|
29
|
+
}
|
|
@@ -1,16 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
import { FindTableResponse } from "@budibase/types"
|
|
2
|
+
import { Store as StoreContext } from "."
|
|
3
|
+
|
|
4
|
+
interface CacheActionStore {
|
|
5
|
+
cache: {
|
|
6
|
+
actions: {
|
|
7
|
+
getPrimaryDisplayForTableId: (tableId: string) => Promise<string>
|
|
8
|
+
getTable: (tableId: string) => Promise<FindTableResponse>
|
|
9
|
+
resetCache: () => any
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Store = CacheActionStore
|
|
15
|
+
|
|
16
|
+
export const createActions = (context: StoreContext): CacheActionStore => {
|
|
2
17
|
const { API } = context
|
|
3
18
|
|
|
4
19
|
// Cache for the primary display columns of different tables.
|
|
5
20
|
// If we ever need to cache table definitions for other purposes then we can
|
|
6
21
|
// expand this to be a more generic cache.
|
|
7
|
-
let tableCache = {}
|
|
22
|
+
let tableCache: Record<string, Promise<FindTableResponse>> = {}
|
|
8
23
|
|
|
9
24
|
const resetCache = () => {
|
|
10
25
|
tableCache = {}
|
|
11
26
|
}
|
|
12
27
|
|
|
13
|
-
const fetchTable = async tableId => {
|
|
28
|
+
const fetchTable = async (tableId: string) => {
|
|
14
29
|
// If we've never encountered this tableId before then store a promise that
|
|
15
30
|
// resolves to the primary display so that subsequent invocations before the
|
|
16
31
|
// promise completes can reuse this promise
|
|
@@ -21,13 +36,13 @@ export const createActions = context => {
|
|
|
21
36
|
return await tableCache[tableId]
|
|
22
37
|
}
|
|
23
38
|
|
|
24
|
-
const getPrimaryDisplayForTableId = async tableId => {
|
|
39
|
+
const getPrimaryDisplayForTableId = async (tableId: string) => {
|
|
25
40
|
const table = await fetchTable(tableId)
|
|
26
41
|
const display = table?.primaryDisplay || table?.schema?.[0]?.name
|
|
27
42
|
return display
|
|
28
43
|
}
|
|
29
44
|
|
|
30
|
-
const getTable = async tableId => {
|
|
45
|
+
const getTable = async (tableId: string) => {
|
|
31
46
|
const table = await fetchTable(tableId)
|
|
32
47
|
return table
|
|
33
48
|
}
|
|
@@ -43,7 +58,7 @@ export const createActions = context => {
|
|
|
43
58
|
}
|
|
44
59
|
}
|
|
45
60
|
|
|
46
|
-
export const initialise = context => {
|
|
61
|
+
export const initialise = (context: StoreContext) => {
|
|
47
62
|
const { datasource, cache } = context
|
|
48
63
|
|
|
49
64
|
// Wipe the caches whenever the datasource changes to ensure we aren't
|
|
@@ -1,10 +1,41 @@
|
|
|
1
|
-
import { derived, writable, get } from "svelte/store"
|
|
1
|
+
import { derived, writable, get, Writable, Readable } from "svelte/store"
|
|
2
2
|
import { Helpers } from "@budibase/bbui"
|
|
3
3
|
import { parseCellID, getCellID } from "../lib/utils"
|
|
4
4
|
import { NewRowID } from "../lib/constants"
|
|
5
|
+
import { Store as StoreContext } from "."
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
type ClipboardStoreData =
|
|
8
|
+
| {
|
|
9
|
+
value: any[][]
|
|
10
|
+
multiCellCopy: true
|
|
11
|
+
}
|
|
12
|
+
| {
|
|
13
|
+
value: any | null | undefined
|
|
14
|
+
multiCellCopy: false
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ClipboardStore {
|
|
18
|
+
clipboard: Writable<ClipboardStoreData>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface ClipboardDerivedStore {
|
|
22
|
+
copyAllowed: Readable<boolean>
|
|
23
|
+
pasteAllowed: Readable<boolean>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ClipboardActions {
|
|
27
|
+
clipboard: ClipboardStore["clipboard"] & {
|
|
28
|
+
actions: {
|
|
29
|
+
copy: () => void
|
|
30
|
+
paste: (progressCallback: () => void) => Promise<void>
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type Store = ClipboardStore & ClipboardDerivedStore & ClipboardActions
|
|
36
|
+
|
|
37
|
+
export const createStores = (): ClipboardStore => {
|
|
38
|
+
const clipboard = writable<ClipboardStoreData>({
|
|
8
39
|
value: null,
|
|
9
40
|
multiCellCopy: false,
|
|
10
41
|
})
|
|
@@ -13,7 +44,7 @@ export const createStores = () => {
|
|
|
13
44
|
}
|
|
14
45
|
}
|
|
15
46
|
|
|
16
|
-
export const deriveStores = context => {
|
|
47
|
+
export const deriveStores = (context: StoreContext): ClipboardDerivedStore => {
|
|
17
48
|
const { clipboard, focusedCellAPI, selectedCellCount, config, focusedRowId } =
|
|
18
49
|
context
|
|
19
50
|
|
|
@@ -60,7 +91,7 @@ export const deriveStores = context => {
|
|
|
60
91
|
}
|
|
61
92
|
}
|
|
62
93
|
|
|
63
|
-
export const createActions = context => {
|
|
94
|
+
export const createActions = (context: StoreContext): ClipboardActions => {
|
|
64
95
|
const {
|
|
65
96
|
clipboard,
|
|
66
97
|
focusedCellAPI,
|
|
@@ -92,11 +123,11 @@ export const createActions = context => {
|
|
|
92
123
|
const $rowChangeCache = get(rowChangeCache)
|
|
93
124
|
|
|
94
125
|
// Extract value of each selected cell, accounting for the change cache
|
|
95
|
-
|
|
96
|
-
for (
|
|
126
|
+
const value = []
|
|
127
|
+
for (const row of $selectedCells) {
|
|
97
128
|
const rowValues = []
|
|
98
|
-
for (
|
|
99
|
-
const { rowId, field } = parseCellID(cellId)
|
|
129
|
+
for (const cellId of row) {
|
|
130
|
+
const { rowId = "", field = "" } = parseCellID(cellId)
|
|
100
131
|
const row = {
|
|
101
132
|
...$rowLookupMap[rowId],
|
|
102
133
|
...$rowChangeCache[rowId],
|
|
@@ -113,7 +144,7 @@ export const createActions = context => {
|
|
|
113
144
|
})
|
|
114
145
|
} else {
|
|
115
146
|
// Single value to copy
|
|
116
|
-
const value = $focusedCellAPI
|
|
147
|
+
const value = $focusedCellAPI?.getValue()
|
|
117
148
|
clipboard.set({
|
|
118
149
|
value,
|
|
119
150
|
multiCellCopy,
|
|
@@ -130,7 +161,7 @@ export const createActions = context => {
|
|
|
130
161
|
}
|
|
131
162
|
|
|
132
163
|
// Pastes the previously copied value(s) into the selected cell(s)
|
|
133
|
-
const paste = async progressCallback => {
|
|
164
|
+
const paste = async (progressCallback: () => void) => {
|
|
134
165
|
if (!get(pasteAllowed)) {
|
|
135
166
|
return
|
|
136
167
|
}
|
|
@@ -166,8 +197,8 @@ export const createActions = context => {
|
|
|
166
197
|
const { rowId, field } = parseCellID($focusedCellId)
|
|
167
198
|
const $rowLookupMap = get(rowLookupMap)
|
|
168
199
|
const $columnLookupMap = get(columnLookupMap)
|
|
169
|
-
const rowIdx = $rowLookupMap[rowId].__idx
|
|
170
|
-
const colIdx = $columnLookupMap[field].__idx
|
|
200
|
+
const rowIdx = $rowLookupMap[rowId!].__idx
|
|
201
|
+
const colIdx = $columnLookupMap[field!].__idx || 0
|
|
171
202
|
|
|
172
203
|
// Get limits of how many rows and columns we're able to paste into
|
|
173
204
|
const $rows = get(rows)
|
|
@@ -187,7 +218,7 @@ export const createActions = context => {
|
|
|
187
218
|
// Paste into target cell range
|
|
188
219
|
if (targetCellId === $focusedCellId) {
|
|
189
220
|
// Single cell edge case
|
|
190
|
-
get(focusedCellAPI)
|
|
221
|
+
get(focusedCellAPI)?.setValue(value[0][0])
|
|
191
222
|
} else {
|
|
192
223
|
// Select the new cells to paste into, then paste
|
|
193
224
|
selectedCells.actions.selectRange($focusedCellId, targetCellId)
|
|
@@ -197,17 +228,20 @@ export const createActions = context => {
|
|
|
197
228
|
} else {
|
|
198
229
|
if (multiCellPaste) {
|
|
199
230
|
// Single to multi - duplicate value to all selected cells
|
|
200
|
-
const newValue = get(selectedCells).map(row => row.map(() => value))
|
|
231
|
+
const newValue = get(selectedCells).map(row => row.map(() => value!))
|
|
201
232
|
await pasteIntoSelectedCells(newValue, progressCallback)
|
|
202
233
|
} else {
|
|
203
234
|
// Single to single - just update the cell's value
|
|
204
|
-
get(focusedCellAPI)
|
|
235
|
+
get(focusedCellAPI)?.setValue(value ?? null)
|
|
205
236
|
}
|
|
206
237
|
}
|
|
207
238
|
}
|
|
208
239
|
|
|
209
240
|
// Paste the specified value into the currently selected cells
|
|
210
|
-
const pasteIntoSelectedCells = async (
|
|
241
|
+
const pasteIntoSelectedCells = async (
|
|
242
|
+
value: string[][],
|
|
243
|
+
progressCallback: () => any
|
|
244
|
+
) => {
|
|
211
245
|
const $selectedCells = get(selectedCells)
|
|
212
246
|
|
|
213
247
|
// Find the extent at which we can paste
|
|
@@ -215,11 +249,13 @@ export const createActions = context => {
|
|
|
215
249
|
const colExtent = Math.min(value[0].length, $selectedCells[0].length)
|
|
216
250
|
|
|
217
251
|
// Build change map
|
|
218
|
-
let changeMap = {}
|
|
252
|
+
let changeMap: Record<string, Record<string, string>> = {}
|
|
219
253
|
for (let rowIdx = 0; rowIdx < rowExtent; rowIdx++) {
|
|
220
254
|
for (let colIdx = 0; colIdx < colExtent; colIdx++) {
|
|
221
255
|
const cellId = $selectedCells[rowIdx][colIdx]
|
|
222
|
-
|
|
256
|
+
let { rowId, field } = parseCellID(cellId)
|
|
257
|
+
rowId = rowId!
|
|
258
|
+
field = field!
|
|
223
259
|
if (!changeMap[rowId]) {
|
|
224
260
|
changeMap[rowId] = {}
|
|
225
261
|
}
|
|
@@ -1,8 +1,34 @@
|
|
|
1
|
-
import { derived, get, writable } from "svelte/store"
|
|
1
|
+
import { derived, get, Readable, Writable, writable } from "svelte/store"
|
|
2
2
|
import { DefaultColumnWidth, GutterWidth } from "../lib/constants"
|
|
3
|
+
import { UIColumn } from "@budibase/types"
|
|
4
|
+
import { Store as StoreContext } from "."
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
interface ColumnStore {
|
|
7
|
+
columns: Writable<UIColumn[]>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface DerivedColumnStore {
|
|
11
|
+
tableColumns: Readable<UIColumn[]>
|
|
12
|
+
displayColumn: Readable<UIColumn | undefined>
|
|
13
|
+
columnLookupMap: Readable<Record<string, UIColumn>>
|
|
14
|
+
visibleColumns: Readable<UIColumn[]>
|
|
15
|
+
scrollableColumns: Readable<UIColumn[]>
|
|
16
|
+
hasNonAutoColumn: Readable<boolean>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ColumnActions {
|
|
20
|
+
columns: ColumnStore["columns"] & {
|
|
21
|
+
actions: {
|
|
22
|
+
changeAllColumnWidths: (width: number) => Promise<void>
|
|
23
|
+
isReadonly: (column: UIColumn) => boolean
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type Store = ColumnStore & DerivedColumnStore & ColumnActions
|
|
29
|
+
|
|
30
|
+
export const createStores = (): ColumnStore => {
|
|
31
|
+
const columns = writable<UIColumn[]>([])
|
|
6
32
|
|
|
7
33
|
// Enrich columns with metadata about their display position
|
|
8
34
|
const enrichedColumns = derived(columns, $columns => {
|
|
@@ -16,7 +42,7 @@ export const createStores = () => {
|
|
|
16
42
|
}
|
|
17
43
|
if (col.visible) {
|
|
18
44
|
idx++
|
|
19
|
-
offset += col.width
|
|
45
|
+
offset += col.width ?? 0
|
|
20
46
|
}
|
|
21
47
|
return enriched
|
|
22
48
|
})
|
|
@@ -30,12 +56,12 @@ export const createStores = () => {
|
|
|
30
56
|
}
|
|
31
57
|
}
|
|
32
58
|
|
|
33
|
-
export const deriveStores = context => {
|
|
59
|
+
export const deriveStores = (context: StoreContext): DerivedColumnStore => {
|
|
34
60
|
const { columns } = context
|
|
35
61
|
|
|
36
62
|
// Derive a lookup map for all columns by name
|
|
37
63
|
const columnLookupMap = derived(columns, $columns => {
|
|
38
|
-
let map = {}
|
|
64
|
+
let map: Record<string, UIColumn> = {}
|
|
39
65
|
$columns.forEach(column => {
|
|
40
66
|
map[column.name] = column
|
|
41
67
|
})
|
|
@@ -78,11 +104,11 @@ export const deriveStores = context => {
|
|
|
78
104
|
}
|
|
79
105
|
}
|
|
80
106
|
|
|
81
|
-
export const createActions = context => {
|
|
107
|
+
export const createActions = (context: StoreContext): ColumnActions => {
|
|
82
108
|
const { columns, datasource } = context
|
|
83
109
|
|
|
84
110
|
// Updates the width of all columns
|
|
85
|
-
const changeAllColumnWidths = async width => {
|
|
111
|
+
const changeAllColumnWidths = async (width: number) => {
|
|
86
112
|
const $columns = get(columns)
|
|
87
113
|
$columns.forEach(column => {
|
|
88
114
|
const { related } = column
|
|
@@ -101,7 +127,7 @@ export const createActions = context => {
|
|
|
101
127
|
}
|
|
102
128
|
|
|
103
129
|
// Checks if a column is readonly
|
|
104
|
-
const isReadonly = column => {
|
|
130
|
+
const isReadonly = (column: UIColumn) => {
|
|
105
131
|
if (!column?.schema) {
|
|
106
132
|
return false
|
|
107
133
|
}
|
|
@@ -125,21 +151,21 @@ export const createActions = context => {
|
|
|
125
151
|
}
|
|
126
152
|
}
|
|
127
153
|
|
|
128
|
-
export const initialise = context => {
|
|
154
|
+
export const initialise = (context: StoreContext) => {
|
|
129
155
|
const { definition, columns, displayColumn, enrichedSchema } = context
|
|
130
156
|
|
|
131
157
|
// Merge new schema fields with existing schema in order to preserve widths
|
|
132
|
-
const processColumns = $enrichedSchema => {
|
|
133
|
-
|
|
158
|
+
const processColumns = ($enrichedSchema: any) => {
|
|
159
|
+
const $definition = get(definition)
|
|
160
|
+
if (!$enrichedSchema || !$definition) {
|
|
134
161
|
columns.set([])
|
|
135
162
|
return
|
|
136
163
|
}
|
|
137
|
-
|
|
138
|
-
const $columns = get(columns)
|
|
164
|
+
|
|
139
165
|
const $displayColumn = get(displayColumn)
|
|
140
166
|
|
|
141
167
|
// Find primary display
|
|
142
|
-
let primaryDisplay
|
|
168
|
+
let primaryDisplay: string
|
|
143
169
|
const candidatePD = $definition.primaryDisplay || $displayColumn?.name
|
|
144
170
|
if (candidatePD && $enrichedSchema[candidatePD]) {
|
|
145
171
|
primaryDisplay = candidatePD
|
|
@@ -150,18 +176,20 @@ export const initialise = context => {
|
|
|
150
176
|
Object.keys($enrichedSchema)
|
|
151
177
|
.map(field => {
|
|
152
178
|
const fieldSchema = $enrichedSchema[field]
|
|
153
|
-
const
|
|
154
|
-
|
|
179
|
+
const column: UIColumn = {
|
|
180
|
+
type: fieldSchema.type,
|
|
155
181
|
name: field,
|
|
156
182
|
label: fieldSchema.displayName || field,
|
|
157
183
|
schema: fieldSchema,
|
|
158
|
-
width: fieldSchema.width ||
|
|
184
|
+
width: fieldSchema.width || DefaultColumnWidth,
|
|
159
185
|
visible: fieldSchema.visible ?? true,
|
|
160
186
|
readonly: fieldSchema.readonly,
|
|
161
|
-
order: fieldSchema.order
|
|
187
|
+
order: fieldSchema.order,
|
|
162
188
|
conditions: fieldSchema.conditions,
|
|
163
189
|
related: fieldSchema.related,
|
|
164
190
|
calculationType: fieldSchema.calculationType,
|
|
191
|
+
__left: undefined as any, // TODO
|
|
192
|
+
__idx: undefined as any, // TODO
|
|
165
193
|
}
|
|
166
194
|
// Override a few properties for primary display
|
|
167
195
|
if (field === primaryDisplay) {
|
|
@@ -1,15 +1,31 @@
|
|
|
1
|
-
import { writable, get } from "svelte/store"
|
|
1
|
+
import { writable, get, Writable, Readable } from "svelte/store"
|
|
2
2
|
import { derivedMemo, QueryUtils } from "../../../utils"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
FieldType,
|
|
5
|
+
EmptyFilterOption,
|
|
6
|
+
UIRow,
|
|
7
|
+
UICondition,
|
|
8
|
+
} from "@budibase/types"
|
|
9
|
+
import { Store as StoreContext } from "."
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
interface ConditionStore {
|
|
12
|
+
metadata: Writable<Record<string, any>>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface ConditionDerivedStore {
|
|
16
|
+
conditions: Readable<UICondition[]>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type Store = ConditionStore & ConditionDerivedStore
|
|
20
|
+
|
|
21
|
+
export const createStores = (): ConditionStore => {
|
|
6
22
|
const metadata = writable({})
|
|
7
23
|
return {
|
|
8
24
|
metadata,
|
|
9
25
|
}
|
|
10
26
|
}
|
|
11
27
|
|
|
12
|
-
export const deriveStores = context => {
|
|
28
|
+
export const deriveStores = (context: StoreContext): ConditionDerivedStore => {
|
|
13
29
|
const { columns } = context
|
|
14
30
|
|
|
15
31
|
// Derive and memoize the cell conditions present in our columns so that we
|
|
@@ -33,12 +49,12 @@ export const deriveStores = context => {
|
|
|
33
49
|
}
|
|
34
50
|
}
|
|
35
51
|
|
|
36
|
-
export const initialise = context => {
|
|
52
|
+
export const initialise = (context: StoreContext) => {
|
|
37
53
|
const { metadata, conditions, rows } = context
|
|
38
54
|
|
|
39
55
|
// Recompute all metadata if conditions change
|
|
40
56
|
conditions.subscribe($conditions => {
|
|
41
|
-
let newMetadata = {}
|
|
57
|
+
let newMetadata: Record<string, any> = {}
|
|
42
58
|
if ($conditions?.length) {
|
|
43
59
|
for (let row of get(rows)) {
|
|
44
60
|
newMetadata[row._id] = evaluateConditions(row, $conditions)
|
|
@@ -54,7 +70,7 @@ export const initialise = context => {
|
|
|
54
70
|
return
|
|
55
71
|
}
|
|
56
72
|
const $metadata = get(metadata)
|
|
57
|
-
let metadataUpdates = {}
|
|
73
|
+
let metadataUpdates: Record<string, any> = {}
|
|
58
74
|
for (let row of $rows) {
|
|
59
75
|
if (!row._rev || $metadata[row._id]?.version !== row._rev) {
|
|
60
76
|
metadataUpdates[row._id] = evaluateConditions(row, $conditions)
|
|
@@ -69,15 +85,15 @@ export const initialise = context => {
|
|
|
69
85
|
})
|
|
70
86
|
}
|
|
71
87
|
|
|
72
|
-
const TypeCoercionMap = {
|
|
88
|
+
const TypeCoercionMap: Partial<Record<FieldType, (val: string) => any>> = {
|
|
73
89
|
[FieldType.NUMBER]: parseFloat,
|
|
74
|
-
[FieldType.DATETIME]: val => {
|
|
90
|
+
[FieldType.DATETIME]: (val: string) => {
|
|
75
91
|
if (val) {
|
|
76
92
|
return new Date(val).toISOString()
|
|
77
93
|
}
|
|
78
94
|
return null
|
|
79
95
|
},
|
|
80
|
-
[FieldType.BOOLEAN]: val => {
|
|
96
|
+
[FieldType.BOOLEAN]: (val: string) => {
|
|
81
97
|
if (`${val}`.toLowerCase().trim() === "true") {
|
|
82
98
|
return true
|
|
83
99
|
}
|
|
@@ -90,8 +106,12 @@ const TypeCoercionMap = {
|
|
|
90
106
|
|
|
91
107
|
// Evaluates an array of cell conditions against a certain row and returns the
|
|
92
108
|
// resultant metadata
|
|
93
|
-
const evaluateConditions = (row, conditions) => {
|
|
94
|
-
|
|
109
|
+
const evaluateConditions = (row: UIRow, conditions: UICondition[]) => {
|
|
110
|
+
const metadata: {
|
|
111
|
+
version?: string
|
|
112
|
+
row: Record<string, string>
|
|
113
|
+
cell: Record<string, any>
|
|
114
|
+
} = {
|
|
95
115
|
version: row._rev,
|
|
96
116
|
row: {},
|
|
97
117
|
cell: {},
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { derivedMemo } from "../../../utils"
|
|
2
|
-
import { derived } from "svelte/store"
|
|
2
|
+
import { derived, Readable } from "svelte/store"
|
|
3
3
|
import { ViewV2Type } from "@budibase/types"
|
|
4
|
+
import { BaseStoreProps, Store as StoreContext } from "."
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
type ConfigStore = {
|
|
7
|
+
[key in keyof BaseStoreProps]: Readable<BaseStoreProps[key]>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface ConfigDerivedStore {
|
|
11
|
+
config: Readable<BaseStoreProps>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type Store = ConfigStore & ConfigDerivedStore
|
|
15
|
+
|
|
16
|
+
export const createStores = (context: StoreContext): ConfigStore => {
|
|
6
17
|
const { props } = context
|
|
7
|
-
const getProp =
|
|
18
|
+
const getProp = <T extends keyof BaseStoreProps>(prop: T) =>
|
|
19
|
+
derivedMemo(props, $props => $props[prop])
|
|
8
20
|
|
|
9
21
|
// Derive and memoize some props so that we can react to them in isolation
|
|
10
22
|
const datasource = getProp("datasource")
|
|
@@ -15,7 +27,6 @@ export const createStores = context => {
|
|
|
15
27
|
const schemaOverrides = getProp("schemaOverrides")
|
|
16
28
|
const notifySuccess = getProp("notifySuccess")
|
|
17
29
|
const notifyError = getProp("notifyError")
|
|
18
|
-
const rowConditions = getProp("rowConditions")
|
|
19
30
|
|
|
20
31
|
return {
|
|
21
32
|
datasource,
|
|
@@ -26,11 +37,10 @@ export const createStores = context => {
|
|
|
26
37
|
schemaOverrides,
|
|
27
38
|
notifySuccess,
|
|
28
39
|
notifyError,
|
|
29
|
-
rowConditions,
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
42
|
|
|
33
|
-
export const deriveStores = context => {
|
|
43
|
+
export const deriveStores = (context: StoreContext): ConfigDerivedStore => {
|
|
34
44
|
const { props, definition, hasNonAutoColumn } = context
|
|
35
45
|
|
|
36
46
|
// Derive features
|