@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 CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@budibase/frontend-core",
3
- "version": "2.6.16-alpha.5",
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.16-alpha.5",
10
- "@budibase/shared-core": "2.6.16-alpha.5",
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": "bbb516f26ae966668b5fa65418d81fbccf3dce37"
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 Testimonial from "./Testimonial.svelte"
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
- <Testimonial />
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>
@@ -32,7 +32,6 @@
32
32
  $: readonly =
33
33
  column.schema.autocolumn ||
34
34
  column.schema.disabled ||
35
- column.schema.type === "formula" ||
36
35
  (!$config.allowEditRows && row._id)
37
36
 
38
37
  // Register this cell API if the row is focused
@@ -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
- let flatpickr
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
- $: isTimeValue = !isNaN(new Date(`0-${value}`))
19
- $: timeOnly = isTimeValue || schema?.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
- {displayValue}
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={isNewRow || !$config.allowEditRows}
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={isNewRow || !$config.allowAddRows}
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={isNewRow || !$config.allowDeleteRows}
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 saved = await API.saveRow({ ...row, ...get(rowChangeCache)[rowId] })
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] = saved
346
+ state[index] = {
347
+ ...newRow,
348
+ _rev: saved._rev,
349
+ }
346
350
  return state.slice()
347
351
  })
348
352
  rowChangeCache.update(state => {
@@ -1,4 +1,3 @@
1
1
  export { default as SplitPage } from "./SplitPage.svelte"
2
2
  export { default as TestimonialPage } from "./TestimonialPage.svelte"
3
- export { default as Testimonial } from "./Testimonial.svelte"
4
3
  export { Grid } from "./grid"
@@ -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, cursor } = await this.getPage()
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
 
@@ -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
- }