@budibase/frontend-core 2.33.14 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/package.json +5 -5
  2. package/src/api/automations.js +2 -7
  3. package/src/api/index.js +2 -0
  4. package/src/api/rowActions.js +90 -0
  5. package/src/api/tables.js +1 -1
  6. package/src/api/viewsV2.js +1 -0
  7. package/src/components/CoreFilterBuilder.svelte +532 -0
  8. package/src/components/FilterField.svelte +319 -0
  9. package/src/components/FilterUsers.svelte +2 -1
  10. package/src/components/grid/cells/AICell.svelte +99 -0
  11. package/src/components/grid/cells/DataCell.svelte +1 -1
  12. package/src/components/grid/cells/GridCell.svelte +6 -1
  13. package/src/components/grid/cells/HeaderCell.svelte +20 -11
  14. package/src/components/grid/cells/NumberCell.svelte +23 -1
  15. package/src/components/grid/cells/RelationshipCell.svelte +1 -3
  16. package/src/components/grid/cells/RoleCell.svelte +45 -0
  17. package/src/components/grid/cells/TextCell.svelte +3 -1
  18. package/src/components/grid/layout/ButtonColumn.svelte +67 -36
  19. package/src/components/grid/layout/Grid.svelte +22 -27
  20. package/src/components/grid/lib/constants.js +2 -0
  21. package/src/components/grid/lib/renderers.js +9 -0
  22. package/src/components/grid/lib/utils.js +13 -31
  23. package/src/components/grid/lib/websocket.js +9 -0
  24. package/src/components/grid/overlays/GridPopover.svelte +4 -2
  25. package/src/components/grid/overlays/MenuOverlay.svelte +19 -0
  26. package/src/components/grid/stores/columns.js +2 -1
  27. package/src/components/grid/stores/config.js +12 -3
  28. package/src/components/grid/stores/datasource.js +27 -10
  29. package/src/components/grid/stores/datasources/nonPlus.js +3 -2
  30. package/src/components/grid/stores/datasources/table.js +3 -2
  31. package/src/components/grid/stores/datasources/viewV2.js +58 -27
  32. package/src/components/grid/stores/filter.js +25 -7
  33. package/src/components/grid/stores/rows.js +11 -6
  34. package/src/components/grid/stores/sort.js +7 -3
  35. package/src/components/index.js +1 -1
  36. package/src/constants.js +17 -30
  37. package/src/fetch/DataFetch.js +17 -9
  38. package/src/fetch/TableFetch.js +2 -1
  39. package/src/fetch/UserFetch.js +7 -8
  40. package/src/fetch/ViewV2Fetch.js +18 -13
  41. package/src/utils/index.js +1 -1
  42. package/src/utils/relatedColumns.js +6 -10
  43. package/src/utils/roles.js +0 -13
  44. package/src/utils/schema.js +24 -0
  45. package/src/utils/table.js +6 -6
  46. package/src/utils/utils.js +1 -1
  47. package/src/components/FilterBuilder.svelte +0 -379
  48. package/src/components/grid/controls/ColumnsSettingButton.svelte +0 -41
  49. package/src/components/grid/controls/ColumnsSettingContent.svelte +0 -270
  50. package/src/components/grid/controls/SizeButton.svelte +0 -136
  51. package/src/components/grid/controls/SortButton.svelte +0 -96
  52. package/src/components/grid/controls/ToggleActionButtonGroup.svelte +0 -41
  53. package/src/utils/theme.js +0 -12
