@budibase/frontend-core 2.6.16-alpha.5 → 2.6.17
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 +4 -4
- package/src/api/groups.js +0 -17
- package/src/components/TestimonialPage.svelte +61 -2
- package/src/components/grid/cells/DataCell.svelte +0 -1
- package/src/components/grid/cells/DateCell.svelte +4 -46
- package/src/components/grid/overlays/MenuOverlay.svelte +4 -34
- package/src/components/grid/stores/rows.js +6 -2
- package/src/components/index.js +0 -1
- package/src/fetch/DataFetch.js +1 -23
- package/src/fetch/fetchData.js +0 -2
- package/src/components/Testimonial.svelte +0 -67
- package/src/fetch/GroupUserFetch.js +0 -51
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/frontend-core",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.17",
|
|
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.6.
|
|
10
|
-
"@budibase/shared-core": "2.6.
|
|
9
|
+
"@budibase/bbui": "^2.6.17",
|
|
10
|
+
"@budibase/shared-core": "^2.6.17",
|
|
11
11
|
"dayjs": "^1.11.7",
|
|
12
12
|
"lodash": "^4.17.21",
|
|
13
13
|
"socket.io-client": "^4.6.1",
|
|
14
14
|
"svelte": "^3.46.2"
|
|
15
15
|
},
|
|
16
|
-
"gitHead": "
|
|
16
|
+
"gitHead": "2a0993fe5e3cab1ec779603cc9228f824e2cea4d"
|
|
17
17
|
}
|
package/src/api/groups.js
CHANGED
|
@@ -52,23 +52,6 @@ export const buildGroupsEndpoints = API => {
|
|
|
52
52
|
})
|
|
53
53
|
},
|
|
54
54
|
|
|
55
|
-
/**
|
|
56
|
-
* Gets a group users by the group id
|
|
57
|
-
*/
|
|
58
|
-
getGroupUsers: async ({ id, bookmark, emailSearch }) => {
|
|
59
|
-
let url = `/api/global/groups/${id}/users?`
|
|
60
|
-
if (bookmark) {
|
|
61
|
-
url += `bookmark=${bookmark}&`
|
|
62
|
-
}
|
|
63
|
-
if (emailSearch) {
|
|
64
|
-
url += `emailSearch=${emailSearch}&`
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return await API.get({
|
|
68
|
-
url,
|
|
69
|
-
})
|
|
70
|
-
},
|
|
71
|
-
|
|
72
55
|
/**
|
|
73
56
|
* Adds users to a group
|
|
74
57
|
* @param groupId The group to update
|
|
@@ -1,15 +1,58 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import SplitPage from "./SplitPage.svelte"
|
|
3
|
-
import
|
|
3
|
+
import { Layout } from "@budibase/bbui"
|
|
4
|
+
import Bulgaria from "../../assets/bulgaria.png"
|
|
5
|
+
import Covanta from "../../assets/covanta.png"
|
|
6
|
+
import Schnellecke from "../../assets/schnellecke.png"
|
|
4
7
|
|
|
5
8
|
export let enabled = true
|
|
9
|
+
|
|
10
|
+
const testimonials = [
|
|
11
|
+
{
|
|
12
|
+
text: "Budibase was the only solution that checked all the boxes for Covanta. Covanta expects to realize $3.2MM in savings due to the elimination of redundant data entry.",
|
|
13
|
+
name: "Charles Link",
|
|
14
|
+
role: "Senior Director, Data and Analytics",
|
|
15
|
+
image: Covanta,
|
|
16
|
+
imageSize: 105,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
text: "Budibase was mission-critical for us and went a long way in preventing what could have become a humanitarian crisis here in Bulgaria.",
|
|
20
|
+
name: "Bozhidar Bozhanov",
|
|
21
|
+
role: "Government of Bulgaria",
|
|
22
|
+
image: Bulgaria,
|
|
23
|
+
imageSize: 49,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
text: "Centralization of authentication, quick turnaround time for requests, integration with different database systems has given it the edge and it’s now used daily for internal development for those apps that you know you need but don’t feel value in losing days of development to reinvent the wheel.",
|
|
27
|
+
name: "Davide Lenzarini",
|
|
28
|
+
role: "IT manager",
|
|
29
|
+
image: Schnellecke,
|
|
30
|
+
imageSize: 141,
|
|
31
|
+
},
|
|
32
|
+
]
|
|
33
|
+
const testimonial = testimonials[Math.floor(Math.random() * 3)]
|
|
6
34
|
</script>
|
|
7
35
|
|
|
8
36
|
<SplitPage>
|
|
9
37
|
<slot />
|
|
10
38
|
<div class:wrapper={enabled} slot="right">
|
|
11
39
|
{#if enabled}
|
|
12
|
-
<
|
|
40
|
+
<div class="testimonial">
|
|
41
|
+
<Layout noPadding gap="S">
|
|
42
|
+
<img
|
|
43
|
+
width={testimonial.imageSize}
|
|
44
|
+
alt="a-happy-budibase-user"
|
|
45
|
+
src={testimonial.image}
|
|
46
|
+
/>
|
|
47
|
+
<div class="text">
|
|
48
|
+
"{testimonial.text}"
|
|
49
|
+
</div>
|
|
50
|
+
<div class="author">
|
|
51
|
+
<div class="name">{testimonial.name}</div>
|
|
52
|
+
<div class="company">{testimonial.role}</div>
|
|
53
|
+
</div>
|
|
54
|
+
</Layout>
|
|
55
|
+
</div>
|
|
13
56
|
{/if}
|
|
14
57
|
</div>
|
|
15
58
|
</SplitPage>
|
|
@@ -21,4 +64,20 @@
|
|
|
21
64
|
display: grid;
|
|
22
65
|
place-items: center;
|
|
23
66
|
}
|
|
67
|
+
.testimonial {
|
|
68
|
+
width: 380px;
|
|
69
|
+
padding: 40px;
|
|
70
|
+
}
|
|
71
|
+
.text {
|
|
72
|
+
font-size: var(--font-size-l);
|
|
73
|
+
font-style: italic;
|
|
74
|
+
}
|
|
75
|
+
.name {
|
|
76
|
+
font-weight: bold;
|
|
77
|
+
color: var(--spectrum-global-color-gray-900);
|
|
78
|
+
font-size: var(--font-size-l);
|
|
79
|
+
}
|
|
80
|
+
.company {
|
|
81
|
+
color: var(--spectrum-global-color-gray-700);
|
|
82
|
+
}
|
|
24
83
|
</style>
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import dayjs from "dayjs"
|
|
3
3
|
import { CoreDatePicker, Icon } from "@budibase/bbui"
|
|
4
|
-
import { onMount } from "svelte"
|
|
5
4
|
|
|
6
5
|
export let value
|
|
7
6
|
export let schema
|
|
8
7
|
export let onChange
|
|
9
8
|
export let focused = false
|
|
10
9
|
export let readonly = false
|
|
11
|
-
export let api
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
let isOpen
|
|
15
|
-
|
|
16
|
-
// Adding the 0- will turn a string like 00:00:00 into a valid ISO
|
|
11
|
+
// adding the 0- will turn a string like 00:00:00 into a valid ISO
|
|
17
12
|
// date, but will make actual ISO dates invalid
|
|
18
|
-
$:
|
|
19
|
-
$: timeOnly =
|
|
13
|
+
$: time = new Date(`0-${value}`)
|
|
14
|
+
$: timeOnly = !isNaN(time) || schema?.timeOnly
|
|
20
15
|
$: dateOnly = schema?.dateOnly
|
|
21
16
|
$: format = timeOnly
|
|
22
17
|
? "HH:mm:ss"
|
|
@@ -24,45 +19,12 @@
|
|
|
24
19
|
? "MMM D YYYY"
|
|
25
20
|
: "MMM D YYYY, HH:mm"
|
|
26
21
|
$: editable = focused && !readonly
|
|
27
|
-
$: displayValue = getDisplayValue(value, format, timeOnly, isTimeValue)
|
|
28
|
-
|
|
29
|
-
const getDisplayValue = (value, format, timeOnly, isTimeValue) => {
|
|
30
|
-
if (!value) {
|
|
31
|
-
return ""
|
|
32
|
-
}
|
|
33
|
-
// Parse full date strings
|
|
34
|
-
if (!timeOnly || !isTimeValue) {
|
|
35
|
-
return dayjs(value).format(format)
|
|
36
|
-
}
|
|
37
|
-
// Otherwise must be a time string
|
|
38
|
-
return dayjs(`0-${value}`).format(format)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Ensure we close flatpickr when unselected
|
|
42
|
-
$: {
|
|
43
|
-
if (!focused) {
|
|
44
|
-
flatpickr?.close()
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const onKeyDown = () => {
|
|
49
|
-
return isOpen
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
onMount(() => {
|
|
53
|
-
api = {
|
|
54
|
-
onKeyDown,
|
|
55
|
-
focus: () => flatpickr?.open(),
|
|
56
|
-
blur: () => flatpickr?.close(),
|
|
57
|
-
isActive: () => isOpen,
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
22
|
</script>
|
|
61
23
|
|
|
62
24
|
<div class="container">
|
|
63
25
|
<div class="value">
|
|
64
26
|
{#if value}
|
|
65
|
-
{
|
|
27
|
+
{dayjs(timeOnly ? time : value).format(format)}
|
|
66
28
|
{/if}
|
|
67
29
|
</div>
|
|
68
30
|
{#if editable}
|
|
@@ -80,10 +42,6 @@
|
|
|
80
42
|
{timeOnly}
|
|
81
43
|
time24hr
|
|
82
44
|
ignoreTimezones={schema.ignoreTimezones}
|
|
83
|
-
bind:flatpickr
|
|
84
|
-
on:open={() => (isOpen = true)}
|
|
85
|
-
on:close={() => (isOpen = false)}
|
|
86
|
-
useKeyboardShortcuts={false}
|
|
87
45
|
/>
|
|
88
46
|
</div>
|
|
89
47
|
{/if}
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import {
|
|
3
|
-
clickOutside,
|
|
4
|
-
Menu,
|
|
5
|
-
MenuItem,
|
|
6
|
-
Helpers,
|
|
7
|
-
notifications,
|
|
8
|
-
} from "@budibase/bbui"
|
|
2
|
+
import { clickOutside, Menu, MenuItem, notifications } from "@budibase/bbui"
|
|
9
3
|
import { getContext } from "svelte"
|
|
10
|
-
import { NewRowID } from "../lib/constants"
|
|
11
4
|
|
|
12
5
|
const {
|
|
13
6
|
focusedRow,
|
|
@@ -21,11 +14,9 @@
|
|
|
21
14
|
clipboard,
|
|
22
15
|
dispatch,
|
|
23
16
|
focusedCellAPI,
|
|
24
|
-
focusedRowId,
|
|
25
17
|
} = getContext("grid")
|
|
26
18
|
|
|
27
19
|
$: style = makeStyle($menu)
|
|
28
|
-
$: isNewRow = $focusedRowId === NewRowID
|
|
29
20
|
|
|
30
21
|
const makeStyle = menu => {
|
|
31
22
|
return `left:${menu.left}px; top:${menu.top}px;`
|
|
@@ -45,11 +36,6 @@
|
|
|
45
36
|
$focusedCellId = `${newRow._id}-${column}`
|
|
46
37
|
}
|
|
47
38
|
}
|
|
48
|
-
|
|
49
|
-
const copyToClipboard = async value => {
|
|
50
|
-
await Helpers.copyToClipboard(value)
|
|
51
|
-
notifications.success("Copied to clipboard")
|
|
52
|
-
}
|
|
53
39
|
</script>
|
|
54
40
|
|
|
55
41
|
{#if $menu.visible}
|
|
@@ -72,38 +58,22 @@
|
|
|
72
58
|
</MenuItem>
|
|
73
59
|
<MenuItem
|
|
74
60
|
icon="Maximize"
|
|
75
|
-
disabled={
|
|
61
|
+
disabled={!$config.allowEditRows}
|
|
76
62
|
on:click={() => dispatch("edit-row", $focusedRow)}
|
|
77
63
|
on:click={menu.actions.close}
|
|
78
64
|
>
|
|
79
65
|
Edit row in modal
|
|
80
66
|
</MenuItem>
|
|
81
|
-
<MenuItem
|
|
82
|
-
icon="Copy"
|
|
83
|
-
disabled={isNewRow || !$focusedRow?._id}
|
|
84
|
-
on:click={() => copyToClipboard($focusedRow?._id)}
|
|
85
|
-
on:click={menu.actions.close}
|
|
86
|
-
>
|
|
87
|
-
Copy row _id
|
|
88
|
-
</MenuItem>
|
|
89
|
-
<MenuItem
|
|
90
|
-
icon="Copy"
|
|
91
|
-
disabled={isNewRow || !$focusedRow?._rev}
|
|
92
|
-
on:click={() => copyToClipboard($focusedRow?._rev)}
|
|
93
|
-
on:click={menu.actions.close}
|
|
94
|
-
>
|
|
95
|
-
Copy row _rev
|
|
96
|
-
</MenuItem>
|
|
97
67
|
<MenuItem
|
|
98
68
|
icon="Duplicate"
|
|
99
|
-
disabled={
|
|
69
|
+
disabled={!$config.allowAddRows}
|
|
100
70
|
on:click={duplicate}
|
|
101
71
|
>
|
|
102
72
|
Duplicate row
|
|
103
73
|
</MenuItem>
|
|
104
74
|
<MenuItem
|
|
105
75
|
icon="Delete"
|
|
106
|
-
disabled={
|
|
76
|
+
disabled={!$config.allowDeleteRows}
|
|
107
77
|
on:click={deleteRow}
|
|
108
78
|
>
|
|
109
79
|
Delete row
|
|
@@ -338,11 +338,15 @@ export const deriveStores = context => {
|
|
|
338
338
|
...state,
|
|
339
339
|
[rowId]: true,
|
|
340
340
|
}))
|
|
341
|
-
const
|
|
341
|
+
const newRow = { ...row, ...get(rowChangeCache)[rowId] }
|
|
342
|
+
const saved = await API.saveRow(newRow)
|
|
342
343
|
|
|
343
344
|
// Update state after a successful change
|
|
344
345
|
rows.update(state => {
|
|
345
|
-
state[index] =
|
|
346
|
+
state[index] = {
|
|
347
|
+
...newRow,
|
|
348
|
+
_rev: saved._rev,
|
|
349
|
+
}
|
|
346
350
|
return state.slice()
|
|
347
351
|
})
|
|
348
352
|
rowChangeCache.update(state => {
|
package/src/components/index.js
CHANGED
package/src/fetch/DataFetch.js
CHANGED
|
@@ -362,35 +362,13 @@ export default class DataFetch {
|
|
|
362
362
|
return
|
|
363
363
|
}
|
|
364
364
|
this.store.update($store => ({ ...$store, loading: true }))
|
|
365
|
-
const { rows, info, error
|
|
366
|
-
|
|
367
|
-
let { cursors } = get(this.store)
|
|
368
|
-
const { pageNumber } = get(this.store)
|
|
369
|
-
|
|
370
|
-
if (!rows.length && pageNumber > 0) {
|
|
371
|
-
// If the full page is gone but we have previous pages, navigate to the previous page
|
|
372
|
-
this.store.update($store => ({
|
|
373
|
-
...$store,
|
|
374
|
-
loading: false,
|
|
375
|
-
cursors: cursors.slice(0, pageNumber),
|
|
376
|
-
}))
|
|
377
|
-
return await this.prevPage()
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const currentNextCursor = cursors[pageNumber + 1]
|
|
381
|
-
if (currentNextCursor != cursor) {
|
|
382
|
-
// If the current cursor changed, all the next pages need to be updated, so we mark them as stale
|
|
383
|
-
cursors = cursors.slice(0, pageNumber + 1)
|
|
384
|
-
cursors[pageNumber + 1] = cursor
|
|
385
|
-
}
|
|
386
|
-
|
|
365
|
+
const { rows, info, error } = await this.getPage()
|
|
387
366
|
this.store.update($store => ({
|
|
388
367
|
...$store,
|
|
389
368
|
rows,
|
|
390
369
|
info,
|
|
391
370
|
loading: false,
|
|
392
371
|
error,
|
|
393
|
-
cursors,
|
|
394
372
|
}))
|
|
395
373
|
}
|
|
396
374
|
|
package/src/fetch/fetchData.js
CHANGED
|
@@ -6,7 +6,6 @@ import NestedProviderFetch from "./NestedProviderFetch.js"
|
|
|
6
6
|
import FieldFetch from "./FieldFetch.js"
|
|
7
7
|
import JSONArrayFetch from "./JSONArrayFetch.js"
|
|
8
8
|
import UserFetch from "./UserFetch.js"
|
|
9
|
-
import GroupUserFetch from "./GroupUserFetch.js"
|
|
10
9
|
|
|
11
10
|
const DataFetchMap = {
|
|
12
11
|
table: TableFetch,
|
|
@@ -14,7 +13,6 @@ const DataFetchMap = {
|
|
|
14
13
|
query: QueryFetch,
|
|
15
14
|
link: RelationshipFetch,
|
|
16
15
|
user: UserFetch,
|
|
17
|
-
groupUser: GroupUserFetch,
|
|
18
16
|
|
|
19
17
|
// Client specific datasource types
|
|
20
18
|
provider: NestedProviderFetch,
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { Layout } from "@budibase/bbui"
|
|
3
|
-
import Bulgaria from "../../assets/bulgaria.png"
|
|
4
|
-
import Covanta from "../../assets/covanta.png"
|
|
5
|
-
import Schnellecke from "../../assets/schnellecke.png"
|
|
6
|
-
|
|
7
|
-
const testimonials = [
|
|
8
|
-
{
|
|
9
|
-
text: "Budibase was the only solution that checked all the boxes for Covanta. Covanta expects to realize $3.2MM in savings due to the elimination of redundant data entry.",
|
|
10
|
-
name: "Charles Link",
|
|
11
|
-
role: "Senior Director, Data and Analytics",
|
|
12
|
-
image: Covanta,
|
|
13
|
-
imageSize: 105,
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
text: "Budibase was mission-critical for us and went a long way in preventing what could have become a humanitarian crisis here in Bulgaria.",
|
|
17
|
-
name: "Bozhidar Bozhanov",
|
|
18
|
-
role: "Government of Bulgaria",
|
|
19
|
-
image: Bulgaria,
|
|
20
|
-
imageSize: 49,
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
text: "Centralization of authentication, quick turnaround time for requests, integration with different database systems has given it the edge and it’s now used daily for internal development for those apps that you know you need but don’t feel value in losing days of development to reinvent the wheel.",
|
|
24
|
-
name: "Davide Lenzarini",
|
|
25
|
-
role: "IT manager",
|
|
26
|
-
image: Schnellecke,
|
|
27
|
-
imageSize: 141,
|
|
28
|
-
},
|
|
29
|
-
]
|
|
30
|
-
const testimonial = testimonials[Math.floor(Math.random() * 3)]
|
|
31
|
-
</script>
|
|
32
|
-
|
|
33
|
-
<div class="testimonial">
|
|
34
|
-
<Layout noPadding gap="S">
|
|
35
|
-
<img
|
|
36
|
-
width={testimonial.imageSize}
|
|
37
|
-
alt="a-happy-budibase-user"
|
|
38
|
-
src={testimonial.image}
|
|
39
|
-
/>
|
|
40
|
-
<div class="text">
|
|
41
|
-
"{testimonial.text}"
|
|
42
|
-
</div>
|
|
43
|
-
<div class="author">
|
|
44
|
-
<div class="name">{testimonial.name}</div>
|
|
45
|
-
<div class="company">{testimonial.role}</div>
|
|
46
|
-
</div>
|
|
47
|
-
</Layout>
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<style>
|
|
51
|
-
.testimonial {
|
|
52
|
-
width: 380px;
|
|
53
|
-
padding: 40px;
|
|
54
|
-
}
|
|
55
|
-
.text {
|
|
56
|
-
font-size: var(--font-size-l);
|
|
57
|
-
font-style: italic;
|
|
58
|
-
}
|
|
59
|
-
.name {
|
|
60
|
-
font-weight: bold;
|
|
61
|
-
color: var(--spectrum-global-color-gray-900);
|
|
62
|
-
font-size: var(--font-size-l);
|
|
63
|
-
}
|
|
64
|
-
.company {
|
|
65
|
-
color: var(--spectrum-global-color-gray-700);
|
|
66
|
-
}
|
|
67
|
-
</style>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { get } from "svelte/store"
|
|
2
|
-
import DataFetch from "./DataFetch.js"
|
|
3
|
-
import { TableNames } from "../constants"
|
|
4
|
-
|
|
5
|
-
export default class GroupUserFetch extends DataFetch {
|
|
6
|
-
constructor(opts) {
|
|
7
|
-
super({
|
|
8
|
-
...opts,
|
|
9
|
-
datasource: {
|
|
10
|
-
tableId: TableNames.USERS,
|
|
11
|
-
},
|
|
12
|
-
})
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
determineFeatureFlags() {
|
|
16
|
-
return {
|
|
17
|
-
supportsSearch: true,
|
|
18
|
-
supportsSort: false,
|
|
19
|
-
supportsPagination: true,
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async getDefinition() {
|
|
24
|
-
return {
|
|
25
|
-
schema: {},
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async getData() {
|
|
30
|
-
const { query, cursor } = get(this.store)
|
|
31
|
-
try {
|
|
32
|
-
const res = await this.API.getGroupUsers({
|
|
33
|
-
id: query.groupId,
|
|
34
|
-
emailSearch: query.emailSearch,
|
|
35
|
-
bookmark: cursor,
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
rows: res?.users || [],
|
|
40
|
-
hasNextPage: res?.hasNextPage || false,
|
|
41
|
-
cursor: res?.bookmark || null,
|
|
42
|
-
}
|
|
43
|
-
} catch (error) {
|
|
44
|
-
return {
|
|
45
|
-
rows: [],
|
|
46
|
-
hasNextPage: false,
|
|
47
|
-
error,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|