@conduction/nextcloud-vue 2.148.0 → 2.149.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.
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +24 -7
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +12 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +2 -1
- package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js +23 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js +1 -1
- package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +34 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue.js +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue.js +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js +64 -8
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js.map +1 -1
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js +14 -4
- package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +26 -3
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +10 -2
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +84 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +61 -33
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +49 -2
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +90 -59
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js +3 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +10 -0
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +11 -0
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +28 -21
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +3 -15
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +123 -115
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +4 -0
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +2 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +2 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +677 -444
- package/dist/nextcloud-vue.cjs.js +1336 -942
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +677 -444
- package/l10n/en.json +2 -1
- package/l10n/nl.json +2 -1
- package/package.json +1 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +24 -7
- package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +13 -1
- package/src/components/CnChecklistRunWidget/CnChecklistRunWidget.vue +29 -2
- package/src/components/CnDataTable/CnDataTable.vue +34 -1
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +6 -1
- package/src/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue +1 -0
- package/src/components/CnDuplicateWarning/CnDuplicateWarning.vue +74 -10
- package/src/components/CnFactsWidget/CnFactsWidget.vue +35 -3
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +131 -3
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +103 -5
- package/src/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue +3 -1
- package/src/components/CnNotesCard/CnNotesCard.vue +10 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +16 -0
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +19 -19
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +4 -0
- package/src/css/dialog.css +17 -0
- package/src/css/look-board-detail.css +52 -3
- package/src/css/look-board-index.css +37 -1
- package/src/css/look-board.css +45 -5
- package/src/css/table.css +5 -2
|
@@ -165,13 +165,28 @@
|
|
|
165
165
|
</NcButton>
|
|
166
166
|
</div>
|
|
167
167
|
</div>
|
|
168
|
-
<ul v-else class="cn-field-list-widget__rows">
|
|
168
|
+
<ul v-else class="cn-field-list-widget__rows" :class="{ 'cn-field-list-widget__rows--options': isOptions }">
|
|
169
169
|
<li
|
|
170
170
|
v-for="row in rows"
|
|
171
171
|
:key="row.key"
|
|
172
172
|
class="cn-field-list-widget__row"
|
|
173
|
-
:
|
|
173
|
+
:draggable="canReorder ? 'true' : undefined"
|
|
174
|
+
:data-testid="`cn-field-list-row-${row.key}`"
|
|
175
|
+
@dragstart="dragFrom = row.index"
|
|
176
|
+
@dragover.prevent
|
|
177
|
+
@drop.prevent="dropOn(row.index)">
|
|
174
178
|
<div class="cn-field-list-widget__line">
|
|
179
|
+
<!-- `variant: "options"`: a grip that moves the option, by drag or with the arrow keys. -->
|
|
180
|
+
<button
|
|
181
|
+
v-if="canReorder"
|
|
182
|
+
type="button"
|
|
183
|
+
class="cn-field-list-widget__grip"
|
|
184
|
+
:aria-label="moveLabel(row)"
|
|
185
|
+
:data-testid="`cn-field-list-grip-${row.key}`"
|
|
186
|
+
@keydown.up.prevent="move(row.index, -1)"
|
|
187
|
+
@keydown.down.prevent="move(row.index, 1)">
|
|
188
|
+
<DragVertical :size="16" />
|
|
189
|
+
</button>
|
|
175
190
|
<span v-if="row.initials" class="cn-field-list-widget__avatar" aria-hidden="true">{{ row.initials }}</span>
|
|
176
191
|
<span class="cn-field-list-widget__main">
|
|
177
192
|
<a
|
|
@@ -187,6 +202,7 @@
|
|
|
187
202
|
:label="row.pill.label"
|
|
188
203
|
:variant="row.pill.variant"
|
|
189
204
|
size="small" />
|
|
205
|
+
<span v-if="row.code" class="cn-field-list-widget__code" :data-testid="`cn-field-list-code-${row.key}`">{{ row.code }}</span>
|
|
190
206
|
<span v-if="row.aside" class="cn-field-list-widget__aside">{{ row.aside }}</span>
|
|
191
207
|
<NcButton
|
|
192
208
|
v-for="action in row.actions"
|
|
@@ -307,7 +323,9 @@
|
|
|
307
323
|
</template>
|
|
308
324
|
|
|
309
325
|
<script>
|
|
326
|
+
import { translate as t } from '@nextcloud/l10n'
|
|
310
327
|
import { NcActionButton, NcActions, NcButton, NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextField } from '@nextcloud/vue'
|
|
328
|
+
import DragVertical from 'vue-material-design-icons/DragVertical.vue'
|
|
311
329
|
import CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'
|
|
312
330
|
import { isBadgeVariant } from '../../utils/badgeVariants.js'
|
|
313
331
|
import { formatBoardDate } from '../../utils/boardDate.js'
|
|
@@ -368,7 +386,7 @@ function rowHref(entry, spec) {
|
|
|
368
386
|
export default {
|
|
369
387
|
name: 'CnFieldListWidget',
|
|
370
388
|
|
|
371
|
-
components: { CnStatusBadge, NcActionButton, NcActions, NcButton, NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextField },
|
|
389
|
+
components: { CnStatusBadge, DragVertical, NcActionButton, NcActions, NcButton, NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextField },
|
|
372
390
|
|
|
373
391
|
inject: {
|
|
374
392
|
cnTranslate: { default: () => (key) => key },
|
|
@@ -388,6 +406,7 @@ export default {
|
|
|
388
406
|
* - `rowActions` — `[{ id, label, ariaLabel?, when?, placement?: 'band'|'inline', request: { method?, url, payload? } }]`, or `{ id, label, dialog, props }` to open a modal registered in the app registry with filled props (shown in `readOnly` too, since it writes nothing, and only when every token in `props` fills); tokens `@object.<field>`, `@objectId`, `@row.<field>`, `@index`. In the table variant `placement: 'inline'` draws the action as a button in the row instead of in the "..." menu; `ariaLabel` is a template filled from the row.
|
|
389
407
|
* - `when` (row actions, `detail`) — `{ field: value }`, every field equal; or per field `{ eq?, neq?, set? }`, where a value `@row.<field>` (or `@<field>`) is another field of the same row: `{ deliveredRef: { set: true, neq: '@originalRef' } }`.
|
|
390
408
|
* - `rowSource` — `{ url, path?, key }`: live per-row state merged by key.
|
|
409
|
+
* - `variant: 'options'` — the rows as framed options (a field's choice list): a grip that moves the option by drag or with the arrow keys and saves the order, and a code chip from `code` (`{ path }` on an object option, or `{ field }`, a map on the record from a plain option to its code).
|
|
391
410
|
* - `variant: 'table'` + `columns` — `[{ header, path, map?, format?, strong?, pill?, variantMap?, labelsFrom? }]` (a list value reads as its items joined; `labelsFrom` names an add field whose option labels word the values): rows as a table; a per-row "..." menu holds the row actions and remove; `detail` lines become a warning band under the table, with the row actions that have `placement: 'band'`.
|
|
392
411
|
* - `add.trigger: 'button'`, `add.placement: 'header' | 'title' | 'footer'` — the add form opens from a button; `title` reports the button for the card's title row on the `header` event.
|
|
393
412
|
* - `readOnly`, `hint`, `emptyText`.
|
|
@@ -436,6 +455,8 @@ export default {
|
|
|
436
455
|
return {
|
|
437
456
|
/** The list as last saved by this widget; null = read it off objectData. */
|
|
438
457
|
saved: null,
|
|
458
|
+
/** The place of the option being dragged, -1 while none is. */
|
|
459
|
+
dragFrom: -1,
|
|
439
460
|
/** Live per-row state from `rowSource`, by key. */
|
|
440
461
|
live: {},
|
|
441
462
|
draft: {},
|
|
@@ -500,10 +521,21 @@ export default {
|
|
|
500
521
|
copies: spec.detail && this.matches(entry, spec.detail.when) ? this.copiesOf(entry, spec.detail.copy) : [],
|
|
501
522
|
actions: this.actionsFor(entry, index),
|
|
502
523
|
cells: this.isTable ? this.cellsOf(entry) : [],
|
|
524
|
+
code: this.isOptions ? this.codeOf(item, entry) : '',
|
|
503
525
|
}
|
|
504
526
|
})
|
|
505
527
|
},
|
|
506
528
|
|
|
529
|
+
/** Whether the rows are drawn as framed options (`variant: 'options'`): a grip, the name, a code chip. */
|
|
530
|
+
isOptions() {
|
|
531
|
+
return this.content.variant === 'options'
|
|
532
|
+
},
|
|
533
|
+
|
|
534
|
+
/** Whether the options can be moved: the options look on a list that saves. */
|
|
535
|
+
canReorder() {
|
|
536
|
+
return this.isOptions && !this.readOnly && Boolean(this.content.field)
|
|
537
|
+
},
|
|
538
|
+
|
|
507
539
|
/** Whether the list is read-only. */
|
|
508
540
|
readOnly() {
|
|
509
541
|
return this.content.readOnly === true
|
|
@@ -1300,6 +1332,73 @@ export default {
|
|
|
1300
1332
|
* @param {object} row The row.
|
|
1301
1333
|
* @return {Promise<void>}
|
|
1302
1334
|
*/
|
|
1335
|
+
/**
|
|
1336
|
+
* An option's code chip: `content.code.path` on an object option, or the
|
|
1337
|
+
* value's entry in the record's map at `content.code.field` for a plain
|
|
1338
|
+
* one ("Woning" -> "WON"); '' for none.
|
|
1339
|
+
*
|
|
1340
|
+
* @param {unknown} item The stored option.
|
|
1341
|
+
* @param {object} entry The option as a row reads it.
|
|
1342
|
+
* @return {string}
|
|
1343
|
+
*/
|
|
1344
|
+
codeOf(item, entry) {
|
|
1345
|
+
const spec = this.content.code
|
|
1346
|
+
if (!spec || typeof spec !== 'object') {
|
|
1347
|
+
return ''
|
|
1348
|
+
}
|
|
1349
|
+
if (item && typeof item === 'object' && typeof spec.path === 'string') {
|
|
1350
|
+
return String(readPath(item, spec.path) ?? '')
|
|
1351
|
+
}
|
|
1352
|
+
const map = typeof spec.field === 'string' ? readPath(this.objectData || {}, spec.field) : null
|
|
1353
|
+
const code = map && typeof map === 'object' ? map[String(entry.value ?? item)] : ''
|
|
1354
|
+
return typeof code === 'string' ? code : ''
|
|
1355
|
+
},
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* The grip's accessible name.
|
|
1359
|
+
*
|
|
1360
|
+
* @param {object} row The row.
|
|
1361
|
+
* @return {string}
|
|
1362
|
+
*/
|
|
1363
|
+
moveLabel(row) {
|
|
1364
|
+
return t('nextcloud-vue', 'Move {item}, use the arrow keys', { item: row.title })
|
|
1365
|
+
},
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* Drop the dragged option on this one's place.
|
|
1369
|
+
*
|
|
1370
|
+
* @param {number} to The place it lands on.
|
|
1371
|
+
* @return {Promise<void>}
|
|
1372
|
+
*/
|
|
1373
|
+
async dropOn(to) {
|
|
1374
|
+
const from = this.dragFrom
|
|
1375
|
+
this.dragFrom = -1
|
|
1376
|
+
if (from < 0 || from === to) {
|
|
1377
|
+
return
|
|
1378
|
+
}
|
|
1379
|
+
await this.move(from, to - from)
|
|
1380
|
+
},
|
|
1381
|
+
|
|
1382
|
+
/**
|
|
1383
|
+
* Move an option by a number of places and save the list.
|
|
1384
|
+
*
|
|
1385
|
+
* @param {number} from Its place.
|
|
1386
|
+
* @param {number} by How far, negative is up.
|
|
1387
|
+
* @return {Promise<void>}
|
|
1388
|
+
*/
|
|
1389
|
+
async move(from, by) {
|
|
1390
|
+
const to = from + by
|
|
1391
|
+
if (!this.canReorder || to < 0 || to >= this.items.length) {
|
|
1392
|
+
return
|
|
1393
|
+
}
|
|
1394
|
+
await this.save((stored) => {
|
|
1395
|
+
const list = [...stored]
|
|
1396
|
+
const [moved] = list.splice(from, 1)
|
|
1397
|
+
list.splice(to, 0, moved)
|
|
1398
|
+
return list
|
|
1399
|
+
}, this.keyOf(this.items[from], from))
|
|
1400
|
+
},
|
|
1401
|
+
|
|
1303
1402
|
async remove(row) {
|
|
1304
1403
|
await this.save((stored) => stored.filter((item, index) => this.keyOf(item, index) !== row.key), row.key)
|
|
1305
1404
|
},
|
|
@@ -1409,6 +1508,35 @@ export default {
|
|
|
1409
1508
|
padding-top: 0;
|
|
1410
1509
|
}
|
|
1411
1510
|
|
|
1511
|
+
/* `variant: "options"` (DqZaaktypeVelden Keuzelijst): each option a framed
|
|
1512
|
+
row, 6px apart, with a grip before its name and its code in a chip. */
|
|
1513
|
+
.cn-field-list-widget__rows--options {
|
|
1514
|
+
gap: 6px;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
.cn-field-list-widget__rows--options .cn-field-list-widget__row,
|
|
1518
|
+
.cn-field-list-widget__rows--options .cn-field-list-widget__row:first-child {
|
|
1519
|
+
padding: 6px 12px;
|
|
1520
|
+
border: 1px solid var(--color-border);
|
|
1521
|
+
border-radius: var(--border-radius-element, 8px);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
.cn-field-list-widget__grip {
|
|
1525
|
+
flex: none;
|
|
1526
|
+
display: inline-flex;
|
|
1527
|
+
padding: 0;
|
|
1528
|
+
border: 0;
|
|
1529
|
+
background: transparent;
|
|
1530
|
+
color: var(--color-text-maxcontrast);
|
|
1531
|
+
cursor: grab;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
.cn-field-list-widget__code {
|
|
1535
|
+
flex: none;
|
|
1536
|
+
color: var(--color-text-maxcontrast);
|
|
1537
|
+
font-size: 13px;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1412
1540
|
.cn-field-list-widget__line {
|
|
1413
1541
|
display: flex;
|
|
1414
1542
|
align-items: center;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
- SPDX-License-Identifier: EUPL-1.2
|
|
4
4
|
-->
|
|
5
5
|
<template>
|
|
6
|
-
<div class="cn-flow-runs-widget">
|
|
6
|
+
<div class="cn-flow-runs-widget" :class="{ 'cn-flow-runs-widget--pills': pills }">
|
|
7
7
|
<!-- One quiet line on failure, never a leaked axios status string
|
|
8
8
|
(ADR-062). The real error goes to the console. -->
|
|
9
9
|
<p v-if="error" class="cn-flow-runs-widget__error">
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
{{ emptyLabel }}
|
|
27
27
|
</p>
|
|
28
28
|
<template v-else>
|
|
29
|
-
<p v-if="rows.length === 0" class="cn-flow-runs-widget__empty">
|
|
29
|
+
<p v-if="rows.length === 0 && content.quietLineWithHistory !== false" class="cn-flow-runs-widget__empty">
|
|
30
30
|
{{ emptyLabel }}
|
|
31
31
|
</p>
|
|
32
32
|
<ul v-else class="cn-flow-runs-widget__list">
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
:href="runHref(run) || undefined"
|
|
43
43
|
@click="onRowClick($event, run)">
|
|
44
44
|
<span
|
|
45
|
+
v-if="!pills"
|
|
45
46
|
class="cn-flow-runs-widget__dot"
|
|
46
47
|
:class="`cn-flow-runs-widget__dot--${run.status}`"
|
|
47
48
|
:title="statusLabel(run.status)" />
|
|
@@ -49,6 +50,12 @@
|
|
|
49
50
|
<span class="cn-flow-runs-widget__name">{{ run.flowName }}</span>
|
|
50
51
|
<span class="cn-flow-runs-widget__meta">{{ metaLine(run) }}</span>
|
|
51
52
|
</span>
|
|
53
|
+
<CnStatusBadge
|
|
54
|
+
v-if="pills"
|
|
55
|
+
class="cn-flow-runs-widget__pill"
|
|
56
|
+
:label="statusLabel(run.status)"
|
|
57
|
+
:variant="statusVariant(run.status)"
|
|
58
|
+
size="small" />
|
|
52
59
|
<span class="cn-flow-runs-widget__age">{{ ageLabel(run) }}</span>
|
|
53
60
|
</component>
|
|
54
61
|
</li>
|
|
@@ -62,7 +69,7 @@
|
|
|
62
69
|
labelled section with a hollow dot and a muted name, so live
|
|
63
70
|
and finished never rely on colour alone to tell apart. -->
|
|
64
71
|
<template v-if="showHistory">
|
|
65
|
-
<p class="cn-flow-runs-widget__history-title">
|
|
72
|
+
<p v-if="content.historyTitle !== false" class="cn-flow-runs-widget__history-title">
|
|
66
73
|
{{ tr('Earlier runs') }}
|
|
67
74
|
</p>
|
|
68
75
|
<p v-if="completedError" class="cn-flow-runs-widget__error">
|
|
@@ -81,6 +88,7 @@
|
|
|
81
88
|
:href="runHref(run) || undefined"
|
|
82
89
|
@click="onRowClick($event, run)">
|
|
83
90
|
<span
|
|
91
|
+
v-if="!pills"
|
|
84
92
|
class="cn-flow-runs-widget__dot cn-flow-runs-widget__dot--terminal"
|
|
85
93
|
:class="`cn-flow-runs-widget__dot--${run.status}`"
|
|
86
94
|
:title="statusLabel(run.status)" />
|
|
@@ -88,6 +96,12 @@
|
|
|
88
96
|
<span class="cn-flow-runs-widget__name">{{ run.flowName }}</span>
|
|
89
97
|
<span class="cn-flow-runs-widget__meta">{{ metaLine(run) }}</span>
|
|
90
98
|
</span>
|
|
99
|
+
<CnStatusBadge
|
|
100
|
+
v-if="pills"
|
|
101
|
+
class="cn-flow-runs-widget__pill"
|
|
102
|
+
:label="statusLabel(run.status)"
|
|
103
|
+
:variant="statusVariant(run.status)"
|
|
104
|
+
size="small" />
|
|
91
105
|
<span class="cn-flow-runs-widget__age">{{ ageLabel(run) }}</span>
|
|
92
106
|
</component>
|
|
93
107
|
</li>
|
|
@@ -106,9 +120,11 @@ import { NcLoadingIcon } from '@nextcloud/vue'
|
|
|
106
120
|
import { computed, inject, ref } from 'vue'
|
|
107
121
|
import { useEndpointSource } from '../../composables/useEndpointSource.js'
|
|
108
122
|
import { dispatchAction } from '../../utils/actionsDispatcher.js'
|
|
123
|
+
import { formatBoardDate } from '../../utils/boardDate.js'
|
|
109
124
|
import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'
|
|
110
125
|
import { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'
|
|
111
126
|
import { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js'
|
|
127
|
+
import { CnStatusBadge } from '../CnStatusBadge/index.js'
|
|
112
128
|
|
|
113
129
|
/**
|
|
114
130
|
* The OpenRegister endpoint that lists the caller's live flow runs.
|
|
@@ -197,6 +213,7 @@ export default {
|
|
|
197
213
|
name: 'CnFlowRunsWidget',
|
|
198
214
|
|
|
199
215
|
components: {
|
|
216
|
+
CnStatusBadge,
|
|
200
217
|
NcLoadingIcon,
|
|
201
218
|
},
|
|
202
219
|
|
|
@@ -231,6 +248,17 @@ export default {
|
|
|
231
248
|
* subject's finished runs render below it. Absent = today's org-wide
|
|
232
249
|
* widget, unchanged.
|
|
233
250
|
* - `emptyText` — override for the "nothing running" line.
|
|
251
|
+
* - `quietLineWithHistory` — `false` leaves out the "nothing running"
|
|
252
|
+
* line while the subject has finished runs to list.
|
|
253
|
+
* - `historyTitle` — `false` leaves out the "Earlier runs" heading.
|
|
254
|
+
* - `statusPill` — `true` shows the status as a pill on each row
|
|
255
|
+
* (no dot, and the meta line leaves the status out), rows ruled.
|
|
256
|
+
* - `statusLabels` — words per status (`{ completed: 'Succeeded' }`),
|
|
257
|
+
* translated, over the built-in ones.
|
|
258
|
+
* - `triggerLabels` — the meta line per trigger in words
|
|
259
|
+
* (`{ 'object.created': 'Started when the case was created' }`), translated.
|
|
260
|
+
* - `age` — `'datetime'` shows when the run started ("3 okt, 14:32")
|
|
261
|
+
* instead of how long ago ("13d").
|
|
234
262
|
* - `headerAction` — an action descriptor drawn in the card header
|
|
235
263
|
* (`{ label, icon?, ...action }`, "Flow uitvoeren"), reported through
|
|
236
264
|
* the `header` event and dispatched with the page's dispatcher; its
|
|
@@ -421,6 +449,11 @@ export default {
|
|
|
421
449
|
return this.tr('+{count} more').replace('{count}', String(this.hiddenCount))
|
|
422
450
|
},
|
|
423
451
|
|
|
452
|
+
/** Whether each row shows its status as a pill (`content.statusPill`). */
|
|
453
|
+
pills() {
|
|
454
|
+
return this.content.statusPill === true
|
|
455
|
+
},
|
|
456
|
+
|
|
424
457
|
/** The nothing-running line. */
|
|
425
458
|
emptyLabel() {
|
|
426
459
|
const override = this.content.emptyText
|
|
@@ -678,10 +711,29 @@ export default {
|
|
|
678
711
|
* @return {string} The label.
|
|
679
712
|
*/
|
|
680
713
|
statusLabel(status) {
|
|
681
|
-
const
|
|
714
|
+
const own = this.content.statusLabels && this.content.statusLabels[status]
|
|
715
|
+
const key = (typeof own === 'string' && own !== '') ? own : STATUS_LABELS[status]
|
|
682
716
|
return key ? this.tr(key) : String(status || '')
|
|
683
717
|
},
|
|
684
718
|
|
|
719
|
+
/**
|
|
720
|
+
* The pill tone of a status: finished well is success, failed is error,
|
|
721
|
+
* anything still going is info.
|
|
722
|
+
*
|
|
723
|
+
* @param {string} status The run status.
|
|
724
|
+
* @return {string} A CnStatusBadge variant.
|
|
725
|
+
* @spec openspec/changes/flow-runs-ruled-with-pills/specs/cn-flow-runs-widget/spec.md
|
|
726
|
+
*/
|
|
727
|
+
statusVariant(status) {
|
|
728
|
+
if (status === 'completed') {
|
|
729
|
+
return 'success'
|
|
730
|
+
}
|
|
731
|
+
if (status === 'failed' || status === 'dead_letter') {
|
|
732
|
+
return 'error'
|
|
733
|
+
}
|
|
734
|
+
return status === 'stopped' ? 'default' : 'info'
|
|
735
|
+
},
|
|
736
|
+
|
|
685
737
|
/**
|
|
686
738
|
* The secondary line: status, the step the run sits on, and what
|
|
687
739
|
* triggered it — whichever of those the run actually carries.
|
|
@@ -690,7 +742,11 @@ export default {
|
|
|
690
742
|
* @return {string} The meta line.
|
|
691
743
|
*/
|
|
692
744
|
metaLine(run) {
|
|
693
|
-
const
|
|
745
|
+
const words = this.content.triggerLabels && this.content.triggerLabels[run.trigger]
|
|
746
|
+
if (typeof words === 'string' && words !== '') {
|
|
747
|
+
return this.tr(words)
|
|
748
|
+
}
|
|
749
|
+
const parts = this.pills ? [] : [this.statusLabel(run.status)]
|
|
694
750
|
if (run.step) {
|
|
695
751
|
parts.push(String(run.step))
|
|
696
752
|
}
|
|
@@ -714,6 +770,11 @@ export default {
|
|
|
714
770
|
if (Number.isFinite(started) === false) {
|
|
715
771
|
return ''
|
|
716
772
|
}
|
|
773
|
+
if (this.content.age === 'datetime') {
|
|
774
|
+
const at = new Date(started)
|
|
775
|
+
const pad = (value) => String(value).padStart(2, '0')
|
|
776
|
+
return `${formatBoardDate(at)}, ${pad(at.getHours())}:${pad(at.getMinutes())}`
|
|
777
|
+
}
|
|
717
778
|
const seconds = Math.max(0, Math.round((Date.now() - started) / 1000))
|
|
718
779
|
if (seconds < 60) {
|
|
719
780
|
return this.tr('now')
|
|
@@ -965,6 +1026,43 @@ a.cn-flow-runs-widget__row-content:hover .cn-flow-runs-widget__name {
|
|
|
965
1026
|
letter-spacing: 0.04em;
|
|
966
1027
|
}
|
|
967
1028
|
|
|
1029
|
+
/* Status pills: each row ruled on top, the name over its meta line, the pill
|
|
1030
|
+
and the start moment at the end, as the Dq case boards draw the Flows card. */
|
|
1031
|
+
.cn-flow-runs-widget--pills .cn-flow-runs-widget__row {
|
|
1032
|
+
border-top: 1px solid var(--color-border);
|
|
1033
|
+
border-bottom: none;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.cn-flow-runs-widget--pills .cn-flow-runs-widget__row-content {
|
|
1037
|
+
flex-wrap: wrap;
|
|
1038
|
+
gap: 6px 16px;
|
|
1039
|
+
padding: 11px 0;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
.cn-flow-runs-widget--pills .cn-flow-runs-widget__body {
|
|
1043
|
+
flex: 1 1 260px;
|
|
1044
|
+
gap: 2px;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
.cn-flow-runs-widget--pills .cn-flow-runs-widget__name,
|
|
1048
|
+
.cn-flow-runs-widget--pills .cn-flow-runs-widget__row--terminal .cn-flow-runs-widget__name {
|
|
1049
|
+
font-size: 15px;
|
|
1050
|
+
font-weight: 500;
|
|
1051
|
+
color: var(--color-main-text);
|
|
1052
|
+
white-space: normal;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.cn-flow-runs-widget--pills .cn-flow-runs-widget__meta {
|
|
1056
|
+
font-size: 13px;
|
|
1057
|
+
white-space: normal;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.cn-flow-runs-widget--pills .cn-flow-runs-widget__age {
|
|
1061
|
+
flex: 0 0 104px;
|
|
1062
|
+
font-size: 13px;
|
|
1063
|
+
text-align: end;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
968
1066
|
@keyframes cn-flow-runs-pulse {
|
|
969
1067
|
0%, 100% { opacity: 1; }
|
|
970
1068
|
50% { opacity: 0.35; }
|
|
@@ -42,6 +42,8 @@ export default {
|
|
|
42
42
|
cnWidgetSelection: { from: WIDGET_SELECTION, default: null },
|
|
43
43
|
/** The host's translate (CnAppRoot provides `cnTranslate`), applied to the title before it is filled. */
|
|
44
44
|
cnTranslate: { default: () => (key) => key },
|
|
45
|
+
/** The app's named formatters (CnAppRoot provides `cnFormatters`), for a `{field|formatter}` token in the title. */
|
|
46
|
+
cnFormatters: { default: () => ({}) },
|
|
45
47
|
},
|
|
46
48
|
|
|
47
49
|
inheritAttrs: false,
|
|
@@ -93,7 +95,7 @@ export default {
|
|
|
93
95
|
return this.widget
|
|
94
96
|
}
|
|
95
97
|
const translated = this.cnTranslate(title)
|
|
96
|
-
return { ...this.widget, title: fillTemplate(translated, this.row) || translated.replace(/\s*\{[^}]*\}/g, '') }
|
|
98
|
+
return { ...this.widget, title: fillTemplate(translated, this.row, new Date(), { formatters: this.cnFormatters }) || translated.replace(/\s*\{[^}]*\}/g, '') }
|
|
97
99
|
},
|
|
98
100
|
},
|
|
99
101
|
}
|
|
@@ -176,6 +176,8 @@ import CnNoteComposer from '../CnNoteComposer/CnNoteComposer.vue'
|
|
|
176
176
|
import CnUserActionMenu from '../CnUserActionMenu/CnUserActionMenu.vue'
|
|
177
177
|
import CnVisibilityChip from '../CnVisibilityChip/CnVisibilityChip.vue'
|
|
178
178
|
import { useFileComments } from '../../composables/useFileComments.js'
|
|
179
|
+
import { normalizeLook } from '../../composables/useLook.js'
|
|
180
|
+
import { formatBoardDateTime } from '../../utils/fillTemplate.js'
|
|
179
181
|
import { buildHeaders, prefixUrl } from '../../utils/index.js'
|
|
180
182
|
import { initialsOf } from '../../utils/initials.js'
|
|
181
183
|
import { leafSourceUrl } from '../../utils/leafSourceUrl.js'
|
|
@@ -248,6 +250,10 @@ export default {
|
|
|
248
250
|
Delete,
|
|
249
251
|
},
|
|
250
252
|
|
|
253
|
+
inject: {
|
|
254
|
+
cnLook: { default: 'nextcloud' },
|
|
255
|
+
},
|
|
256
|
+
|
|
251
257
|
props: {
|
|
252
258
|
/** OpenRegister register ID */
|
|
253
259
|
registerId: {
|
|
@@ -795,6 +801,10 @@ export default {
|
|
|
795
801
|
if (!dateStr) {
|
|
796
802
|
return ''
|
|
797
803
|
}
|
|
804
|
+
// The board look writes a note's moment as the boards do: "6 okt 11:10", the year only outside this year.
|
|
805
|
+
if (normalizeLook(this.cnLook) === 'board') {
|
|
806
|
+
return formatBoardDateTime(dateStr) || dateStr
|
|
807
|
+
}
|
|
798
808
|
try {
|
|
799
809
|
return new Date(dateStr).toLocaleString(userLocale(), {
|
|
800
810
|
year: 'numeric',
|
|
@@ -112,6 +112,11 @@
|
|
|
112
112
|
:row="object" />
|
|
113
113
|
<template v-else>{{ recordFootCell.text }}</template>
|
|
114
114
|
</span>
|
|
115
|
+
<!-- An empty footerCell keeps its place as a dash, as an empty table cell. -->
|
|
116
|
+
<span
|
|
117
|
+
v-else-if="recordFootCellDeclared"
|
|
118
|
+
class="cn-object-card__record-foot-cell cn-object-card__record-foot-cell--empty"
|
|
119
|
+
data-testid="cn-object-card-foot-cell-empty">—</span>
|
|
115
120
|
<span
|
|
116
121
|
v-if="recordDate"
|
|
117
122
|
class="cn-object-card__record-date"
|
|
@@ -589,6 +594,17 @@ export default {
|
|
|
589
594
|
return { text: part.text, tone }
|
|
590
595
|
},
|
|
591
596
|
|
|
597
|
+
/**
|
|
598
|
+
* Whether the record layout names a `footerCell`, so an empty one
|
|
599
|
+
* keeps its place.
|
|
600
|
+
*
|
|
601
|
+
* @spec openspec/changes/card-empty-footer-cell-dash/specs/card-empty-footer-cell-dash/spec.md#requirement-an-empty-footer-cell-reads-as-a-dash
|
|
602
|
+
* @return {boolean}
|
|
603
|
+
*/
|
|
604
|
+
recordFootCellDeclared() {
|
|
605
|
+
return Boolean(this.recordLayout && this.recordLayout.footerCell)
|
|
606
|
+
},
|
|
607
|
+
|
|
592
608
|
/**
|
|
593
609
|
* The footer's `footerCell` part, read as a meta part is (through the
|
|
594
610
|
* page column it names), or null while it is empty.
|
|
@@ -860,7 +860,7 @@ export default {
|
|
|
860
860
|
// `secondary` (a second, muted line under the cell) rides
|
|
861
861
|
// along too: the table draws it, and dropping it here took the
|
|
862
862
|
// list rows' second line away (zuiddrecht-pixel-gaps-3).
|
|
863
|
-
for (const k of ['format', 'widget', 'widgetProps', 'formatter', 'align', 'width', 'type', 'enum', 'enumLabels', 'sortable', 'secondary', 'colorMap', 'grow', 'cellClass']) {
|
|
863
|
+
for (const k of ['format', 'widget', 'widgetProps', 'formatter', 'align', 'width', 'type', 'enum', 'enumLabels', 'sortable', 'secondary', 'colorMap', 'grow', 'cellClass', 'emptyValue']) {
|
|
864
864
|
if (c[k] !== undefined) {
|
|
865
865
|
out[k] = c[k]
|
|
866
866
|
}
|
|
@@ -61,7 +61,8 @@
|
|
|
61
61
|
:data-testid="`cn-record-list-sort-${col.key}`"
|
|
62
62
|
@click="toggleTableSort(col.key)">
|
|
63
63
|
{{ col.label }}
|
|
64
|
-
<
|
|
64
|
+
<ChevronUp v-if="sortStateOf(col.key) === 'ascending'" class="cn-record-list__sort-mark" :size="14" />
|
|
65
|
+
<ChevronDown v-else class="cn-record-list__sort-mark" :size="14" />
|
|
65
66
|
</button>
|
|
66
67
|
<template v-else>
|
|
67
68
|
{{ col.label }}
|
|
@@ -575,7 +576,9 @@ import { generateUrl } from '@nextcloud/router'
|
|
|
575
576
|
import { NcActionButton, NcActionCheckbox, NcActionLink, NcActions, NcButton, NcLoadingIcon } from '@nextcloud/vue'
|
|
576
577
|
import { inject, ref } from 'vue'
|
|
577
578
|
import Check from 'vue-material-design-icons/Check.vue'
|
|
579
|
+
import ChevronDown from 'vue-material-design-icons/ChevronDown.vue'
|
|
578
580
|
import ChevronRight from 'vue-material-design-icons/ChevronRight.vue'
|
|
581
|
+
import ChevronUp from 'vue-material-design-icons/ChevronUp.vue'
|
|
579
582
|
import FilterOutline from 'vue-material-design-icons/FilterOutline.vue'
|
|
580
583
|
import CnIcon from '../CnIcon/CnIcon.vue'
|
|
581
584
|
import CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'
|
|
@@ -672,7 +675,7 @@ function unwrap(value) {
|
|
|
672
675
|
export default {
|
|
673
676
|
name: 'CnRecordListWidget',
|
|
674
677
|
|
|
675
|
-
components: { Check, ChevronRight, CnIcon, CnRecordNoteRows, CnStatusBadge, FilterOutline, NcActionButton, NcActionCheckbox, NcActionLink, NcActions, NcButton, NcLoadingIcon },
|
|
678
|
+
components: { Check, ChevronDown, ChevronRight, ChevronUp, CnIcon, CnRecordNoteRows, CnStatusBadge, FilterOutline, NcActionButton, NcActionCheckbox, NcActionLink, NcActions, NcButton, NcLoadingIcon },
|
|
676
679
|
|
|
677
680
|
inject: {
|
|
678
681
|
/** Detail-page object context (`{ objectId, object, register, schema }`). */
|
|
@@ -2269,20 +2272,6 @@ export default {
|
|
|
2269
2272
|
return this.tableSort.key === key && this.tableSort.dir ? this.tableSort.dir : 'none'
|
|
2270
2273
|
},
|
|
2271
2274
|
|
|
2272
|
-
/**
|
|
2273
|
-
* The arrow after a sortable column's label.
|
|
2274
|
-
*
|
|
2275
|
-
* @param {string} key The column key.
|
|
2276
|
-
* @return {string} An up or down arrow, or '' while the column is not the sort.
|
|
2277
|
-
*/
|
|
2278
|
-
sortMarkOf(key) {
|
|
2279
|
-
const state = this.sortStateOf(key)
|
|
2280
|
-
if (state === 'ascending') {
|
|
2281
|
-
return '▲'
|
|
2282
|
-
}
|
|
2283
|
-
return state === 'descending' ? '▼' : ''
|
|
2284
|
-
},
|
|
2285
|
-
|
|
2286
2275
|
/**
|
|
2287
2276
|
* Sort the `table` by a column: ascending first, then descending.
|
|
2288
2277
|
*
|
|
@@ -3312,7 +3301,7 @@ export default {
|
|
|
3312
3301
|
}
|
|
3313
3302
|
|
|
3314
3303
|
.cn-record-list__sort-mark {
|
|
3315
|
-
|
|
3304
|
+
color: var(--color-text-maxcontrast);
|
|
3316
3305
|
}
|
|
3317
3306
|
|
|
3318
3307
|
.cn-record-list__head {
|
|
@@ -3321,8 +3310,14 @@ export default {
|
|
|
3321
3310
|
align-items: center;
|
|
3322
3311
|
}
|
|
3323
3312
|
|
|
3324
|
-
|
|
3313
|
+
/* The funnel is a 22px control, as the boards draw it beside a head, not
|
|
3314
|
+
NcActions' 34px trigger that made the head row 54px. */
|
|
3315
|
+
.cn-record-list__head-filter :deep(.button-vue) {
|
|
3325
3316
|
--button-size: 22px;
|
|
3317
|
+
width: 22px;
|
|
3318
|
+
min-width: 22px;
|
|
3319
|
+
height: 22px;
|
|
3320
|
+
min-height: 22px;
|
|
3326
3321
|
}
|
|
3327
3322
|
|
|
3328
3323
|
.cn-record-list__table .cn-record-list__cell--end {
|
|
@@ -3413,11 +3408,16 @@ export default {
|
|
|
3413
3408
|
font-weight: 600;
|
|
3414
3409
|
height: 34px;
|
|
3415
3410
|
justify-content: center;
|
|
3416
|
-
margin: 0;
|
|
3417
3411
|
padding: 0 14px;
|
|
3418
3412
|
text-decoration: none;
|
|
3419
3413
|
}
|
|
3420
3414
|
|
|
3415
|
+
/* server.css gives every button `margin: 3px 3px 3px 0` at (0,2,1); the
|
|
3416
|
+
doubled class outranks it. */
|
|
3417
|
+
.cn-record-list__action.cn-record-list__action {
|
|
3418
|
+
margin: 0;
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
3421
|
.cn-record-list__action:hover,
|
|
3422
3422
|
.cn-record-list__action:focus-visible {
|
|
3423
3423
|
background: var(--color-primary-element-light-hover, var(--color-primary-element-light));
|
|
@@ -1094,6 +1094,10 @@ export default {
|
|
|
1094
1094
|
const results = data.results || data
|
|
1095
1095
|
this.registers = Array.isArray(results) ? results : []
|
|
1096
1096
|
this.registersLoaded = true
|
|
1097
|
+
// A configuration that arrived while the registers were loading
|
|
1098
|
+
// skipped its schema read (the watcher waits for the registers),
|
|
1099
|
+
// so read the mapped registers' schemas now.
|
|
1100
|
+
this.mappedRegisterIds().forEach((id) => this.loadSchemasForRegister(id))
|
|
1097
1101
|
} catch (error) {
|
|
1098
1102
|
this.registersError = error.message || t('nextcloud-vue', 'The registers could not be loaded: {reason}', { reason: t('nextcloud-vue', 'no connection') })
|
|
1099
1103
|
} finally {
|
package/src/css/dialog.css
CHANGED
|
@@ -595,3 +595,20 @@ body:has(.cn-look-board):not(:has(.cn-look-nextcloud)) .modal-mask {
|
|
|
595
595
|
max-height: calc(100% - var(--cn-dialog-top, 88px) - 24px);
|
|
596
596
|
}
|
|
597
597
|
}
|
|
598
|
+
|
|
599
|
+
/* The chosen option's fields start 12px under its description, the label on
|
|
600
|
+
the normal line, as DqVolgendeStap draws "Opschorten": the row's 12px
|
|
601
|
+
bottom padding plus the cell's 8px gap and a 21px label line put them
|
|
602
|
+
11.6px lower (r31).
|
|
603
|
+
@spec openspec/changes/board-choice-card-fields-under-the-text/specs/dialog/spec.md */
|
|
604
|
+
.cn-dialog-board .cn-choice-cards .cn-choice-cards__cell--with-details {
|
|
605
|
+
gap: 12px;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.cn-dialog-board .cn-choice-cards .cn-choice-cards__cell--with-details .cn-choice-cards__row {
|
|
609
|
+
padding-bottom: 0;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.cn-dialog-board .cn-transition-input-fields .cn-transition-input-fields__label {
|
|
613
|
+
line-height: normal;
|
|
614
|
+
}
|