@@ -1,379 +0,0 @@
1
- <script>
2
- import {
3
- Body,
4
- Button,
5
- Combobox,
6
- DatePicker,
7
- Icon,
8
- Input,
9
- Layout,
10
- Select,
11
- Label,
12
- Multiselect,
13
- } from "@budibase/bbui"
14
- import { ArrayOperator, FieldType } from "@budibase/types"
15
- import { generate } from "shortid"
16
- import { QueryUtils, Constants } from "@budibase/frontend-core"
17
- import { getContext } from "svelte"
18
- import FilterUsers from "./FilterUsers.svelte"
19
-
20
- const { OperatorOptions, DEFAULT_BB_DATASOURCE_ID } = Constants
21
-
22
- export let schemaFields
23
- export let filters = []
24
- export let tables = []
25
- export let datasource
26
- export let behaviourFilters = false
27
- export let allowBindings = false
28
- export let filtersLabel = "Filters"
29
- export let showFilterEmptyDropdown = true
30
- $: {
31
- if (
32
- tables.find(
33
- table =>
34
- table._id === datasource?.tableId &&
35
- table.sourceId === DEFAULT_BB_DATASOURCE_ID
36
- ) &&
37
- !schemaFields.some(field => field.name === "_id")
38
- ) {
39
- schemaFields = [...schemaFields, { name: "_id", type: "string" }]
40
- }
41
- }
42
-
43
- $: matchAny = filters?.find(filter => filter.operator === "allOr") != null
44
- $: onEmptyFilter =
45
- filters?.find(filter => filter.onEmptyFilter)?.onEmptyFilter ?? "all"
46
-
47
- $: fieldFilters = filters.filter(
48
- filter => filter.operator !== "allOr" && !filter.onEmptyFilter
49
- )
50
- const behaviourOptions = [
51
- { value: "and", label: "Match all filters" },
52
- { value: "or", label: "Match any filter" },
53
- ]
54
- const onEmptyOptions = [
55
- { value: "all", label: "Return all table rows" },
56
- { value: "none", label: "Return no rows" },
57
- ]
58
- const context = getContext("context")
59
-
60
- $: fieldOptions = (schemaFields || []).map(field => ({
61
- label: field.displayName || field.name,
62
- value: field.name,
63
- }))
64
-
65
- const addFilter = () => {
66
- filters = [
67
- ...(filters || []),
68
- {
69
- id: generate(),
70
- field: null,
71
- operator: OperatorOptions.Equals.value,
72
- value: null,
73
- valueType: "Value",
74
- },
75
- ]
76
- }
77
-
78
- const removeFilter = id => {
79
- filters = filters.filter(field => field.id !== id)
80
-
81
- // Clear all filters when no fields are specified
82
- if (filters.length === 1 && filters[0].onEmptyFilter) {
83
- filters = []
84
- }
85
- }
86
-
87
- const duplicateFilter = id => {
88
- const existingFilter = filters.find(filter => filter.id === id)
89
- const duplicate = { ...existingFilter, id: generate() }
90
- filters = [...filters, duplicate]
91
- }
92
-
93
- const onFieldChange = filter => {
94
- const previousType = filter.type
95
- sanitizeTypes(filter)
96
- sanitizeOperator(filter)
97
- sanitizeValue(filter, previousType)
98
- }
99
-
100
- const onOperatorChange = filter => {
101
- sanitizeOperator(filter)
102
- sanitizeValue(filter, filter.type)
103
- }
104
-
105
- const onValueTypeChange = filter => {
106
- sanitizeValue(filter)
107
- }
108
-
109
- const getFieldOptions = field => {
110
- const schema = schemaFields.find(x => x.name === field)
111
- return schema?.constraints?.inclusion || []
112
- }
113
-
114
- const getSchema = filter => {
115
- return schemaFields.find(field => field.name === filter.field)
116
- }
117
-
118
- const getValidOperatorsForType = filter => {
119
- if (!filter?.field && !filter?.name) {
120
- return []
121
- }
122
-
123
- return QueryUtils.getValidOperatorsForType(
124
- filter,
125
- filter.field || filter.name,
126
- datasource
127
- )
128
- }
129
-
130
- $: valueTypeOptions = allowBindings ? ["Value", "Binding"] : ["Value"]
131
-
132
- const sanitizeTypes = filter => {
133
- // Update type based on field
134
- const fieldSchema = schemaFields.find(x => x.name === filter.field)
135
- filter.type = fieldSchema?.type
136
- filter.subtype = fieldSchema?.subtype
137
- filter.formulaType = fieldSchema?.formulaType
138
- filter.constraints = fieldSchema?.constraints
139
-
140
- // Update external type based on field
141
- filter.externalType = getSchema(filter)?.externalType
142
- }
143
-
144
- const sanitizeOperator = filter => {
145
- // Ensure a valid operator is selected
146
- const operators = getValidOperatorsForType(filter).map(x => x.value)
147
- if (!operators.includes(filter.operator)) {
148
- filter.operator = operators[0] ?? OperatorOptions.Equals.value
149
- }
150
-
151
- // Update the noValue flag if the operator does not take a value
152
- const noValueOptions = [
153
- OperatorOptions.Empty.value,
154
- OperatorOptions.NotEmpty.value,
155
- ]
156
- filter.noValue = noValueOptions.includes(filter.operator)
157
- }
158
-
159
- const sanitizeValue = (filter, previousType) => {
160
- // Check if the operator allows a value at all
161
- if (filter.noValue) {
162
- filter.value = null
163
- return
164
- }
165
-
166
- // Ensure array values are properly set and cleared
167
- if (Array.isArray(filter.value)) {
168
- if (filter.valueType !== "Value" || filter.type !== FieldType.ARRAY) {
169
- filter.value = null
170
- }
171
- } else if (
172
- filter.type === FieldType.ARRAY &&
173
- filter.valueType === "Value"
174
- ) {
175
- filter.value = []
176
- } else if (
177
- previousType !== filter.type &&
178
- (previousType === FieldType.BB_REFERENCE ||
179
- filter.type === FieldType.BB_REFERENCE)
180
- ) {
181
- filter.value = filter.type === FieldType.ARRAY ? [] : null
182
- }
183
- }
184
-
185
- function handleAllOr(option) {
186
- filters = filters.filter(f => f.operator !== "allOr")
187
- if (option === "or") {
188
- filters.push({ operator: "allOr" })
189
- }
190
- }
191
-
192
- function handleOnEmptyFilter(value) {
193
- filters = filters?.filter(filter => !filter.onEmptyFilter)
194
- filters.push({ onEmptyFilter: value })
195
- }
196
- </script>
197
-
198
- <div class="container" class:mobile={$context?.device?.mobile}>
199
- <Layout noPadding>
200
- {#if fieldOptions?.length}
201
- <Body size="S">
202
- {#if !fieldFilters?.length}
203
- Add your first filter expression.
204
- {:else}
205
- <slot name="filtering-hero-content" />
206
- {#if behaviourFilters}
207
- <div class="behaviour-filters">
208
- <Select
209
- label="Behaviour"
210
- value={matchAny ? "or" : "and"}
211
- options={behaviourOptions}
212
- getOptionLabel={opt => opt.label}
213
- getOptionValue={opt => opt.value}
214
- on:change={e => handleAllOr(e.detail)}
215
- placeholder={null}
216
- />
217
- {#if datasource?.type === "table" && showFilterEmptyDropdown}
218
- <Select
219
- label="When filter empty"
220
- value={onEmptyFilter}
221
- options={onEmptyOptions}
222
- getOptionLabel={opt => opt.label}
223
- getOptionValue={opt => opt.value}
224
- on:change={e => handleOnEmptyFilter(e.detail)}
225
- placeholder={null}
226
- />
227
- {/if}
228
- </div>
229
- {/if}
230
- {/if}
231
- </Body>
232
- {#if fieldFilters?.length}
233
- <div>
234
- {#if filtersLabel}
235
- <div class="filter-label">
236
- <Label>{filtersLabel}</Label>
237
- </div>
238
- {/if}
239
- <div class="fields" class:with-bindings={allowBindings}>
240
- {#each fieldFilters as filter}
241
- <Select
242
- bind:value={filter.field}
243
- options={fieldOptions}
244
- on:change={() => onFieldChange(filter)}
245
- placeholder="Column"
246
- />
247
- <Select
248
- disabled={!filter.field}
249
- options={getValidOperatorsForType(filter)}
250
- bind:value={filter.operator}
251
- on:change={() => onOperatorChange(filter)}
252
- placeholder={null}
253
- />
254
- {#if allowBindings}
255
- <Select
256
- disabled={filter.noValue || !filter.field}
257
- options={valueTypeOptions}
258
- bind:value={filter.valueType}
259
- on:change={() => onValueTypeChange(filter)}
260
- placeholder={null}
261
- />
262
- {/if}
263
- {#if allowBindings && filter.field && filter.valueType === "Binding"}
264
- <slot name="binding" {filter} />
265
- {:else if [FieldType.STRING, FieldType.LONGFORM, FieldType.NUMBER, FieldType.BIGINT, FieldType.FORMULA].includes(filter.type)}
266
- <Input disabled={filter.noValue} bind:value={filter.value} />
267
- {:else if filter.type === FieldType.ARRAY || (filter.type === FieldType.OPTIONS && filter.operator === ArrayOperator.ONE_OF)}
268
- <Multiselect
269
- disabled={filter.noValue}
270
- options={getFieldOptions(filter.field)}
271
- bind:value={filter.value}
272
- />
273
- {:else if filter.type === FieldType.OPTIONS}
274
- <Combobox
275
- disabled={filter.noValue}
276
- options={getFieldOptions(filter.field)}
277
- bind:value={filter.value}
278
- />
279
- {:else if filter.type === FieldType.BOOLEAN}
280
- <Combobox
281
- disabled={filter.noValue}
282
- options={[
283
- { label: "True", value: "true" },
284
- { label: "False", value: "false" },
285
- ]}
286
- bind:value={filter.value}
287
- />
288
- {:else if filter.type === FieldType.DATETIME}
289
- <DatePicker
290
- disabled={filter.noValue}
291
- enableTime={!getSchema(filter)?.dateOnly}
292
- timeOnly={getSchema(filter)?.timeOnly}
293
- bind:value={filter.value}
294
- />
295
- {:else if [FieldType.BB_REFERENCE, FieldType.BB_REFERENCE_SINGLE].includes(filter.type)}
296
- <FilterUsers
297
- bind:value={filter.value}
298
- multiselect={[
299
- OperatorOptions.In.value,
300
- OperatorOptions.ContainsAny.value,
301
- ].includes(filter.operator)}
302
- disabled={filter.noValue}
303
- type={filter.valueType}
304
- />
305
- {:else}
306
- <Input disabled />
307
- {/if}
308
- <div class="controls">
309
- <Icon
310
- name="Duplicate"
311
- hoverable
312
- size="S"
313
- on:click={() => duplicateFilter(filter.id)}
314
- />
315
- <Icon
316
- name="Close"
317
- hoverable
318
- size="S"
319
- on:click={() => removeFilter(filter.id)}
320
- />
321
- </div>
322
- {/each}
323
- </div>
324
- </div>
325
- {/if}
326
- <div>
327
- <Button icon="AddCircle" size="M" secondary on:click={addFilter}>
328
- Add filter
329
- </Button>
330
- </div>
331
- {:else}
332
- <Body size="S">None of the table column can be used for filtering.</Body>
333
- {/if}
334
- </Layout>
335
- </div>
336
-
337
- <style>
338
- .container {
339
- width: 100%;
340
- }
341
- .fields {
342
- display: grid;
343
- column-gap: var(--spacing-l);
344
- row-gap: var(--spacing-s);
345
- align-items: center;
346
- grid-template-columns: 1fr 120px 1fr auto auto;
347
- }
348
- .fields.with-bindings {
349
- grid-template-columns: minmax(150px, 1fr) 170px 120px minmax(150px, 1fr) 16px 16px;
350
- }
351
-
352
- .controls {
353
- display: contents;
354
- }
355
-
356
- .container.mobile .fields {
357
- grid-template-columns: 1fr;
358
- }
359
- .container.mobile .controls {
360
- display: flex;
361
- flex-direction: row;
362
- justify-content: flex-start;
363
- align-items: center;
364
- padding: var(--spacing-s) 0;
365
- gap: var(--spacing-s);
366
- }
367
-
368
- .filter-label {
369
- margin-bottom: var(--spacing-s);
370
- }
371
-
372
- .behaviour-filters {
373
- display: grid;
374
- column-gap: var(--spacing-l);
375
- row-gap: var(--spacing-s);
376
- align-items: center;
377
- grid-template-columns: minmax(150px, 1fr) 170px 120px minmax(150px, 1fr) 16px 16px;
378
- }
379
- </style>
@@ -1,41 +0,0 @@
1
- <script>
2
- import { getContext } from "svelte"
3
- import { ActionButton, Popover } from "@budibase/bbui"
4
- import ColumnsSettingContent from "./ColumnsSettingContent.svelte"
5
- import { FieldPermissions } from "../../../constants"
6
-
7
- const { tableColumns, datasource } = getContext("grid")
8
-
9
- let open = false
10
- let anchor
11
-
12
- $: anyRestricted = $tableColumns.filter(
13
- col => !col.visible || col.readonly
14
- ).length
15
- $: text = anyRestricted ? `Columns (${anyRestricted} restricted)` : "Columns"
16
- $: permissions =
17
- $datasource.type === "viewV2"
18
- ? [
19
- FieldPermissions.WRITABLE,
20
- FieldPermissions.READONLY,
21
- FieldPermissions.HIDDEN,
22
- ]
23
- : [FieldPermissions.WRITABLE, FieldPermissions.HIDDEN]
24
- </script>
25
-
26
- <div bind:this={anchor}>
27
- <ActionButton
28
- icon="ColumnSettings"
29
- quiet
30
- size="M"
31
- on:click={() => (open = !open)}
32
- selected={open || anyRestricted}
33
- disabled={!$tableColumns.length}
34
- >
35
- {text}
36
- </ActionButton>
37
- </div>
38
-
39
- <Popover bind:open {anchor} align="left">
40
- <ColumnsSettingContent columns={$tableColumns} {permissions} />
41
- </Popover>
@@ -1,270 +0,0 @@
1
- <script>
2
- import { getContext } from "svelte"
3
- import { Icon, notifications, ActionButton, Popover } from "@budibase/bbui"
4
- import { getColumnIcon } from "../lib/utils"
5
- import ToggleActionButtonGroup from "./ToggleActionButtonGroup.svelte"
6
- import { helpers } from "@budibase/shared-core"
7
- import { FieldType } from "@budibase/types"
8
- import { FieldPermissions } from "../../../constants"
9
-
10
- export let permissions = [FieldPermissions.WRITABLE, FieldPermissions.HIDDEN]
11
- export let disabledPermissions = []
12
- export let columns
13
- export let fromRelationshipField
14
-
15
- const { datasource, dispatch, config } = getContext("grid")
16
-
17
- $: canSetRelationshipSchemas = $config.canSetRelationshipSchemas
18
-
19
- let relationshipPanelAnchor
20
- let relationshipFieldName
21
-
22
- $: relationshipField = columns.find(
23
- c => c.name === relationshipFieldName
24
- )?.schema
25
- $: permissionsObj = permissions.reduce(
26
- (acc, c) => ({
27
- ...acc,
28
- [c]: {
29
- disabled: disabledPermissions.includes(c),
30
- },
31
- }),
32
- {}
33
- )
34
-
35
- $: displayColumns = columns.map(c => {
36
- const isRequired =
37
- c.primaryDisplay || helpers.schema.isRequired(c.schema.constraints)
38
-
39
- const defaultPermission = permissions[0]
40
- const requiredTooltips = {
41
- [FieldPermissions.WRITABLE]: (() => {
42
- if (defaultPermission === FieldPermissions.WRITABLE) {
43
- if (c.primaryDisplay) {
44
- return "Display column must be writable"
45
- }
46
- if (isRequired) {
47
- return "Required columns must be writable"
48
- }
49
- }
50
- })(),
51
- [FieldPermissions.READONLY]: (() => {
52
- if (defaultPermission === FieldPermissions.WRITABLE) {
53
- if (c.primaryDisplay) {
54
- return "Display column cannot be read-only"
55
- }
56
- if (isRequired) {
57
- return "Required columns cannot be read-only"
58
- }
59
- }
60
- if (defaultPermission === FieldPermissions.READONLY) {
61
- if (c.primaryDisplay) {
62
- return "Display column must be read-only"
63
- }
64
- if (isRequired) {
65
- return "Required columns must be read-only"
66
- }
67
- }
68
- })(),
69
- [FieldPermissions.HIDDEN]: (() => {
70
- if (c.primaryDisplay) {
71
- return "Display column cannot be hidden"
72
- }
73
- if (isRequired) {
74
- return "Required columns cannot be hidden"
75
- }
76
- })(),
77
- }
78
-
79
- const options = []
80
-
81
- let permission
82
- if ((permission = permissionsObj[FieldPermissions.WRITABLE])) {
83
- const tooltip = requiredTooltips[FieldPermissions.WRITABLE] || "Writable"
84
- options.push({
85
- icon: "Edit",
86
- value: FieldPermissions.WRITABLE,
87
- tooltip,
88
- disabled: isRequired || permission.disabled,
89
- })
90
- }
91
-
92
- if ((permission = permissionsObj[FieldPermissions.READONLY])) {
93
- const tooltip =
94
- (requiredTooltips[FieldPermissions.READONLY] || "Read-only") +
95
- (permission.disabled ? " (premium feature)" : "")
96
- options.push({
97
- icon: "Visibility",
98
- value: FieldPermissions.READONLY,
99
- tooltip,
100
- disabled: permission.disabled || isRequired,
101
- })
102
- }
103
-
104
- if ((permission = permissionsObj[FieldPermissions.HIDDEN])) {
105
- const tooltip = requiredTooltips[FieldPermissions.HIDDEN] || "Hidden"
106
- options.push({
107
- icon: "VisibilityOff",
108
- value: FieldPermissions.HIDDEN,
109
- disabled: permission.disabled || isRequired,
110
- tooltip,
111
- })
112
- }
113
-
114
- return { ...c, options }
115
- })
116
-
117
- $: relationshipPanelColumns = Object.entries(
118
- relationshipField?.columns || {}
119
- ).map(([name, column]) => {
120
- return {
121
- name: name,
122
- label: name,
123
- schema: {
124
- type: column.type,
125
- subtype: column.subtype,
126
- visible: column.visible,
127
- readonly: column.readonly,
128
- icon: column.icon,
129
- },
130
- }
131
- })
132
-
133
- async function toggleColumn(column, permission) {
134
- const visible = permission !== FieldPermissions.HIDDEN
135
- const readonly = permission === FieldPermissions.READONLY
136
-
137
- if (!fromRelationshipField) {
138
- await datasource.actions.addSchemaMutation(column.name, {
139
- visible,
140
- readonly,
141
- })
142
- } else {
143
- await datasource.actions.addSubSchemaMutation(
144
- column.name,
145
- fromRelationshipField.name,
146
- {
147
- visible,
148
- readonly,
149
- }
150
- )
151
- }
152
- try {
153
- await datasource.actions.saveSchemaMutations()
154
- } catch (e) {
155
- notifications.error(e.message)
156
- } finally {
157
- await datasource.actions.resetSchemaMutations()
158
- await datasource.actions.refreshDefinition()
159
- }
160
- dispatch(visible ? "show-column" : "hide-column")
161
- }
162
-
163
- function columnToPermissionOptions(column) {
164
- if (column.schema.visible === false) {
165
- return FieldPermissions.HIDDEN
166
- }
167
-
168
- if (column.schema.readonly) {
169
- return FieldPermissions.READONLY
170
- }
171
-
172
- return FieldPermissions.WRITABLE
173
- }
174
- </script>
175
-
176
- <div class="content">
177
- <div class="columns">
178
- {#each displayColumns as column}
179
- <div class="column">
180
- <Icon size="S" name={getColumnIcon(column)} />
181
- <div class="column-label" title={column.label}>
182
- {column.label}
183
- </div>
184
- </div>
185
- <div class="column-options">
186
- <ToggleActionButtonGroup
187
- on:click={e => toggleColumn(column, e.detail)}
188
- value={columnToPermissionOptions(column)}
189
- options={column.options}
190
- />
191
- {#if canSetRelationshipSchemas && column.schema.type === FieldType.LINK && columnToPermissionOptions(column) !== FieldPermissions.HIDDEN}
192
- <div class="relationship-columns">
193
- <ActionButton
194
- on:click={e => {
195
- relationshipFieldName = column.name
196
- relationshipPanelAnchor = e.currentTarget
197
- }}
198
- size="S"
199
- icon="ChevronRight"
200
- quiet
201
- />
202
- </div>
203
- {/if}
204
- </div>
205
- {/each}
206
- </div>
207
- </div>
208
-
209
- {#if canSetRelationshipSchemas}
210
- <Popover
211
- on:close={() => (relationshipFieldName = null)}
212
- open={relationshipFieldName}
213
- anchor={relationshipPanelAnchor}
214
- align="left"
215
- >
216
- {#if relationshipPanelColumns.length}
217
- <div class="relationship-header">
218
- {relationshipFieldName} columns
219
- </div>
220
- {/if}
221
- <svelte:self
222
- columns={relationshipPanelColumns}
223
- permissions={[FieldPermissions.READONLY, FieldPermissions.HIDDEN]}
224
- fromRelationshipField={relationshipField}
225
- />
226
- </Popover>
227
- {/if}
228
-
229
- <style>
230
- .relationship-columns :global(.spectrum-ActionButton) {
231
- width: 28px;
232
- height: 28px;
233
- }
234
-
235
- .content {
236
- padding: 12px 12px;
237
- display: flex;
238
- flex-direction: column;
239
- gap: 12px;
240
- }
241
- .columns {
242
- display: grid;
243
- align-items: center;
244
- grid-template-columns: 1fr auto;
245
- grid-row-gap: 8px;
246
- grid-column-gap: 24px;
247
- }
248
- .columns :global(.spectrum-Switch) {
249
- margin-right: 0;
250
- }
251
- .column {
252
- display: flex;
253
- gap: 8px;
254
- }
255
- .column-label {
256
- min-width: 80px;
257
- max-width: 200px;
258
- text-overflow: ellipsis;
259
- white-space: nowrap;
260
- overflow: hidden;
261
- }
262
- .column-options {
263
- display: flex;
264
- gap: var(--spacing-xs);
265
- }
266
- .relationship-header {
267
- color: var(--spectrum-global-color-gray-600);
268
- padding: 12px 12px 0 12px;
269
- }
270
- </style>