@budibase/frontend-core 2.26.3 → 2.27.3
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 +5 -5
- package/src/components/SignatureModal.svelte +59 -0
- package/src/components/grid/cells/AttachmentCell.svelte +3 -10
- package/src/components/grid/cells/DataCell.svelte +0 -4
- package/src/components/grid/cells/DateCell.svelte +1 -2
- package/src/components/grid/cells/HeaderCell.svelte +3 -8
- package/src/components/grid/cells/LongFormCell.svelte +1 -2
- package/src/components/grid/cells/OptionsCell.svelte +1 -2
- package/src/components/grid/cells/RelationshipCell.svelte +1 -2
- package/src/components/grid/cells/SignatureCell.svelte +162 -0
- package/src/components/grid/controls/HideColumnsButton.svelte +14 -30
- package/src/components/grid/layout/Grid.svelte +13 -4
- package/src/components/grid/layout/GridBody.svelte +1 -6
- package/src/components/grid/layout/GridRow.svelte +1 -5
- package/src/components/grid/layout/NewRow.svelte +1 -14
- package/src/components/grid/lib/renderers.js +2 -0
- package/src/components/grid/stores/columns.js +7 -57
- package/src/components/grid/stores/datasource.js +103 -35
- package/src/components/grid/stores/reorder.js +16 -12
- package/src/components/grid/stores/resize.js +8 -36
- package/src/components/grid/stores/viewport.js +1 -46
- package/src/components/index.js +1 -0
- package/src/constants.js +1 -0
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/frontend-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.27.3",
|
|
4
4
|
"description": "Budibase frontend core libraries used in builder and client",
|
|
5
5
|
"author": "Budibase",
|
|
6
6
|
"license": "MPL-2.0",
|
|
7
7
|
"svelte": "src/index.js",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@budibase/bbui": "2.
|
|
10
|
-
"@budibase/shared-core": "2.
|
|
11
|
-
"@budibase/types": "2.
|
|
9
|
+
"@budibase/bbui": "2.27.3",
|
|
10
|
+
"@budibase/shared-core": "2.27.3",
|
|
11
|
+
"@budibase/types": "2.27.3",
|
|
12
12
|
"dayjs": "^1.10.8",
|
|
13
13
|
"lodash": "4.17.21",
|
|
14
14
|
"shortid": "2.2.15",
|
|
15
15
|
"socket.io-client": "^4.6.1"
|
|
16
16
|
},
|
|
17
|
-
"gitHead": "
|
|
17
|
+
"gitHead": "7edd7b2ee3284719cd17f7004a17f4ed5d818c65"
|
|
18
18
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Modal, ModalContent, Body, CoreSignature } from "@budibase/bbui"
|
|
3
|
+
|
|
4
|
+
export let onConfirm = () => {}
|
|
5
|
+
export let value
|
|
6
|
+
export let title
|
|
7
|
+
export let darkMode
|
|
8
|
+
|
|
9
|
+
export const show = () => {
|
|
10
|
+
edited = false
|
|
11
|
+
modal.show()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let modal
|
|
15
|
+
let canvas
|
|
16
|
+
let edited = false
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<Modal bind:this={modal}>
|
|
20
|
+
<ModalContent
|
|
21
|
+
showConfirmButton
|
|
22
|
+
showCancelButton={false}
|
|
23
|
+
showCloseIcon={false}
|
|
24
|
+
custom
|
|
25
|
+
disabled={!edited}
|
|
26
|
+
showDivider={false}
|
|
27
|
+
onConfirm={() => {
|
|
28
|
+
onConfirm(canvas)
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<div slot="header">
|
|
32
|
+
<Body>{title}</Body>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="signature-wrap modal">
|
|
35
|
+
<CoreSignature
|
|
36
|
+
{darkMode}
|
|
37
|
+
{value}
|
|
38
|
+
saveIcon={false}
|
|
39
|
+
bind:this={canvas}
|
|
40
|
+
on:update={() => {
|
|
41
|
+
edited = true
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
</ModalContent>
|
|
46
|
+
</Modal>
|
|
47
|
+
|
|
48
|
+
<style>
|
|
49
|
+
.signature-wrap {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
justify-content: flex-start;
|
|
53
|
+
align-items: stretch;
|
|
54
|
+
background-color: var(--spectrum-global-color-gray-50);
|
|
55
|
+
color: var(--spectrum-alias-text-color);
|
|
56
|
+
box-sizing: border-box;
|
|
57
|
+
position: relative;
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
@@ -8,11 +8,10 @@
|
|
|
8
8
|
export let onChange
|
|
9
9
|
export let readonly = false
|
|
10
10
|
export let api
|
|
11
|
-
export let invertX = false
|
|
12
11
|
export let schema
|
|
13
12
|
export let maximum
|
|
14
13
|
|
|
15
|
-
const { API, notifications } = getContext("grid")
|
|
14
|
+
const { API, notifications, props } = getContext("grid")
|
|
16
15
|
const imageExtensions = ["png", "tiff", "gif", "raw", "jpg", "jpeg"]
|
|
17
16
|
|
|
18
17
|
let isOpen = false
|
|
@@ -92,13 +91,7 @@
|
|
|
92
91
|
</div>
|
|
93
92
|
|
|
94
93
|
{#if isOpen}
|
|
95
|
-
<GridPopover
|
|
96
|
-
open={isOpen}
|
|
97
|
-
{anchor}
|
|
98
|
-
{invertX}
|
|
99
|
-
maxHeight={null}
|
|
100
|
-
on:close={close}
|
|
101
|
-
>
|
|
94
|
+
<GridPopover open={isOpen} {anchor} maxHeight={null} on:close={close}>
|
|
102
95
|
<div class="dropzone">
|
|
103
96
|
<Dropzone
|
|
104
97
|
{value}
|
|
@@ -106,7 +99,7 @@
|
|
|
106
99
|
on:change={e => onChange(e.detail)}
|
|
107
100
|
maximum={maximum || schema.constraints?.length?.maximum}
|
|
108
101
|
{processFiles}
|
|
109
|
-
{handleFileTooLarge}
|
|
102
|
+
handleFileTooLarge={$props.isCloud ? handleFileTooLarge : null}
|
|
110
103
|
/>
|
|
111
104
|
</div>
|
|
112
105
|
</GridPopover>
|
|
@@ -18,8 +18,6 @@
|
|
|
18
18
|
export let row
|
|
19
19
|
export let cellId
|
|
20
20
|
export let updateValue = rows.actions.updateValue
|
|
21
|
-
export let invertX = false
|
|
22
|
-
export let invertY = false
|
|
23
21
|
export let contentLines = 1
|
|
24
22
|
export let hidden = false
|
|
25
23
|
|
|
@@ -93,8 +91,6 @@
|
|
|
93
91
|
onChange={cellAPI.setValue}
|
|
94
92
|
{focused}
|
|
95
93
|
{readonly}
|
|
96
|
-
{invertY}
|
|
97
|
-
{invertX}
|
|
98
94
|
{contentLines}
|
|
99
95
|
/>
|
|
100
96
|
<slot />
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
export let focused = false
|
|
11
11
|
export let readonly = false
|
|
12
12
|
export let api
|
|
13
|
-
export let invertX = false
|
|
14
13
|
|
|
15
14
|
let isOpen
|
|
16
15
|
let anchor
|
|
@@ -111,7 +110,7 @@
|
|
|
111
110
|
</div>
|
|
112
111
|
|
|
113
112
|
{#if isOpen}
|
|
114
|
-
<GridPopover {anchor}
|
|
113
|
+
<GridPopover {anchor} maxHeight={null} on:close={close}>
|
|
115
114
|
<CoreDatePickerPopoverContents
|
|
116
115
|
value={parsedValue}
|
|
117
116
|
useKeyboardShortcuts={false}
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
subscribe,
|
|
24
24
|
config,
|
|
25
25
|
ui,
|
|
26
|
-
columns,
|
|
27
26
|
definition,
|
|
28
27
|
datasource,
|
|
29
28
|
schema,
|
|
@@ -158,17 +157,13 @@
|
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
const makeDisplayColumn = () => {
|
|
161
|
-
|
|
160
|
+
datasource.actions.changePrimaryDisplay(column.name)
|
|
162
161
|
open = false
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
const hideColumn = () => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
state[index].visible = false
|
|
169
|
-
return state.slice()
|
|
170
|
-
})
|
|
171
|
-
columns.actions.saveChanges()
|
|
165
|
+
datasource.actions.addSchemaMutation(column.name, { visible: false })
|
|
166
|
+
datasource.actions.saveSchemaMutations()
|
|
172
167
|
open = false
|
|
173
168
|
}
|
|
174
169
|
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
export let onChange
|
|
9
9
|
export let readonly = false
|
|
10
10
|
export let api
|
|
11
|
-
export let invertX = false
|
|
12
11
|
|
|
13
12
|
let textarea
|
|
14
13
|
let isOpen = false
|
|
@@ -67,7 +66,7 @@
|
|
|
67
66
|
</div>
|
|
68
67
|
|
|
69
68
|
{#if isOpen}
|
|
70
|
-
<GridPopover {anchor}
|
|
69
|
+
<GridPopover {anchor} on:close={close}>
|
|
71
70
|
<textarea
|
|
72
71
|
bind:this={textarea}
|
|
73
72
|
value={value || ""}
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
export let multi = false
|
|
12
12
|
export let readonly = false
|
|
13
13
|
export let api
|
|
14
|
-
export let invertX
|
|
15
14
|
export let contentLines = 1
|
|
16
15
|
|
|
17
16
|
let isOpen = false
|
|
@@ -120,7 +119,7 @@
|
|
|
120
119
|
</div>
|
|
121
120
|
|
|
122
121
|
{#if isOpen}
|
|
123
|
-
<GridPopover {anchor}
|
|
122
|
+
<GridPopover {anchor} on:close={close}>
|
|
124
123
|
<div class="options">
|
|
125
124
|
{#each options as option, idx}
|
|
126
125
|
{@const color = optionColors[option] || getOptionColor(option)}
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
export let focused
|
|
14
14
|
export let schema
|
|
15
15
|
export let onChange
|
|
16
|
-
export let invertX = false
|
|
17
16
|
export let contentLines = 1
|
|
18
17
|
export let searchFunction = API.searchTable
|
|
19
18
|
export let primaryDisplay
|
|
@@ -275,7 +274,7 @@
|
|
|
275
274
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
276
275
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
277
276
|
{#if isOpen}
|
|
278
|
-
<GridPopover open={isOpen} {anchor}
|
|
277
|
+
<GridPopover open={isOpen} {anchor} on:close={close}>
|
|
279
278
|
<div class="dropdown" on:wheel|stopPropagation>
|
|
280
279
|
<div class="search">
|
|
281
280
|
<Input
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { onMount, getContext } from "svelte"
|
|
3
|
+
import { SignatureModal } from "@budibase/frontend-core/src/components"
|
|
4
|
+
import { CoreSignature, ActionButton } from "@budibase/bbui"
|
|
5
|
+
import GridPopover from "../overlays/GridPopover.svelte"
|
|
6
|
+
|
|
7
|
+
export let schema
|
|
8
|
+
export let value
|
|
9
|
+
export let focused = false
|
|
10
|
+
export let onChange
|
|
11
|
+
export let readonly = false
|
|
12
|
+
export let api
|
|
13
|
+
|
|
14
|
+
const { API, notifications, props } = getContext("grid")
|
|
15
|
+
|
|
16
|
+
let isOpen = false
|
|
17
|
+
let modal
|
|
18
|
+
let anchor
|
|
19
|
+
|
|
20
|
+
$: editable = focused && !readonly
|
|
21
|
+
$: {
|
|
22
|
+
if (!focused) {
|
|
23
|
+
close()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const onKeyDown = () => {
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const open = () => {
|
|
32
|
+
isOpen = true
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const close = () => {
|
|
36
|
+
isOpen = false
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const deleteSignature = async () => {
|
|
40
|
+
onChange(null)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const saveSignature = async sigCanvas => {
|
|
44
|
+
const signatureFile = sigCanvas.toFile()
|
|
45
|
+
|
|
46
|
+
let attachRequest = new FormData()
|
|
47
|
+
attachRequest.append("file", signatureFile)
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const uploadReq = await API.uploadBuilderAttachment(attachRequest)
|
|
51
|
+
const [signatureAttachment] = uploadReq
|
|
52
|
+
onChange(signatureAttachment)
|
|
53
|
+
} catch (error) {
|
|
54
|
+
$notifications.error(error.message || "Failed to save signature")
|
|
55
|
+
return []
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
onMount(() => {
|
|
60
|
+
api = {
|
|
61
|
+
focus: () => open(),
|
|
62
|
+
blur: () => close(),
|
|
63
|
+
isActive: () => isOpen,
|
|
64
|
+
onKeyDown,
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
70
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
71
|
+
<div
|
|
72
|
+
class="signature-cell"
|
|
73
|
+
class:light={!$props?.darkMode}
|
|
74
|
+
class:editable
|
|
75
|
+
bind:this={anchor}
|
|
76
|
+
on:click={editable ? open : null}
|
|
77
|
+
>
|
|
78
|
+
{#if value?.url}
|
|
79
|
+
<!-- svelte-ignore a11y-missing-attribute -->
|
|
80
|
+
<img src={value?.url} />
|
|
81
|
+
{/if}
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<SignatureModal
|
|
85
|
+
onConfirm={saveSignature}
|
|
86
|
+
title={schema?.name}
|
|
87
|
+
{value}
|
|
88
|
+
darkMode={$props.darkMode}
|
|
89
|
+
bind:this={modal}
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
{#if isOpen}
|
|
93
|
+
<GridPopover open={isOpen} {anchor} maxHeight={null} on:close={close}>
|
|
94
|
+
<div class="signature" class:empty={!value}>
|
|
95
|
+
{#if value?.key}
|
|
96
|
+
<div class="signature-wrap">
|
|
97
|
+
<CoreSignature
|
|
98
|
+
darkMode={$props.darkMode}
|
|
99
|
+
editable={false}
|
|
100
|
+
{value}
|
|
101
|
+
on:change={saveSignature}
|
|
102
|
+
on:clear={deleteSignature}
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
{:else}
|
|
106
|
+
<div class="add-signature">
|
|
107
|
+
<ActionButton
|
|
108
|
+
fullWidth
|
|
109
|
+
on:click={() => {
|
|
110
|
+
modal.show()
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
Add signature
|
|
114
|
+
</ActionButton>
|
|
115
|
+
</div>
|
|
116
|
+
{/if}
|
|
117
|
+
</div>
|
|
118
|
+
</GridPopover>
|
|
119
|
+
{/if}
|
|
120
|
+
|
|
121
|
+
<style>
|
|
122
|
+
.signature {
|
|
123
|
+
min-width: 320px;
|
|
124
|
+
padding: var(--cell-padding);
|
|
125
|
+
background: var(--grid-background-alt);
|
|
126
|
+
border: var(--cell-border);
|
|
127
|
+
}
|
|
128
|
+
.signature.empty {
|
|
129
|
+
width: 100%;
|
|
130
|
+
min-width: unset;
|
|
131
|
+
}
|
|
132
|
+
.signature-cell.light img {
|
|
133
|
+
-webkit-filter: invert(100%);
|
|
134
|
+
filter: invert(100%);
|
|
135
|
+
}
|
|
136
|
+
.signature-cell {
|
|
137
|
+
flex: 1 1 auto;
|
|
138
|
+
display: flex;
|
|
139
|
+
flex-direction: row;
|
|
140
|
+
align-items: stretch;
|
|
141
|
+
max-width: 320px;
|
|
142
|
+
padding-left: var(--cell-padding);
|
|
143
|
+
padding-right: var(--cell-padding);
|
|
144
|
+
flex-wrap: nowrap;
|
|
145
|
+
align-self: stretch;
|
|
146
|
+
overflow: hidden;
|
|
147
|
+
user-select: none;
|
|
148
|
+
}
|
|
149
|
+
.signature-cell.editable:hover {
|
|
150
|
+
cursor: pointer;
|
|
151
|
+
}
|
|
152
|
+
.signature-wrap {
|
|
153
|
+
display: flex;
|
|
154
|
+
flex-direction: column;
|
|
155
|
+
justify-content: flex-start;
|
|
156
|
+
align-items: stretch;
|
|
157
|
+
background-color: var(--spectrum-global-color-gray-50);
|
|
158
|
+
color: var(--spectrum-alias-text-color);
|
|
159
|
+
box-sizing: border-box;
|
|
160
|
+
position: relative;
|
|
161
|
+
}
|
|
162
|
+
</style>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { ActionButton, Popover, Toggle, Icon } from "@budibase/bbui"
|
|
4
4
|
import { getColumnIcon } from "../lib/utils"
|
|
5
5
|
|
|
6
|
-
const { columns, stickyColumn, dispatch } = getContext("grid")
|
|
6
|
+
const { columns, datasource, stickyColumn, dispatch } = getContext("grid")
|
|
7
7
|
|
|
8
8
|
let open = false
|
|
9
9
|
let anchor
|
|
@@ -11,36 +11,20 @@
|
|
|
11
11
|
$: anyHidden = $columns.some(col => !col.visible)
|
|
12
12
|
$: text = getText($columns)
|
|
13
13
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
state[index].visible = visible
|
|
18
|
-
return state.slice()
|
|
19
|
-
})
|
|
20
|
-
await columns.actions.saveChanges()
|
|
14
|
+
const toggleColumn = async (column, visible) => {
|
|
15
|
+
datasource.actions.addSchemaMutation(column.name, { visible })
|
|
16
|
+
await datasource.actions.saveSchemaMutations()
|
|
21
17
|
dispatch(visible ? "show-column" : "hide-column")
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
visible: true,
|
|
29
|
-
}))
|
|
20
|
+
const toggleAll = async visible => {
|
|
21
|
+
let mutations = {}
|
|
22
|
+
$columns.forEach(column => {
|
|
23
|
+
mutations[column.name] = { visible }
|
|
30
24
|
})
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const hideAll = async () => {
|
|
36
|
-
columns.update(state => {
|
|
37
|
-
return state.map(col => ({
|
|
38
|
-
...col,
|
|
39
|
-
visible: false,
|
|
40
|
-
}))
|
|
41
|
-
})
|
|
42
|
-
await columns.actions.saveChanges()
|
|
43
|
-
dispatch("hide-column")
|
|
25
|
+
datasource.actions.addSchemaMutations(mutations)
|
|
26
|
+
await datasource.actions.saveSchemaMutations()
|
|
27
|
+
dispatch(visible ? "show-column" : "hide-column")
|
|
44
28
|
}
|
|
45
29
|
|
|
46
30
|
const getText = columns => {
|
|
@@ -80,14 +64,14 @@
|
|
|
80
64
|
<Toggle
|
|
81
65
|
size="S"
|
|
82
66
|
value={column.visible}
|
|
83
|
-
on:change={e =>
|
|
67
|
+
on:change={e => toggleColumn(column, e.detail)}
|
|
84
68
|
disabled={column.primaryDisplay}
|
|
85
69
|
/>
|
|
86
70
|
{/each}
|
|
87
71
|
</div>
|
|
88
72
|
<div class="buttons">
|
|
89
|
-
<ActionButton on:click={
|
|
90
|
-
<ActionButton on:click={
|
|
73
|
+
<ActionButton on:click={() => toggleAll(true)}>Show all</ActionButton>
|
|
74
|
+
<ActionButton on:click={() => toggleAll(false)}>Hide all</ActionButton>
|
|
91
75
|
</div>
|
|
92
76
|
</div>
|
|
93
77
|
</Popover>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { setContext, onMount } from "svelte"
|
|
3
|
-
import { writable } from "svelte/store"
|
|
3
|
+
import { writable, derived } from "svelte/store"
|
|
4
4
|
import { fade } from "svelte/transition"
|
|
5
5
|
import { clickOutside, ProgressCircle } from "@budibase/bbui"
|
|
6
6
|
import { createEventManagers } from "../lib/events"
|
|
@@ -54,6 +54,8 @@
|
|
|
54
54
|
export let notifySuccess = null
|
|
55
55
|
export let notifyError = null
|
|
56
56
|
export let buttons = null
|
|
57
|
+
export let darkMode
|
|
58
|
+
export let isCloud = null
|
|
57
59
|
|
|
58
60
|
// Unique identifier for DOM nodes inside this instance
|
|
59
61
|
const gridID = `grid-${Math.random().toString().slice(2)}`
|
|
@@ -108,9 +110,16 @@
|
|
|
108
110
|
notifySuccess,
|
|
109
111
|
notifyError,
|
|
110
112
|
buttons,
|
|
113
|
+
darkMode,
|
|
114
|
+
isCloud,
|
|
111
115
|
})
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
|
|
117
|
+
// Derive min height and make available in context
|
|
118
|
+
const minHeight = derived(rowHeight, $height => {
|
|
119
|
+
const heightForControls = showControls ? ControlsHeight : 0
|
|
120
|
+
return Padding + SmallRowHeight + $height + heightForControls
|
|
121
|
+
})
|
|
122
|
+
context = { ...context, minHeight }
|
|
114
123
|
|
|
115
124
|
// Set context for children to consume
|
|
116
125
|
setContext("grid", context)
|
|
@@ -136,7 +145,7 @@
|
|
|
136
145
|
class:quiet
|
|
137
146
|
on:mouseenter={() => gridFocused.set(true)}
|
|
138
147
|
on:mouseleave={() => gridFocused.set(false)}
|
|
139
|
-
style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-overflow:{MaxCellRenderOverflow}px; --content-lines:{$contentLines}; --min-height:{minHeight}px; --controls-height:{ControlsHeight}px;"
|
|
148
|
+
style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-overflow:{MaxCellRenderOverflow}px; --content-lines:{$contentLines}; --min-height:{$minHeight}px; --controls-height:{ControlsHeight}px;"
|
|
140
149
|
>
|
|
141
150
|
{#if showControls}
|
|
142
151
|
<div class="controls">
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
bounds,
|
|
10
10
|
renderedRows,
|
|
11
11
|
visibleColumns,
|
|
12
|
-
rowVerticalInversionIndex,
|
|
13
12
|
hoveredRowId,
|
|
14
13
|
dispatch,
|
|
15
14
|
isDragging,
|
|
@@ -41,11 +40,7 @@
|
|
|
41
40
|
<div bind:this={body} class="grid-body">
|
|
42
41
|
<GridScrollWrapper scrollHorizontally scrollVertically attachHandlers>
|
|
43
42
|
{#each $renderedRows as row, idx}
|
|
44
|
-
<GridRow
|
|
45
|
-
{row}
|
|
46
|
-
top={idx === 0}
|
|
47
|
-
invertY={idx >= $rowVerticalInversionIndex}
|
|
48
|
-
/>
|
|
43
|
+
<GridRow {row} top={idx === 0} />
|
|
49
44
|
{/each}
|
|
50
45
|
{#if $config.canAddRows}
|
|
51
46
|
<div
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
export let row
|
|
7
7
|
export let top = false
|
|
8
|
-
export let invertY = false
|
|
9
8
|
|
|
10
9
|
const {
|
|
11
10
|
focusedCellId,
|
|
@@ -15,7 +14,6 @@
|
|
|
15
14
|
hoveredRowId,
|
|
16
15
|
selectedCellMap,
|
|
17
16
|
focusedRow,
|
|
18
|
-
columnHorizontalInversionIndex,
|
|
19
17
|
contentLines,
|
|
20
18
|
isDragging,
|
|
21
19
|
dispatch,
|
|
@@ -38,15 +36,13 @@
|
|
|
38
36
|
on:mouseleave={$isDragging ? null : () => ($hoveredRowId = null)}
|
|
39
37
|
on:click={() => dispatch("rowclick", rows.actions.cleanRow(row))}
|
|
40
38
|
>
|
|
41
|
-
{#each $visibleColumns as column
|
|
39
|
+
{#each $visibleColumns as column}
|
|
42
40
|
{@const cellId = getCellID(row._id, column.name)}
|
|
43
41
|
<DataCell
|
|
44
42
|
{cellId}
|
|
45
43
|
{column}
|
|
46
44
|
{row}
|
|
47
|
-
{invertY}
|
|
48
45
|
{rowFocused}
|
|
49
|
-
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
|
50
46
|
highlighted={rowHovered || rowFocused || reorderSource === column.name}
|
|
51
47
|
selected={rowSelected}
|
|
52
48
|
rowIdx={row.__idx}
|
|
@@ -24,8 +24,6 @@
|
|
|
24
24
|
rowHeight,
|
|
25
25
|
hasNextPage,
|
|
26
26
|
maxScrollTop,
|
|
27
|
-
rowVerticalInversionIndex,
|
|
28
|
-
columnHorizontalInversionIndex,
|
|
29
27
|
selectedRows,
|
|
30
28
|
loaded,
|
|
31
29
|
refreshing,
|
|
@@ -43,17 +41,9 @@
|
|
|
43
41
|
$: firstColumn = $stickyColumn || $visibleColumns[0]
|
|
44
42
|
$: width = GutterWidth + ($stickyColumn?.width || 0)
|
|
45
43
|
$: $datasource, (visible = false)
|
|
46
|
-
$: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows)
|
|
47
44
|
$: selectedRowCount = Object.values($selectedRows).length
|
|
48
45
|
$: hasNoRows = !$rows.length
|
|
49
46
|
|
|
50
|
-
const shouldInvertY = (offset, inversionIndex, rows) => {
|
|
51
|
-
if (offset === 0) {
|
|
52
|
-
return false
|
|
53
|
-
}
|
|
54
|
-
return rows.length >= inversionIndex
|
|
55
|
-
}
|
|
56
|
-
|
|
57
47
|
const addRow = async () => {
|
|
58
48
|
// Blur the active cell and tick to let final value updates propagate
|
|
59
49
|
isAdding = true
|
|
@@ -205,7 +195,6 @@
|
|
|
205
195
|
width={$stickyColumn.width}
|
|
206
196
|
{updateValue}
|
|
207
197
|
topRow={offset === 0}
|
|
208
|
-
{invertY}
|
|
209
198
|
>
|
|
210
199
|
{#if $stickyColumn?.schema?.autocolumn}
|
|
211
200
|
<div class="readonly-overlay">Can't edit auto column</div>
|
|
@@ -219,7 +208,7 @@
|
|
|
219
208
|
<div class="normal-columns" transition:fade|local={{ duration: 130 }}>
|
|
220
209
|
<GridScrollWrapper scrollHorizontally attachHandlers>
|
|
221
210
|
<div class="row">
|
|
222
|
-
{#each $visibleColumns as column
|
|
211
|
+
{#each $visibleColumns as column}
|
|
223
212
|
{@const cellId = `new-${column.name}`}
|
|
224
213
|
<DataCell
|
|
225
214
|
{cellId}
|
|
@@ -230,8 +219,6 @@
|
|
|
230
219
|
focused={$focusedCellId === cellId}
|
|
231
220
|
width={column.width}
|
|
232
221
|
topRow={offset === 0}
|
|
233
|
-
invertX={columnIdx >= $columnHorizontalInversionIndex}
|
|
234
|
-
{invertY}
|
|
235
222
|
hidden={!$columnRenderMap[column.name]}
|
|
236
223
|
>
|
|
237
224
|
{#if column?.schema?.autocolumn}
|
|
@@ -13,6 +13,7 @@ import JSONCell from "../cells/JSONCell.svelte"
|
|
|
13
13
|
import AttachmentCell from "../cells/AttachmentCell.svelte"
|
|
14
14
|
import AttachmentSingleCell from "../cells/AttachmentSingleCell.svelte"
|
|
15
15
|
import BBReferenceCell from "../cells/BBReferenceCell.svelte"
|
|
16
|
+
import SignatureCell from "../cells/SignatureCell.svelte"
|
|
16
17
|
import BBReferenceSingleCell from "../cells/BBReferenceSingleCell.svelte"
|
|
17
18
|
|
|
18
19
|
const TypeComponentMap = {
|
|
@@ -20,6 +21,7 @@ const TypeComponentMap = {
|
|
|
20
21
|
[FieldType.OPTIONS]: OptionsCell,
|
|
21
22
|
[FieldType.DATETIME]: DateCell,
|
|
22
23
|
[FieldType.BARCODEQR]: TextCell,
|
|
24
|
+
[FieldType.SIGNATURE_SINGLE]: SignatureCell,
|
|
23
25
|
[FieldType.LONGFORM]: LongFormCell,
|
|
24
26
|
[FieldType.ARRAY]: MultiSelectCell,
|
|
25
27
|
[FieldType.NUMBER]: NumberCell,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { derived, get, writable } from "svelte/store"
|
|
2
|
-
import { cloneDeep } from "lodash/fp"
|
|
3
2
|
import { GutterWidth, DefaultColumnWidth } from "../lib/constants"
|
|
4
3
|
|
|
5
4
|
export const createStores = () => {
|
|
@@ -75,72 +74,23 @@ export const deriveStores = context => {
|
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
export const createActions = context => {
|
|
78
|
-
const { columns,
|
|
79
|
-
|
|
80
|
-
// Updates the datasources primary display column
|
|
81
|
-
const changePrimaryDisplay = async column => {
|
|
82
|
-
return await datasource.actions.saveDefinition({
|
|
83
|
-
...get(definition),
|
|
84
|
-
primaryDisplay: column,
|
|
85
|
-
})
|
|
86
|
-
}
|
|
77
|
+
const { columns, datasource, schema } = context
|
|
87
78
|
|
|
88
79
|
// Updates the width of all columns
|
|
89
80
|
const changeAllColumnWidths = async width => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}))
|
|
95
|
-
})
|
|
96
|
-
if (get(stickyColumn)) {
|
|
97
|
-
stickyColumn.update(state => ({
|
|
98
|
-
...state,
|
|
99
|
-
width,
|
|
100
|
-
}))
|
|
101
|
-
}
|
|
102
|
-
await saveChanges()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Persists column changes by saving metadata against datasource schema
|
|
106
|
-
const saveChanges = async () => {
|
|
107
|
-
const $columns = get(columns)
|
|
108
|
-
const $definition = get(definition)
|
|
109
|
-
const $stickyColumn = get(stickyColumn)
|
|
110
|
-
let newSchema = cloneDeep(get(schema)) || {}
|
|
111
|
-
|
|
112
|
-
// Build new updated datasource schema
|
|
113
|
-
Object.keys(newSchema).forEach(column => {
|
|
114
|
-
// Respect order specified by columns
|
|
115
|
-
const index = $columns.findIndex(x => x.name === column)
|
|
116
|
-
if (index !== -1) {
|
|
117
|
-
newSchema[column].order = index
|
|
118
|
-
} else {
|
|
119
|
-
delete newSchema[column].order
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Copy over metadata
|
|
123
|
-
if (column === $stickyColumn?.name) {
|
|
124
|
-
newSchema[column].visible = true
|
|
125
|
-
newSchema[column].width = $stickyColumn.width || DefaultColumnWidth
|
|
126
|
-
} else {
|
|
127
|
-
newSchema[column].visible = $columns[index]?.visible ?? true
|
|
128
|
-
newSchema[column].width = $columns[index]?.width || DefaultColumnWidth
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
await datasource.actions.saveDefinition({
|
|
133
|
-
...$definition,
|
|
134
|
-
schema: newSchema,
|
|
81
|
+
const $schema = get(schema)
|
|
82
|
+
let mutations = {}
|
|
83
|
+
Object.keys($schema).forEach(field => {
|
|
84
|
+
mutations[field] = { width }
|
|
135
85
|
})
|
|
86
|
+
datasource.actions.addSchemaMutations(mutations)
|
|
87
|
+
await datasource.actions.saveSchemaMutations()
|
|
136
88
|
}
|
|
137
89
|
|
|
138
90
|
return {
|
|
139
91
|
columns: {
|
|
140
92
|
...columns,
|
|
141
93
|
actions: {
|
|
142
|
-
saveChanges,
|
|
143
|
-
changePrimaryDisplay,
|
|
144
94
|
changeAllColumnWidths,
|
|
145
95
|
},
|
|
146
96
|
},
|
|
@@ -4,15 +4,23 @@ import { memo } from "../../../utils"
|
|
|
4
4
|
|
|
5
5
|
export const createStores = () => {
|
|
6
6
|
const definition = memo(null)
|
|
7
|
+
const schemaMutations = memo({})
|
|
7
8
|
|
|
8
9
|
return {
|
|
9
10
|
definition,
|
|
11
|
+
schemaMutations,
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export const deriveStores = context => {
|
|
14
|
-
const {
|
|
15
|
-
|
|
16
|
+
const {
|
|
17
|
+
API,
|
|
18
|
+
definition,
|
|
19
|
+
schemaOverrides,
|
|
20
|
+
columnWhitelist,
|
|
21
|
+
datasource,
|
|
22
|
+
schemaMutations,
|
|
23
|
+
} = context
|
|
16
24
|
|
|
17
25
|
const schema = derived(definition, $definition => {
|
|
18
26
|
let schema = getDatasourceSchema({
|
|
@@ -35,42 +43,26 @@ export const deriveStores = context => {
|
|
|
35
43
|
return schema
|
|
36
44
|
})
|
|
37
45
|
|
|
46
|
+
// Derives the total enriched schema, made up of the saved schema and any
|
|
47
|
+
// prop and user overrides
|
|
38
48
|
const enrichedSchema = derived(
|
|
39
|
-
[schema, schemaOverrides, columnWhitelist],
|
|
40
|
-
([$schema, $schemaOverrides, $columnWhitelist]) => {
|
|
49
|
+
[schema, schemaOverrides, schemaMutations, columnWhitelist],
|
|
50
|
+
([$schema, $schemaOverrides, $schemaMutations, $columnWhitelist]) => {
|
|
41
51
|
if (!$schema) {
|
|
42
52
|
return null
|
|
43
53
|
}
|
|
44
|
-
let enrichedSchema = {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
let enrichedSchema = {}
|
|
55
|
+
Object.keys($schema).forEach(field => {
|
|
56
|
+
// Apply whitelist if provided
|
|
57
|
+
if ($columnWhitelist?.length && !$columnWhitelist.includes(field)) {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
enrichedSchema[field] = {
|
|
61
|
+
...$schema[field],
|
|
62
|
+
...$schemaOverrides?.[field],
|
|
63
|
+
...$schemaMutations[field],
|
|
53
64
|
}
|
|
54
65
|
})
|
|
55
|
-
|
|
56
|
-
// Apply whitelist if specified
|
|
57
|
-
if ($columnWhitelist?.length) {
|
|
58
|
-
const sortedColumns = {}
|
|
59
|
-
|
|
60
|
-
$columnWhitelist.forEach((columnKey, idx) => {
|
|
61
|
-
const enrichedColumn = enrichedSchema[columnKey]
|
|
62
|
-
if (enrichedColumn) {
|
|
63
|
-
sortedColumns[columnKey] = {
|
|
64
|
-
...enrichedColumn,
|
|
65
|
-
order: idx,
|
|
66
|
-
visible: true,
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
return sortedColumns
|
|
72
|
-
}
|
|
73
|
-
|
|
74
66
|
return enrichedSchema
|
|
75
67
|
}
|
|
76
68
|
)
|
|
@@ -100,6 +92,8 @@ export const createActions = context => {
|
|
|
100
92
|
table,
|
|
101
93
|
viewV2,
|
|
102
94
|
nonPlus,
|
|
95
|
+
schemaMutations,
|
|
96
|
+
schema,
|
|
103
97
|
} = context
|
|
104
98
|
|
|
105
99
|
// Gets the appropriate API for the configured datasource type
|
|
@@ -136,11 +130,81 @@ export const createActions = context => {
|
|
|
136
130
|
// Update server
|
|
137
131
|
if (get(config).canSaveSchema) {
|
|
138
132
|
await getAPI()?.actions.saveDefinition(newDefinition)
|
|
133
|
+
|
|
134
|
+
// Broadcast change so external state can be updated, as this change
|
|
135
|
+
// will not be received by the builder websocket because we caused it
|
|
136
|
+
// ourselves
|
|
137
|
+
dispatch("updatedatasource", newDefinition)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Updates the datasources primary display column
|
|
142
|
+
const changePrimaryDisplay = async column => {
|
|
143
|
+
return await saveDefinition({
|
|
144
|
+
...get(definition),
|
|
145
|
+
primaryDisplay: column,
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Adds a schema mutation for a single field
|
|
150
|
+
const addSchemaMutation = (field, mutation) => {
|
|
151
|
+
if (!field || !mutation) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
schemaMutations.update($schemaMutations => {
|
|
155
|
+
return {
|
|
156
|
+
...$schemaMutations,
|
|
157
|
+
[field]: {
|
|
158
|
+
...$schemaMutations[field],
|
|
159
|
+
...mutation,
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Adds schema mutations for multiple fields at once
|
|
166
|
+
const addSchemaMutations = mutations => {
|
|
167
|
+
const fields = Object.keys(mutations || {})
|
|
168
|
+
if (!fields.length) {
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
schemaMutations.update($schemaMutations => {
|
|
172
|
+
let newSchemaMutations = { ...$schemaMutations }
|
|
173
|
+
fields.forEach(field => {
|
|
174
|
+
newSchemaMutations[field] = {
|
|
175
|
+
...newSchemaMutations[field],
|
|
176
|
+
...mutations[field],
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
return newSchemaMutations
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Saves schema changes to the server, if possible
|
|
184
|
+
const saveSchemaMutations = async () => {
|
|
185
|
+
// If we can't save schema changes then we just want to keep this in memory
|
|
186
|
+
if (!get(config).canSaveSchema) {
|
|
187
|
+
return
|
|
139
188
|
}
|
|
189
|
+
const $definition = get(definition)
|
|
190
|
+
const $schemaMutations = get(schemaMutations)
|
|
191
|
+
const $schema = get(schema)
|
|
192
|
+
let newSchema = {}
|
|
140
193
|
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
194
|
+
// Build new updated datasource schema
|
|
195
|
+
Object.keys($schema).forEach(column => {
|
|
196
|
+
newSchema[column] = {
|
|
197
|
+
...$schema[column],
|
|
198
|
+
...$schemaMutations[column],
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
// Save the changes, then reset our local mutations
|
|
203
|
+
await saveDefinition({
|
|
204
|
+
...$definition,
|
|
205
|
+
schema: newSchema,
|
|
206
|
+
})
|
|
207
|
+
schemaMutations.set({})
|
|
144
208
|
}
|
|
145
209
|
|
|
146
210
|
// Adds a row to the datasource
|
|
@@ -185,6 +249,10 @@ export const createActions = context => {
|
|
|
185
249
|
getRow,
|
|
186
250
|
isDatasourceValid,
|
|
187
251
|
canUseColumn,
|
|
252
|
+
changePrimaryDisplay,
|
|
253
|
+
addSchemaMutation,
|
|
254
|
+
addSchemaMutations,
|
|
255
|
+
saveSchemaMutations,
|
|
188
256
|
},
|
|
189
257
|
},
|
|
190
258
|
}
|
|
@@ -34,6 +34,7 @@ export const createActions = context => {
|
|
|
34
34
|
stickyColumn,
|
|
35
35
|
maxScrollLeft,
|
|
36
36
|
width,
|
|
37
|
+
datasource,
|
|
37
38
|
} = context
|
|
38
39
|
|
|
39
40
|
let autoScrollInterval
|
|
@@ -173,20 +174,17 @@ export const createActions = context => {
|
|
|
173
174
|
document.removeEventListener("touchend", stopReordering)
|
|
174
175
|
document.removeEventListener("touchcancel", stopReordering)
|
|
175
176
|
|
|
176
|
-
// Ensure there's actually a change
|
|
177
|
-
|
|
177
|
+
// Ensure there's actually a change before saving
|
|
178
|
+
const { sourceColumn, targetColumn } = get(reorder)
|
|
179
|
+
reorder.set(reorderInitialState)
|
|
178
180
|
if (sourceColumn !== targetColumn) {
|
|
179
|
-
moveColumn(sourceColumn, targetColumn)
|
|
180
|
-
await columns.actions.saveChanges()
|
|
181
|
+
await moveColumn(sourceColumn, targetColumn)
|
|
181
182
|
}
|
|
182
|
-
|
|
183
|
-
// Reset state
|
|
184
|
-
reorder.set(reorderInitialState)
|
|
185
183
|
}
|
|
186
184
|
|
|
187
185
|
// Moves a column after another columns.
|
|
188
186
|
// An undefined target column will move the source to index 0.
|
|
189
|
-
const moveColumn = (sourceColumn, targetColumn) => {
|
|
187
|
+
const moveColumn = async (sourceColumn, targetColumn) => {
|
|
190
188
|
let $columns = get(columns)
|
|
191
189
|
let sourceIdx = $columns.findIndex(x => x.name === sourceColumn)
|
|
192
190
|
let targetIdx = $columns.findIndex(x => x.name === targetColumn)
|
|
@@ -198,14 +196,21 @@ export const createActions = context => {
|
|
|
198
196
|
}
|
|
199
197
|
return state.toSpliced(targetIdx, 0, removed[0])
|
|
200
198
|
})
|
|
199
|
+
|
|
200
|
+
// Extract new orders as schema mutations
|
|
201
|
+
let mutations = {}
|
|
202
|
+
get(columns).forEach((column, idx) => {
|
|
203
|
+
mutations[column.name] = { order: idx }
|
|
204
|
+
})
|
|
205
|
+
datasource.actions.addSchemaMutations(mutations)
|
|
206
|
+
await datasource.actions.saveSchemaMutations()
|
|
201
207
|
}
|
|
202
208
|
|
|
203
209
|
// Moves a column one place left (as appears visually)
|
|
204
210
|
const moveColumnLeft = async column => {
|
|
205
211
|
const $visibleColumns = get(visibleColumns)
|
|
206
212
|
const sourceIdx = $visibleColumns.findIndex(x => x.name === column)
|
|
207
|
-
moveColumn(column, $visibleColumns[sourceIdx - 2]?.name)
|
|
208
|
-
await columns.actions.saveChanges()
|
|
213
|
+
await moveColumn(column, $visibleColumns[sourceIdx - 2]?.name)
|
|
209
214
|
}
|
|
210
215
|
|
|
211
216
|
// Moves a column one place right (as appears visually)
|
|
@@ -215,8 +220,7 @@ export const createActions = context => {
|
|
|
215
220
|
if (sourceIdx === $visibleColumns.length - 1) {
|
|
216
221
|
return
|
|
217
222
|
}
|
|
218
|
-
moveColumn(column, $visibleColumns[sourceIdx + 1]?.name)
|
|
219
|
-
await columns.actions.saveChanges()
|
|
223
|
+
await moveColumn(column, $visibleColumns[sourceIdx + 1]?.name)
|
|
220
224
|
}
|
|
221
225
|
|
|
222
226
|
return {
|
|
@@ -6,7 +6,6 @@ const initialState = {
|
|
|
6
6
|
initialMouseX: null,
|
|
7
7
|
initialWidth: null,
|
|
8
8
|
column: null,
|
|
9
|
-
columnIdx: null,
|
|
10
9
|
width: 0,
|
|
11
10
|
left: 0,
|
|
12
11
|
}
|
|
@@ -21,7 +20,7 @@ export const createStores = () => {
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
export const createActions = context => {
|
|
24
|
-
const { resize,
|
|
23
|
+
const { resize, ui, datasource } = context
|
|
25
24
|
|
|
26
25
|
// Starts resizing a certain column
|
|
27
26
|
const startResizing = (column, e) => {
|
|
@@ -32,12 +31,6 @@ export const createActions = context => {
|
|
|
32
31
|
e.preventDefault()
|
|
33
32
|
ui.actions.blur()
|
|
34
33
|
|
|
35
|
-
// Find and cache index
|
|
36
|
-
let columnIdx = get(columns).findIndex(col => col.name === column.name)
|
|
37
|
-
if (columnIdx === -1) {
|
|
38
|
-
columnIdx = "sticky"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
34
|
// Set initial store state
|
|
42
35
|
resize.set({
|
|
43
36
|
width: column.width,
|
|
@@ -45,7 +38,6 @@ export const createActions = context => {
|
|
|
45
38
|
initialWidth: column.width,
|
|
46
39
|
initialMouseX: x,
|
|
47
40
|
column: column.name,
|
|
48
|
-
columnIdx,
|
|
49
41
|
})
|
|
50
42
|
|
|
51
43
|
// Add mouse event listeners to handle resizing
|
|
@@ -58,7 +50,7 @@ export const createActions = context => {
|
|
|
58
50
|
|
|
59
51
|
// Handler for moving the mouse to resize columns
|
|
60
52
|
const onResizeMouseMove = e => {
|
|
61
|
-
const { initialMouseX, initialWidth, width,
|
|
53
|
+
const { initialMouseX, initialWidth, width, column } = get(resize)
|
|
62
54
|
const { x } = parseEventLocation(e)
|
|
63
55
|
const dx = x - initialMouseX
|
|
64
56
|
const newWidth = Math.round(Math.max(MinColumnWidth, initialWidth + dx))
|
|
@@ -69,17 +61,7 @@ export const createActions = context => {
|
|
|
69
61
|
}
|
|
70
62
|
|
|
71
63
|
// Update column state
|
|
72
|
-
|
|
73
|
-
stickyColumn.update(state => ({
|
|
74
|
-
...state,
|
|
75
|
-
width: newWidth,
|
|
76
|
-
}))
|
|
77
|
-
} else {
|
|
78
|
-
columns.update(state => {
|
|
79
|
-
state[columnIdx].width = newWidth
|
|
80
|
-
return [...state]
|
|
81
|
-
})
|
|
82
|
-
}
|
|
64
|
+
datasource.actions.addSchemaMutation(column, { width })
|
|
83
65
|
|
|
84
66
|
// Update state
|
|
85
67
|
resize.update(state => ({
|
|
@@ -101,26 +83,16 @@ export const createActions = context => {
|
|
|
101
83
|
|
|
102
84
|
// Persist width if it changed
|
|
103
85
|
if ($resize.width !== $resize.initialWidth) {
|
|
104
|
-
await
|
|
86
|
+
await datasource.actions.saveSchemaMutations()
|
|
105
87
|
}
|
|
106
88
|
}
|
|
107
89
|
|
|
108
90
|
// Resets a column size back to default
|
|
109
91
|
const resetSize = async column => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
width: DefaultColumnWidth,
|
|
115
|
-
}))
|
|
116
|
-
} else {
|
|
117
|
-
columns.update(state => {
|
|
118
|
-
const columnIdx = state.findIndex(x => x.name === column.name)
|
|
119
|
-
state[columnIdx].width = DefaultColumnWidth
|
|
120
|
-
return [...state]
|
|
121
|
-
})
|
|
122
|
-
}
|
|
123
|
-
await columns.actions.saveChanges()
|
|
92
|
+
datasource.actions.addSchemaMutation(column.name, {
|
|
93
|
+
width: DefaultColumnWidth,
|
|
94
|
+
})
|
|
95
|
+
await datasource.actions.saveSchemaMutations()
|
|
124
96
|
}
|
|
125
97
|
|
|
126
98
|
return {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { derived } from "svelte/store"
|
|
2
|
-
import {
|
|
3
|
-
MaxCellRenderOverflow,
|
|
4
|
-
MinColumnWidth,
|
|
5
|
-
ScrollBarSize,
|
|
6
|
-
} from "../lib/constants"
|
|
2
|
+
import { MinColumnWidth } from "../lib/constants"
|
|
7
3
|
|
|
8
4
|
export const deriveStores = context => {
|
|
9
5
|
const {
|
|
@@ -85,51 +81,10 @@ export const deriveStores = context => {
|
|
|
85
81
|
}
|
|
86
82
|
)
|
|
87
83
|
|
|
88
|
-
// Determine the row index at which we should start vertically inverting cell
|
|
89
|
-
// dropdowns
|
|
90
|
-
const rowVerticalInversionIndex = derived(
|
|
91
|
-
[height, rowHeight, scrollTop],
|
|
92
|
-
([$height, $rowHeight, $scrollTop]) => {
|
|
93
|
-
const offset = $scrollTop % $rowHeight
|
|
94
|
-
|
|
95
|
-
// Compute the last row index with space to render popovers below it
|
|
96
|
-
const minBottom =
|
|
97
|
-
$height - ScrollBarSize * 3 - MaxCellRenderOverflow + offset
|
|
98
|
-
const lastIdx = Math.floor(minBottom / $rowHeight)
|
|
99
|
-
|
|
100
|
-
// Compute the first row index with space to render popovers above it
|
|
101
|
-
const minTop = MaxCellRenderOverflow + offset
|
|
102
|
-
const firstIdx = Math.ceil(minTop / $rowHeight)
|
|
103
|
-
|
|
104
|
-
// Use the greater of the two indices so that we prefer content below,
|
|
105
|
-
// unless there is room to render the entire popover above
|
|
106
|
-
return Math.max(lastIdx, firstIdx)
|
|
107
|
-
}
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
// Determine the column index at which we should start horizontally inverting
|
|
111
|
-
// cell dropdowns
|
|
112
|
-
const columnHorizontalInversionIndex = derived(
|
|
113
|
-
[visibleColumns, scrollLeft, width],
|
|
114
|
-
([$visibleColumns, $scrollLeft, $width]) => {
|
|
115
|
-
const cutoff = $width + $scrollLeft - ScrollBarSize * 3
|
|
116
|
-
let inversionIdx = $visibleColumns.length
|
|
117
|
-
for (let i = $visibleColumns.length - 1; i >= 0; i--, inversionIdx--) {
|
|
118
|
-
const rightEdge = $visibleColumns[i].left + $visibleColumns[i].width
|
|
119
|
-
if (rightEdge + MaxCellRenderOverflow <= cutoff) {
|
|
120
|
-
break
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return inversionIdx
|
|
124
|
-
}
|
|
125
|
-
)
|
|
126
|
-
|
|
127
84
|
return {
|
|
128
85
|
scrolledRowCount,
|
|
129
86
|
visualRowCapacity,
|
|
130
87
|
renderedRows,
|
|
131
88
|
columnRenderMap,
|
|
132
|
-
rowVerticalInversionIndex,
|
|
133
|
-
columnHorizontalInversionIndex,
|
|
134
89
|
}
|
|
135
90
|
}
|
package/src/components/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { default as SplitPage } from "./SplitPage.svelte"
|
|
2
2
|
export { default as TestimonialPage } from "./TestimonialPage.svelte"
|
|
3
|
+
export { default as SignatureModal } from "./SignatureModal.svelte"
|
|
3
4
|
export { default as Testimonial } from "./Testimonial.svelte"
|
|
4
5
|
export { default as UserAvatar } from "./UserAvatar.svelte"
|
|
5
6
|
export { default as UserAvatars } from "./UserAvatars.svelte"
|
package/src/constants.js
CHANGED
|
@@ -121,6 +121,7 @@ export const TypeIconMap = {
|
|
|
121
121
|
[FieldType.OPTIONS]: "Dropdown",
|
|
122
122
|
[FieldType.DATETIME]: "Calendar",
|
|
123
123
|
[FieldType.BARCODEQR]: "Camera",
|
|
124
|
+
[FieldType.SIGNATURE_SINGLE]: "AnnotatePen",
|
|
124
125
|
[FieldType.LONGFORM]: "TextAlignLeft",
|
|
125
126
|
[FieldType.ARRAY]: "Duplicate",
|
|
126
127
|
[FieldType.NUMBER]: "123",
|