@conduction/nextcloud-vue 2.86.0 → 2.87.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/CnIndexPage/CnIndexPage.vue2.js +2 -0
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +36 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +55 -40
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +3 -26
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +74 -53
- package/dist/esm/utils/boardReferenceColumns.js +63 -4
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -1
- package/dist/esm/utils/contentHeaderLink.js +48 -1
- package/dist/esm/utils/contentHeaderLink.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +255 -121
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +74 -53
- package/package.json +1 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +2 -0
- package/src/components/CnTabsWidget/CnTabsWidget.vue +71 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +3 -26
- package/src/schemas/app-manifest-v2.schema.json +3 -1
- package/src/utils/boardReferenceColumns.js +62 -3
- package/src/utils/contentHeaderLink.js +47 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -21010,7 +21010,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21010
21010
|
}
|
|
21011
21011
|
|
|
21012
21012
|
|
|
21013
|
-
.cn-widget-wrapper[data-v-
|
|
21013
|
+
.cn-widget-wrapper[data-v-4f6c55f6] {
|
|
21014
21014
|
position: relative;
|
|
21015
21015
|
height: 100%;
|
|
21016
21016
|
display: flex;
|
|
@@ -21024,13 +21024,13 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21024
21024
|
}
|
|
21025
21025
|
|
|
21026
21026
|
/* Headerless date chip — floated over the top-right of a flush card. */
|
|
21027
|
-
.cn-widget-wrapper__floating-meta[data-v-
|
|
21027
|
+
.cn-widget-wrapper__floating-meta[data-v-4f6c55f6] {
|
|
21028
21028
|
position: absolute;
|
|
21029
21029
|
top: 8px;
|
|
21030
21030
|
inset-inline-end: 10px;
|
|
21031
21031
|
z-index: 2;
|
|
21032
21032
|
}
|
|
21033
|
-
.cn-widget-wrapper__content[data-v-
|
|
21033
|
+
.cn-widget-wrapper__content[data-v-4f6c55f6] {
|
|
21034
21034
|
flex: 1;
|
|
21035
21035
|
overflow: auto;
|
|
21036
21036
|
min-height: 0;
|
|
@@ -21046,24 +21046,24 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21046
21046
|
So it is structural instead. `:has()` keys on the table component's own root
|
|
21047
21047
|
class, which means a table is flush by construction and no caller can
|
|
21048
21048
|
reintroduce the gap by forgetting a prop. */
|
|
21049
|
-
.cn-widget-wrapper__content[data-v-
|
|
21050
|
-
.cn-widget-wrapper__content[data-v-
|
|
21049
|
+
.cn-widget-wrapper__content[data-v-4f6c55f6]:has(> .cn-table-container),
|
|
21050
|
+
.cn-widget-wrapper__content[data-v-4f6c55f6]:has(> .cn-widget-object-table) {
|
|
21051
21051
|
padding: 0;
|
|
21052
21052
|
}
|
|
21053
21053
|
|
|
21054
21054
|
/* Keyboard focus ring for the now-focusable scrollable content region. */
|
|
21055
|
-
.cn-widget-wrapper__content[data-v-
|
|
21055
|
+
.cn-widget-wrapper__content[data-v-4f6c55f6]:focus-visible {
|
|
21056
21056
|
outline: 2px solid var(--color-primary-element);
|
|
21057
21057
|
outline-offset: -2px;
|
|
21058
21058
|
}
|
|
21059
|
-
.cn-widget-wrapper--borderless[data-v-
|
|
21059
|
+
.cn-widget-wrapper--borderless[data-v-4f6c55f6] {
|
|
21060
21060
|
border: none;
|
|
21061
21061
|
background: transparent;
|
|
21062
21062
|
}
|
|
21063
|
-
.cn-widget-wrapper--borderless .cn-widget-wrapper__content[data-v-
|
|
21063
|
+
.cn-widget-wrapper--borderless .cn-widget-wrapper__content[data-v-4f6c55f6] {
|
|
21064
21064
|
padding: 0;
|
|
21065
21065
|
}
|
|
21066
|
-
.cn-widget-wrapper--flush .cn-widget-wrapper__content[data-v-
|
|
21066
|
+
.cn-widget-wrapper--flush .cn-widget-wrapper__content[data-v-4f6c55f6] {
|
|
21067
21067
|
padding: 0;
|
|
21068
21068
|
}
|
|
21069
21069
|
|
|
@@ -21071,8 +21071,8 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21071
21071
|
above. A dashboard renders every widget `flush`, and without this their
|
|
21072
21072
|
fields touch the card's edges. Borderless and chromeless cards, and the
|
|
21073
21073
|
Nextcloud dashboard variant, keep their own padding. */
|
|
21074
|
-
.cn-widget-wrapper--flush:not(.cn-widget-wrapper--borderless, .cn-widget-wrapper--nc-dashboard) > .cn-widget-wrapper__content[data-v-
|
|
21075
|
-
.cn-widget-wrapper--flush:not(.cn-widget-wrapper--borderless, .cn-widget-wrapper--nc-dashboard) > .cn-widget-wrapper__content[data-v-
|
|
21074
|
+
.cn-widget-wrapper--flush:not(.cn-widget-wrapper--borderless, .cn-widget-wrapper--nc-dashboard) > .cn-widget-wrapper__content[data-v-4f6c55f6]:has(> .cn-form-widget),
|
|
21075
|
+
.cn-widget-wrapper--flush:not(.cn-widget-wrapper--borderless, .cn-widget-wrapper--nc-dashboard) > .cn-widget-wrapper__content[data-v-4f6c55f6]:has(> .cn-kb-search-widget) {
|
|
21076
21076
|
padding: 16px;
|
|
21077
21077
|
}
|
|
21078
21078
|
|
|
@@ -21083,7 +21083,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21083
21083
|
a square panel, which is the last visible piece of a card that is supposed
|
|
21084
21084
|
to be absent. `CnDetailCard.cn-detail-card--chromeless` zeroes the same
|
|
21085
21085
|
thing for the same reason. */
|
|
21086
|
-
.cn-widget-wrapper--chromeless[data-v-
|
|
21086
|
+
.cn-widget-wrapper--chromeless[data-v-4f6c55f6] {
|
|
21087
21087
|
border-radius: 0;
|
|
21088
21088
|
}
|
|
21089
21089
|
|
|
@@ -21095,7 +21095,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21095
21095
|
* so users can override any token. Combined selector raises specificity above
|
|
21096
21096
|
* the base `.cn-widget-wrapper` rules it supersedes.
|
|
21097
21097
|
*/
|
|
21098
|
-
.cn-widget-wrapper__header[data-v-
|
|
21098
|
+
.cn-widget-wrapper__header[data-v-4f6c55f6] {
|
|
21099
21099
|
display: flex;
|
|
21100
21100
|
align-items: center;
|
|
21101
21101
|
justify-content: space-between;
|
|
@@ -21111,7 +21111,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21111
21111
|
/* Actions with no title beside them. `header-left` is not rendered at all in
|
|
21112
21112
|
this mode, and the header is `space-between`, so a single child would sit
|
|
21113
21113
|
flush LEFT where every other surface puts its actions on the right. */
|
|
21114
|
-
.cn-widget-wrapper__header--actions-only[data-v-
|
|
21114
|
+
.cn-widget-wrapper__header--actions-only[data-v-4f6c55f6] {
|
|
21115
21115
|
justify-content: flex-end;
|
|
21116
21116
|
}
|
|
21117
21117
|
|
|
@@ -21127,11 +21127,11 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21127
21127
|
no-descending-specificity asks for. The cascade did not need it (this
|
|
21128
21128
|
selector is more specific either way), a reader does: an override written
|
|
21129
21129
|
above the thing it overrides has to be read twice. */
|
|
21130
|
-
.cn-widget-wrapper--chromeless .cn-widget-wrapper__header[data-v-
|
|
21130
|
+
.cn-widget-wrapper--chromeless .cn-widget-wrapper__header[data-v-4f6c55f6] {
|
|
21131
21131
|
border-bottom: none;
|
|
21132
21132
|
padding-inline: 0;
|
|
21133
21133
|
}
|
|
21134
|
-
.cn-widget-wrapper__header-left[data-v-
|
|
21134
|
+
.cn-widget-wrapper__header-left[data-v-4f6c55f6] {
|
|
21135
21135
|
display: flex;
|
|
21136
21136
|
align-items: center;
|
|
21137
21137
|
gap: 8px;
|
|
@@ -21140,19 +21140,19 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21140
21140
|
of centering between icon and actions (header is space-between). */
|
|
21141
21141
|
flex: 1 1 auto;
|
|
21142
21142
|
}
|
|
21143
|
-
.cn-widget-wrapper__icon[data-v-
|
|
21143
|
+
.cn-widget-wrapper__icon[data-v-4f6c55f6] {
|
|
21144
21144
|
width: 24px;
|
|
21145
21145
|
height: 24px;
|
|
21146
21146
|
flex-shrink: 0;
|
|
21147
21147
|
color: var(--cn-widget-icon-color, var(--color-primary-element));
|
|
21148
21148
|
}
|
|
21149
|
-
.cn-widget-wrapper__title-stack[data-v-
|
|
21149
|
+
.cn-widget-wrapper__title-stack[data-v-4f6c55f6] {
|
|
21150
21150
|
display: flex;
|
|
21151
21151
|
flex-direction: column;
|
|
21152
21152
|
gap: 2px;
|
|
21153
21153
|
min-width: 0;
|
|
21154
21154
|
}
|
|
21155
|
-
.cn-widget-wrapper__eyebrow[data-v-
|
|
21155
|
+
.cn-widget-wrapper__eyebrow[data-v-4f6c55f6] {
|
|
21156
21156
|
font-size: 13px;
|
|
21157
21157
|
line-height: 1.3;
|
|
21158
21158
|
color: var(--color-text-maxcontrast);
|
|
@@ -21160,7 +21160,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21160
21160
|
overflow: hidden;
|
|
21161
21161
|
text-overflow: ellipsis;
|
|
21162
21162
|
}
|
|
21163
|
-
.cn-widget-wrapper__title[data-v-
|
|
21163
|
+
.cn-widget-wrapper__title[data-v-4f6c55f6] {
|
|
21164
21164
|
font-weight: 600;
|
|
21165
21165
|
font-size: 14px;
|
|
21166
21166
|
margin: 0;
|
|
@@ -21168,34 +21168,34 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21168
21168
|
overflow: hidden;
|
|
21169
21169
|
text-overflow: ellipsis;
|
|
21170
21170
|
}
|
|
21171
|
-
.cn-widget-wrapper.cn-widget-wrapper--nc-dashboard[data-v-
|
|
21171
|
+
.cn-widget-wrapper.cn-widget-wrapper--nc-dashboard[data-v-4f6c55f6] {
|
|
21172
21172
|
background: var(--color-main-background-blur, var(--color-main-background));
|
|
21173
21173
|
-webkit-backdrop-filter: var(--filter-background-blur, none);
|
|
21174
21174
|
backdrop-filter: var(--filter-background-blur, none);
|
|
21175
21175
|
border: none;
|
|
21176
21176
|
border-radius: var(--border-radius-container-large, 16px);
|
|
21177
21177
|
}
|
|
21178
|
-
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__header[data-v-
|
|
21178
|
+
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__header[data-v-4f6c55f6] {
|
|
21179
21179
|
padding: 16px;
|
|
21180
21180
|
border-bottom: none;
|
|
21181
21181
|
}
|
|
21182
|
-
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__header-left[data-v-
|
|
21182
|
+
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__header-left[data-v-4f6c55f6] {
|
|
21183
21183
|
gap: 16px;
|
|
21184
21184
|
}
|
|
21185
|
-
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__icon[data-v-
|
|
21185
|
+
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__icon[data-v-4f6c55f6] {
|
|
21186
21186
|
width: 32px;
|
|
21187
21187
|
height: 32px;
|
|
21188
21188
|
background-size: 32px;
|
|
21189
21189
|
}
|
|
21190
|
-
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__title[data-v-
|
|
21190
|
+
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__title[data-v-4f6c55f6] {
|
|
21191
21191
|
font-size: 20px;
|
|
21192
21192
|
font-weight: 700;
|
|
21193
21193
|
line-height: 24px;
|
|
21194
21194
|
}
|
|
21195
|
-
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__content[data-v-
|
|
21195
|
+
.cn-widget-wrapper--nc-dashboard .cn-widget-wrapper__content[data-v-4f6c55f6] {
|
|
21196
21196
|
padding: 0 16px 16px;
|
|
21197
21197
|
}
|
|
21198
|
-
.cn-widget-wrapper__title-meta[data-v-
|
|
21198
|
+
.cn-widget-wrapper__title-meta[data-v-4f6c55f6] {
|
|
21199
21199
|
display: flex;
|
|
21200
21200
|
align-items: center;
|
|
21201
21201
|
gap: 4px;
|
|
@@ -21204,7 +21204,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21204
21204
|
white-space: nowrap;
|
|
21205
21205
|
flex-shrink: 0;
|
|
21206
21206
|
}
|
|
21207
|
-
.cn-widget-wrapper__actions[data-v-
|
|
21207
|
+
.cn-widget-wrapper__actions[data-v-4f6c55f6] {
|
|
21208
21208
|
display: flex;
|
|
21209
21209
|
gap: 4px;
|
|
21210
21210
|
flex-shrink: 0;
|
|
@@ -21212,7 +21212,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21212
21212
|
|
|
21213
21213
|
/* The header's text link (`headerLink`). Theme hooks: --cn-widget-header-link-size
|
|
21214
21214
|
and --cn-widget-header-link-weight. */
|
|
21215
|
-
.cn-widget-wrapper__header-link[data-v-
|
|
21215
|
+
.cn-widget-wrapper__header-link[data-v-4f6c55f6] {
|
|
21216
21216
|
align-self: center;
|
|
21217
21217
|
padding: 0 calc(1 * var(--default-grid-baseline));
|
|
21218
21218
|
color: var(--color-primary-element);
|
|
@@ -21221,11 +21221,11 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21221
21221
|
text-decoration: none;
|
|
21222
21222
|
white-space: nowrap;
|
|
21223
21223
|
}
|
|
21224
|
-
.cn-widget-wrapper__header-link[data-v-
|
|
21225
|
-
.cn-widget-wrapper__header-link[data-v-
|
|
21224
|
+
.cn-widget-wrapper__header-link[data-v-4f6c55f6]:hover,
|
|
21225
|
+
.cn-widget-wrapper__header-link[data-v-4f6c55f6]:focus-visible {
|
|
21226
21226
|
text-decoration: underline;
|
|
21227
21227
|
}
|
|
21228
|
-
.cn-widget-wrapper__header-link[data-v-
|
|
21228
|
+
.cn-widget-wrapper__header-link[data-v-4f6c55f6]:focus-visible {
|
|
21229
21229
|
outline: 2px solid var(--color-primary-element);
|
|
21230
21230
|
outline-offset: 2px;
|
|
21231
21231
|
border-radius: var(--border-radius-small, 4px);
|
|
@@ -21236,7 +21236,7 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21236
21236
|
wrapper is ever rendered without it. Material-design-icon components paint
|
|
21237
21237
|
with `fill: currentColor`, so this reaches them; the :deep rule below makes
|
|
21238
21238
|
it reach a raw <svg> in the slot too. */
|
|
21239
|
-
.cn-widget-wrapper__title-icon[data-v-
|
|
21239
|
+
.cn-widget-wrapper__title-icon[data-v-4f6c55f6] {
|
|
21240
21240
|
display: flex;
|
|
21241
21241
|
align-items: center;
|
|
21242
21242
|
flex-shrink: 0;
|
|
@@ -21256,17 +21256,17 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21256
21256
|
|
|
21257
21257
|
/* Right-positioned title icons sit AFTER the actions, so the margin belongs on
|
|
21258
21258
|
the other side or it pushes the icon off the header's right edge. */
|
|
21259
|
-
.cn-widget-wrapper__title-icon[data-v-
|
|
21259
|
+
.cn-widget-wrapper__title-icon[data-v-4f6c55f6]:last-child {
|
|
21260
21260
|
margin-inline-end: 0;
|
|
21261
21261
|
margin-inline-start: 8px;
|
|
21262
21262
|
}
|
|
21263
21263
|
|
|
21264
21264
|
/* Material-design-icon components paint with `fill: currentColor`, so the
|
|
21265
21265
|
colour above reaches them; this makes it reach a raw <svg> in the slot too. */
|
|
21266
|
-
.cn-widget-wrapper__title-icon[data-v-
|
|
21266
|
+
.cn-widget-wrapper__title-icon[data-v-4f6c55f6] svg {
|
|
21267
21267
|
fill: currentcolor;
|
|
21268
21268
|
}
|
|
21269
|
-
.cn-widget-wrapper__footer[data-v-
|
|
21269
|
+
.cn-widget-wrapper__footer[data-v-4f6c55f6] {
|
|
21270
21270
|
display: flex;
|
|
21271
21271
|
justify-content: flex-end;
|
|
21272
21272
|
gap: 8px;
|
|
@@ -21274,12 +21274,12 @@ a.cn-xwiki-card__title[data-v-1a6b61fd]:hover {
|
|
|
21274
21274
|
border-top: 1px solid var(--color-border);
|
|
21275
21275
|
flex-shrink: 0;
|
|
21276
21276
|
}
|
|
21277
|
-
.cn-widget-wrapper__footer-link[data-v-
|
|
21277
|
+
.cn-widget-wrapper__footer-link[data-v-4f6c55f6] {
|
|
21278
21278
|
font-size: 13px;
|
|
21279
21279
|
color: var(--color-primary-element);
|
|
21280
21280
|
text-decoration: none;
|
|
21281
21281
|
}
|
|
21282
|
-
.cn-widget-wrapper__footer-link[data-v-
|
|
21282
|
+
.cn-widget-wrapper__footer-link[data-v-4f6c55f6]:hover {
|
|
21283
21283
|
text-decoration: underline;
|
|
21284
21284
|
}
|
|
21285
21285
|
|
|
@@ -25328,7 +25328,7 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25328
25328
|
|
|
25329
25329
|
|
|
25330
25330
|
/* A stack (`widgetIds`): the panel's widget, then cards 20px apart. */
|
|
25331
|
-
.cn-tabs-widget__stack[data-v-
|
|
25331
|
+
.cn-tabs-widget__stack[data-v-4294c502] {
|
|
25332
25332
|
display: flex;
|
|
25333
25333
|
flex-direction: column;
|
|
25334
25334
|
gap: 20px;
|
|
@@ -25337,19 +25337,19 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25337
25337
|
/* A gridded stack (`columns` / `layout` on the tab): 12 columns, widgets wrap
|
|
25338
25338
|
onto the next row, a row's cards as tall as the tallest. Narrow, it is the
|
|
25339
25339
|
plain stack again. */
|
|
25340
|
-
.cn-tabs-widget__stack--grid[data-v-
|
|
25340
|
+
.cn-tabs-widget__stack--grid[data-v-4294c502] {
|
|
25341
25341
|
display: grid;
|
|
25342
25342
|
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
25343
25343
|
align-items: stretch;
|
|
25344
25344
|
}
|
|
25345
|
-
.cn-tabs-widget__stack--grid[data-v-
|
|
25345
|
+
.cn-tabs-widget__stack--grid[data-v-4294c502] > * {
|
|
25346
25346
|
min-width: 0;
|
|
25347
25347
|
}
|
|
25348
25348
|
@media (max-width: 700px) {
|
|
25349
|
-
.cn-tabs-widget__stack--grid[data-v-
|
|
25349
|
+
.cn-tabs-widget__stack--grid[data-v-4294c502] {
|
|
25350
25350
|
grid-template-columns: minmax(0, 1fr);
|
|
25351
25351
|
}
|
|
25352
|
-
.cn-tabs-widget__stack--grid[data-v-
|
|
25352
|
+
.cn-tabs-widget__stack--grid[data-v-4294c502] > * {
|
|
25353
25353
|
grid-column: auto !important;
|
|
25354
25354
|
}
|
|
25355
25355
|
}
|
|
@@ -25383,7 +25383,7 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25383
25383
|
`!important` or on load order this library does not control. The same
|
|
25384
25384
|
technique, for the same reason, is used on `.cn-tabs__nav .cn-tabs__nav-item`
|
|
25385
25385
|
in CnTabs to beat Nextcloud's own button margin. */
|
|
25386
|
-
.cn-tabs-widget.cn-tabs-widget[data-v-
|
|
25386
|
+
.cn-tabs-widget.cn-tabs-widget[data-v-4294c502] {
|
|
25387
25387
|
background-color: transparent;
|
|
25388
25388
|
border: 0;
|
|
25389
25389
|
border-radius: 0;
|
|
@@ -25407,12 +25407,12 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25407
25407
|
below it: the rule ran straight on to the widget's edge and read as a
|
|
25408
25408
|
border sticking out past a rounded corner (Ruben, 2026-09-13). Ending it
|
|
25409
25409
|
where the curve begins makes the rule and the curve one continuous edge. */
|
|
25410
|
-
.cn-tabs-widget__tabs[data-v-
|
|
25410
|
+
.cn-tabs-widget__tabs[data-v-4294c502] .cn-tabs__bar {
|
|
25411
25411
|
border-bottom: none;
|
|
25412
25412
|
padding: 0;
|
|
25413
25413
|
position: relative;
|
|
25414
25414
|
}
|
|
25415
|
-
.cn-tabs-widget__tabs[data-v-
|
|
25415
|
+
.cn-tabs-widget__tabs[data-v-4294c502] .cn-tabs__bar::after {
|
|
25416
25416
|
border-bottom: 1px solid var(--color-border);
|
|
25417
25417
|
content: '';
|
|
25418
25418
|
inset-block-end: 0;
|
|
@@ -25425,11 +25425,11 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25425
25425
|
own background-coloured bottom edge, which only works if it paints ABOVE the
|
|
25426
25426
|
pseudo-element: a positioned pseudo-element otherwise paints over every
|
|
25427
25427
|
in-flow sibling, rule included. */
|
|
25428
|
-
.cn-tabs-widget__tabs[data-v-
|
|
25428
|
+
.cn-tabs-widget__tabs[data-v-4294c502] .cn-tabs__nav-item--active {
|
|
25429
25429
|
position: relative;
|
|
25430
25430
|
z-index: 1;
|
|
25431
25431
|
}
|
|
25432
|
-
.cn-tabs-widget__tabs[data-v-
|
|
25432
|
+
.cn-tabs-widget__tabs[data-v-4294c502] {
|
|
25433
25433
|
display: flex;
|
|
25434
25434
|
flex-direction: column;
|
|
25435
25435
|
/* Grow to the widget's height, so the panel fills the grid cell the
|
|
@@ -25447,7 +25447,7 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25447
25447
|
the open tab, but padding sits inside the painted box — only a margin would
|
|
25448
25448
|
have opened that gap, and a zero top put every panel's content against the
|
|
25449
25449
|
strip. */
|
|
25450
|
-
.cn-tabs-widget__tabs[data-v-
|
|
25450
|
+
.cn-tabs-widget__tabs[data-v-4294c502] .cn-tabs__content {
|
|
25451
25451
|
background-color: var(--color-main-background);
|
|
25452
25452
|
/* Three sides only: the bar's rule (redrawn above, stopping at the corner)
|
|
25453
25453
|
is this sheet's top edge, and the open tab erases the slice of it
|
|
@@ -25467,7 +25467,7 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25467
25467
|
overflow: auto;
|
|
25468
25468
|
padding: 12px;
|
|
25469
25469
|
}
|
|
25470
|
-
.cn-tabs-widget__tabs[data-v-
|
|
25470
|
+
.cn-tabs-widget__tabs[data-v-4294c502] .cn-tab {
|
|
25471
25471
|
height: 100%;
|
|
25472
25472
|
}
|
|
25473
25473
|
|
|
@@ -25475,15 +25475,36 @@ button.cn-stepper__step[data-v-776581d4] {
|
|
|
25475
25475
|
(margin 0 -16px -16px). The panel of a tab pads 12px, so on a tab that
|
|
25476
25476
|
holds the list directly the footer stuck out 4px on the right and at the
|
|
25477
25477
|
bottom and made the panel scroll. It bleeds exactly the panel's padding. */
|
|
25478
|
-
.cn-tabs-widget__tabs[data-v-
|
|
25478
|
+
.cn-tabs-widget__tabs[data-v-4294c502] .cn-tabs__content > .cn-tab > .cn-detail-widget-host--bare .cn-object-list-widget__add {
|
|
25479
25479
|
margin: auto -12px -12px;
|
|
25480
25480
|
}
|
|
25481
|
-
|
|
25481
|
+
|
|
25482
|
+
/* The open panel's header link, beside the strip. Same look and theme hooks
|
|
25483
|
+
as a card header link (CnWidgetWrapper). */
|
|
25484
|
+
.cn-tabs-widget__header-link[data-v-4294c502] {
|
|
25485
|
+
align-self: center;
|
|
25486
|
+
padding: 0 calc(1 * var(--default-grid-baseline));
|
|
25487
|
+
color: var(--color-primary-element);
|
|
25488
|
+
font-size: var(--cn-widget-header-link-size, 14px);
|
|
25489
|
+
font-weight: var(--cn-widget-header-link-weight, 600);
|
|
25490
|
+
text-decoration: none;
|
|
25491
|
+
white-space: nowrap;
|
|
25492
|
+
}
|
|
25493
|
+
.cn-tabs-widget__header-link[data-v-4294c502]:hover,
|
|
25494
|
+
.cn-tabs-widget__header-link[data-v-4294c502]:focus-visible {
|
|
25495
|
+
text-decoration: underline;
|
|
25496
|
+
}
|
|
25497
|
+
.cn-tabs-widget__header-link[data-v-4294c502]:focus-visible {
|
|
25498
|
+
outline: 2px solid var(--color-primary-element);
|
|
25499
|
+
outline-offset: 2px;
|
|
25500
|
+
border-radius: var(--border-radius-small, 4px);
|
|
25501
|
+
}
|
|
25502
|
+
.cn-tabs-widget__title[data-v-4294c502] {
|
|
25482
25503
|
align-items: center;
|
|
25483
25504
|
display: inline-flex;
|
|
25484
25505
|
gap: 6px;
|
|
25485
25506
|
}
|
|
25486
|
-
.cn-tabs-widget__title-icon[data-v-
|
|
25507
|
+
.cn-tabs-widget__title-icon[data-v-4294c502] {
|
|
25487
25508
|
flex: 0 0 auto;
|
|
25488
25509
|
}
|
|
25489
25510
|
|
|
@@ -128,6 +128,11 @@ function referenceTargetOf(source, { register = '', property = null } = {}) {
|
|
|
128
128
|
* @param {string} [options.narrowValue] The parent the board is narrowed to, '' for all.
|
|
129
129
|
* @param {string} [options.capacityField] The numeric row field that holds a column's limit.
|
|
130
130
|
* A column merged from two or more rows shows none: each row has its own limit.
|
|
131
|
+
* @param {string} [options.neutralColor] The colour a row holds when nobody chose one. A merged
|
|
132
|
+
* column then takes its first row colour that is not this one, and this one only when no row
|
|
133
|
+
* has another. Compared as written: "Grey" is not "grey", and a hex value is not a name.
|
|
134
|
+
* @param {object} [options.colorMap] A stored colour to the CSS colour a column is drawn in,
|
|
135
|
+
* applied after the merge. A colour it does not map is kept as stored.
|
|
131
136
|
* @return {{states: Array<{key: string, label: string, color: string, capacity?: (number|null)}>, keyByValue: Map<string, string>, refsByKey: Map<string, Array<object>>}} The stages.
|
|
132
137
|
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references
|
|
133
138
|
*/
|
|
@@ -140,6 +145,8 @@ function buildReferenceStages({
|
|
|
140
145
|
narrowBy = null,
|
|
141
146
|
narrowValue = '',
|
|
142
147
|
capacityField = '',
|
|
148
|
+
neutralColor = '',
|
|
149
|
+
colorMap = null,
|
|
143
150
|
} = {}) {
|
|
144
151
|
const list = (Array.isArray(refs) ? refs : []).filter((ref) => ref && typeof ref === 'object' && refIdOf(ref) !== '');
|
|
145
152
|
const narrowed = narrowBy && narrowBy.field && narrowValue !== ''
|
|
@@ -165,8 +172,7 @@ function buildReferenceStages({
|
|
|
165
172
|
keyByValue.set(id, key);
|
|
166
173
|
if (!refsByKey.has(key)) {
|
|
167
174
|
refsByKey.set(key, []);
|
|
168
|
-
const
|
|
169
|
-
const state = { key, label, color: typeof color === 'string' ? color : '' };
|
|
175
|
+
const state = { key, label, color: colorOfRef(ref, colorField) };
|
|
170
176
|
if (capacityField) {
|
|
171
177
|
state.capacity = capacityOfRef(ref, capacityField);
|
|
172
178
|
}
|
|
@@ -175,13 +181,66 @@ function buildReferenceStages({
|
|
|
175
181
|
refsByKey.get(key).push(ref);
|
|
176
182
|
}
|
|
177
183
|
for (const state of states) {
|
|
178
|
-
|
|
184
|
+
const rows = refsByKey.get(state.key);
|
|
185
|
+
if (capacityField && rows.length > 1) {
|
|
179
186
|
state.capacity = null;
|
|
180
187
|
}
|
|
188
|
+
if (neutralColor && rows.length > 1) {
|
|
189
|
+
state.color = mergedColumnColor(rows.map((ref) => colorOfRef(ref, colorField)), neutralColor, state.color);
|
|
190
|
+
}
|
|
191
|
+
state.color = mappedColor(state.color, colorMap);
|
|
181
192
|
}
|
|
182
193
|
return { states, keyByValue, refsByKey }
|
|
183
194
|
}
|
|
184
195
|
|
|
196
|
+
/**
|
|
197
|
+
* The colour one referenced row carries.
|
|
198
|
+
*
|
|
199
|
+
* @param {object} ref The referenced row.
|
|
200
|
+
* @param {string} colorField The row field that holds the colour, '' for `color`.
|
|
201
|
+
* @return {string} The colour, '' when it has none.
|
|
202
|
+
*/
|
|
203
|
+
function colorOfRef(ref, colorField) {
|
|
204
|
+
const color = colorField ? readPath(ref, colorField) : ref.color;
|
|
205
|
+
return typeof color === 'string' ? color : ''
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* The colour a column merged from several rows takes when a neutral colour
|
|
210
|
+
* is declared: the first chosen colour, so a row stored with the default
|
|
211
|
+
* never outranks one somebody picked, whatever order the rows come in.
|
|
212
|
+
*
|
|
213
|
+
* @param {Array<string>} colors The rows' colours, in column order.
|
|
214
|
+
* @param {string} neutralColor The colour a row holds when nobody chose one.
|
|
215
|
+
* @param {string} fallback The colour when no row has a chosen or neutral one.
|
|
216
|
+
* @return {string} The column's colour.
|
|
217
|
+
* @spec openspec/changes/board-neutral-column-colour/specs/board-view/spec.md#requirement-a-merged-column-prefers-a-chosen-colour
|
|
218
|
+
*/
|
|
219
|
+
function mergedColumnColor(colors, neutralColor, fallback = '') {
|
|
220
|
+
const chosen = colors.find((color) => color !== '' && color !== neutralColor);
|
|
221
|
+
if (chosen !== undefined) {
|
|
222
|
+
return chosen
|
|
223
|
+
}
|
|
224
|
+
return colors.includes(neutralColor) ? neutralColor : fallback
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The CSS colour a stored colour maps to, so a palette name such as
|
|
229
|
+
* "orange" or "grey-light" can draw a theme token.
|
|
230
|
+
*
|
|
231
|
+
* @param {string} color The stored colour.
|
|
232
|
+
* @param {object|null} colorMap A stored colour to a CSS colour.
|
|
233
|
+
* @return {string} The mapped colour, else the stored one.
|
|
234
|
+
* @spec openspec/changes/board-column-colour-map/specs/board-view/spec.md#requirement-a-column-colour-can-be-mapped-to-a-css-colour
|
|
235
|
+
*/
|
|
236
|
+
function mappedColor(color, colorMap) {
|
|
237
|
+
if (!colorMap || typeof colorMap !== 'object' || color === '' || !Object.hasOwn(colorMap, color)) {
|
|
238
|
+
return color
|
|
239
|
+
}
|
|
240
|
+
const mapped = colorMap[color];
|
|
241
|
+
return typeof mapped === 'string' && mapped !== '' ? mapped : color
|
|
242
|
+
}
|
|
243
|
+
|
|
185
244
|
/**
|
|
186
245
|
* The limit one referenced row declares.
|
|
187
246
|
*
|
|
@@ -326,5 +385,5 @@ async function fetchReferenceObjects({ register, schema, filter = {}, limit = 50
|
|
|
326
385
|
return Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : [])
|
|
327
386
|
}
|
|
328
387
|
|
|
329
|
-
export { NO_VALUE_KEY, buildReferenceStages, buildValueStages, capacityOfRef, columnFieldsOf, columnKeyOfRow, fetchReferenceObjects, fullTargetOf, refIdOf, referenceTargetOf, resolveDropValue };
|
|
388
|
+
export { NO_VALUE_KEY, buildReferenceStages, buildValueStages, capacityOfRef, columnFieldsOf, columnKeyOfRow, fetchReferenceObjects, fullTargetOf, mappedColor, mergedColumnColor, refIdOf, referenceTargetOf, resolveDropValue };
|
|
330
389
|
//# sourceMappingURL=boardReferenceColumns.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"boardReferenceColumns.js","sources":["../../../src/utils/boardReferenceColumns.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Board columns from a REFERENCED field (screens-board-reference-columns).\n *\n * A status that is an enum or a lifecycle list carries its stages on the\n * field, and `boardColumns.js` reads them there. A status that is a reference\n * to another object (a case's `status` pointing at a statusType row) carries\n * nothing on the field: the stages are the rows of the referenced schema. This\n * module turns those rows into the same `states` list `stagesOf()` reads, plus\n * the map from a row's raw value (the referenced id) to its column.\n *\n * 🔴 THE COLUMNS ARE STILL THE SCHEMA'S, NOT THE DATA'S. They are the\n * referenced rows, fetched, not the values present on the loaded cards, so an\n * empty stage is still a column to drop a card into. The one exception is a\n * field with no referenced schema at all (a Nextcloud user id): there the\n * values present are all there is, and a \"nobody\" column is always added so\n * work without an owner stays visible and can be dropped back to nobody.\n *\n * 🔴 MERGED COLUMNS RESOLVE PER CARD. Referenced rows are often per parent\n * (every case type has its own \"In behandeling\"). Merged by name they make one\n * column, and a drop must then write the row of THAT card's parent. A column\n * with no row for the card's parent is not a place the card can go, and the\n * drop is refused rather than written to some other parent's row.\n *\n * Pure apart from `fetchReferenceObjects`: no store, no Vue.\n */\n\nimport { capacityValue } from './boardColumns.js'\nimport { buildHeaders, buildQueryString, prefixUrl } from './headers.js'\nimport { readPath } from './readPath.js'\nimport { schemaRefSlug } from './schemaRefSlug.js'\n\n/** The column of cards with no value, for a `values` column field. */\nexport const NO_VALUE_KEY = '__none__'\n\n/**\n * The id a reference value carries: a string as is, an object by its `id`,\n * `uuid` or `@self.id`.\n *\n * @param {unknown} value A reference as a row holds it.\n * @return {string} The id, '' when there is none.\n */\nexport function refIdOf(value) {\n\tif (value === null || value === undefined) {\n\t\treturn ''\n\t}\n\tif (typeof value === 'object') {\n\t\tconst id = value.id ?? value.uuid ?? value['@self']?.id ?? value.value ?? ''\n\t\treturn id === null || id === undefined ? '' : String(id)\n\t}\n\treturn String(value)\n}\n\n/**\n * A value as text: a string or number as is, an object by its name.\n *\n * @param {unknown} value The raw value.\n * @return {string} The text.\n */\nfunction textOf(value) {\n\tif (value === null || value === undefined) {\n\t\treturn ''\n\t}\n\tif (typeof value === 'object') {\n\t\treturn String(value.displayName ?? value.name ?? value.title ?? value.label ?? '').trim()\n\t}\n\treturn String(value).trim()\n}\n\n/**\n * The column fields a board offers, normalised. Without `columnFields` the\n * board has one, its `statusField`, read from the schema as before.\n *\n * @param {object} board The board configuration (manifest `config.board`).\n * @return {Array<{field: string, label: string, source: (object|null), kind: string, readOnly: boolean, moveHandler: string, moveTargetsHandler: string}>} The fields.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from\n */\nexport function columnFieldsOf(board) {\n\tconst declared = Array.isArray(board?.columnFields) ? board.columnFields : []\n\treturn declared\n\t\t.map((entry) => (typeof entry === 'string' ? { field: entry } : entry))\n\t\t.filter((entry) => entry && typeof entry.field === 'string' && entry.field !== '')\n\t\t.map((entry) => ({\n\t\t\tfield: entry.field,\n\t\t\tlabel: typeof entry.label === 'string' && entry.label !== '' ? entry.label : entry.field,\n\t\t\tsource: entry.source && typeof entry.source === 'object' ? entry.source : null,\n\t\t\tkind: entry.kind === 'values' ? 'values' : (entry.source ? 'reference' : 'schema'),\n\t\t\treadOnly: entry.readOnly === true,\n\t\t\tmoveHandler: typeof entry.moveHandler === 'string' ? entry.moveHandler : '',\n\t\t\tmoveTargetsHandler: typeof entry.moveTargetsHandler === 'string' ? entry.moveTargetsHandler : '',\n\t\t\tvalueLabels: entry.valueLabels && typeof entry.valueLabels === 'object' ? entry.valueLabels : null,\n\t\t\temptyLabel: typeof entry.emptyLabel === 'string' ? entry.emptyLabel : '',\n\t\t}))\n}\n\n/**\n * The register and schema a reference column reads its rows from: the\n * source's own, else the page's register and the property's `$ref`.\n *\n * @param {object} source The column field's `source`.\n * @param {object} options The context.\n * @param {string} options.register The page's register.\n * @param {object} [options.property] The field's schema property.\n * @return {{register: string, schema: string}} Both, '' when unknown.\n */\nexport function referenceTargetOf(source, { register = '', property = null } = {}) {\n\tconst schema = source?.schema || schemaRefSlug(property?.$ref ?? property?.items?.$ref ?? '')\n\treturn {\n\t\tregister: String(source?.register || register || ''),\n\t\tschema: schema === '' || schema === null || schema === undefined ? '' : String(schema),\n\t}\n}\n\n/**\n * The stages of a referenced field: the referenced rows, narrowed to one\n * parent when asked, ordered, and merged by a field when asked.\n *\n * @param {object} options The call.\n * @param {Array<object>} options.refs The referenced rows.\n * @param {string} [options.labelField] The row field that names a column.\n * @param {string} [options.orderField] The numeric row field the columns are ordered by.\n * @param {string} [options.colorField] The row field that holds the dot colour.\n * @param {string} [options.mergeBy] The row field whose equal values make one column.\n * @param {{field: string, rowField: string}|null} [options.narrowBy] The parent link.\n * @param {string} [options.narrowValue] The parent the board is narrowed to, '' for all.\n * @param {string} [options.capacityField] The numeric row field that holds a column's limit.\n * A column merged from two or more rows shows none: each row has its own limit.\n * @return {{states: Array<{key: string, label: string, color: string, capacity?: (number|null)}>, keyByValue: Map<string, string>, refsByKey: Map<string, Array<object>>}} The stages.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references\n */\nexport function buildReferenceStages({\n\trefs = [],\n\tlabelField = '',\n\torderField = '',\n\tcolorField = '',\n\tmergeBy = '',\n\tnarrowBy = null,\n\tnarrowValue = '',\n\tcapacityField = '',\n} = {}) {\n\tconst list = (Array.isArray(refs) ? refs : []).filter((ref) => ref && typeof ref === 'object' && refIdOf(ref) !== '')\n\tconst narrowed = narrowBy && narrowBy.field && narrowValue !== ''\n\t\t? list.filter((ref) => refIdOf(readPath(ref, narrowBy.field)) === String(narrowValue))\n\t\t: list\n\n\tconst orderOf = (ref) => {\n\t\tconst n = Number(orderField ? readPath(ref, orderField) : NaN)\n\t\treturn Number.isFinite(n) ? n : Number.MAX_SAFE_INTEGER\n\t}\n\tconst ordered = narrowed\n\t\t.map((ref, index) => ({ ref, index }))\n\t\t.sort((a, b) => (orderOf(a.ref) - orderOf(b.ref)) || (a.index - b.index))\n\t\t.map((entry) => entry.ref)\n\n\tconst states = []\n\tconst keyByValue = new Map()\n\tconst refsByKey = new Map()\n\tfor (const ref of ordered) {\n\t\tconst id = refIdOf(ref)\n\t\tconst label = textOf(labelField ? readPath(ref, labelField) : (ref.name ?? ref.title)) || id\n\t\tconst key = mergeBy ? (textOf(readPath(ref, mergeBy)) || id) : id\n\t\tkeyByValue.set(id, key)\n\t\tif (!refsByKey.has(key)) {\n\t\t\trefsByKey.set(key, [])\n\t\t\tconst color = colorField ? readPath(ref, colorField) : ref.color\n\t\t\tconst state = { key, label, color: typeof color === 'string' ? color : '' }\n\t\t\tif (capacityField) {\n\t\t\t\tstate.capacity = capacityOfRef(ref, capacityField)\n\t\t\t}\n\t\t\tstates.push(state)\n\t\t}\n\t\trefsByKey.get(key).push(ref)\n\t}\n\tfor (const state of states) {\n\t\tif (capacityField && refsByKey.get(state.key).length > 1) {\n\t\t\tstate.capacity = null\n\t\t}\n\t}\n\treturn { states, keyByValue, refsByKey }\n}\n\n/**\n * The limit one referenced row declares.\n *\n * @param {object} ref The referenced row.\n * @param {string} capacityField The row field that holds the limit.\n * @return {number|null} The limit, or null when it has none.\n * @spec openspec/changes/board-column-capacity/specs/board-view/spec.md#requirement-a-column-can-carry-a-capacity\n */\nexport function capacityOfRef(ref, capacityField) {\n\treturn capacityField ? capacityValue(readPath(ref, capacityField)) : null\n}\n\n/**\n * Whether a drop fills a referenced row past its limit: the cards that\n * already carry that row, counted against the row's own limit. Counted per\n * row, not per column, so a column merged from several rows still refuses\n * the one that is full.\n *\n * @param {object} options The call.\n * @param {object} options.target The referenced row the drop would write.\n * @param {object} options.card The card being moved.\n * @param {Array<object>} options.rows The cards the board holds.\n * @param {string} options.field The row field the columns come from.\n * @param {string} options.capacityField The referenced row's limit field.\n * @param {string} [options.rowKey] The row key, so the moving card is not counted.\n * @return {{count: number, capacity: number}|null} The count and limit when full, else null.\n * @spec openspec/changes/board-column-capacity/specs/board-view/spec.md#requirement-a-drop-into-a-full-column-is-refused\n */\nexport function fullTargetOf({ target, card, rows = [], field, capacityField, rowKey = 'id' } = {}) {\n\tconst capacity = capacityOfRef(target, capacityField)\n\tif (capacity === null) {\n\t\treturn null\n\t}\n\tconst id = refIdOf(target)\n\tconst self = String(card?.[rowKey] ?? '')\n\tconst count = (Array.isArray(rows) ? rows : []).filter((row) => String(row?.[rowKey] ?? '') !== self && refIdOf(readPath(row, field)) === id).length\n\treturn count >= capacity ? { count, capacity } : null\n}\n\n/**\n * The stages of a field with no referenced schema (a user id): the values\n * present on the rows, by label, then one column for no value.\n *\n * @param {object} options The call.\n * @param {Array<object>} options.rows The rows the list holds.\n * @param {string} options.field The row field.\n * @param {object} [options.valueLabels] Raw value to the label to show.\n * @param {string} [options.emptyLabel] The no-value column's label.\n * @return {{states: Array<{key: string, label: string, color: string}>, keyByValue: Map<string, string>, refsByKey: Map<string, Array<object>>}} The stages.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-field-without-a-referenced-schema-takes-its-values\n */\nexport function buildValueStages({ rows = [], field = '', valueLabels = null, emptyLabel = 'Nobody' } = {}) {\n\tconst labels = valueLabels && typeof valueLabels === 'object' ? valueLabels : {}\n\tconst seen = new Map()\n\tfor (const row of Array.isArray(rows) ? rows : []) {\n\t\tconst raw = readPath(row, field)\n\t\tconst id = refIdOf(raw)\n\t\tif (id !== '' && !seen.has(id)) {\n\t\t\tseen.set(id, typeof labels[id] === 'string' ? labels[id] : (textOf(raw) || id))\n\t\t}\n\t}\n\tconst states = [...seen.entries()]\n\t\t.sort((a, b) => a[1].localeCompare(b[1]))\n\t\t.map(([key, label]) => ({ key, label, color: '' }))\n\tstates.push({ key: NO_VALUE_KEY, label: emptyLabel, color: '' })\n\tconst keyByValue = new Map(states.map((state) => [state.key, state.key]))\n\tkeyByValue.set('', NO_VALUE_KEY)\n\treturn { states, keyByValue, refsByKey: new Map() }\n}\n\n/**\n * The column a row sits in, under a value-to-column map.\n *\n * @param {object} row The row.\n * @param {string} field The row field.\n * @param {Map<string, string>} keyByValue The value-to-column map.\n * @return {string} The column key, or the raw value when the map has none\n * (which lands the card in the off-board column).\n */\nexport function columnKeyOfRow(row, field, keyByValue) {\n\tconst id = refIdOf(readPath(row, field))\n\treturn keyByValue.has(id) ? keyByValue.get(id) : id\n}\n\n/**\n * What a drop on a column writes for one card: the referenced row of that\n * column which belongs to the card's parent, or null when the column has none\n * (the card cannot go there).\n *\n * @param {object} options The call.\n * @param {object} options.card The card.\n * @param {string} options.toKey The column it was dropped on.\n * @param {string} options.kind `reference` or `values`.\n * @param {Map<string, Array<object>>} [options.refsByKey] The column's rows.\n * @param {{field: string, rowField: string}|null} [options.narrowBy] The parent link.\n * @return {{value: (string|null), target: (object|null)}|null} The value to write and its row, or null.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-drop-writes-the-reference\n */\nexport function resolveDropValue({ card, toKey, kind, refsByKey = new Map(), narrowBy = null } = {}) {\n\tif (kind === 'values') {\n\t\treturn { value: toKey === NO_VALUE_KEY ? null : String(toKey), target: null }\n\t}\n\tconst candidates = refsByKey.get(String(toKey)) || []\n\tif (candidates.length === 0) {\n\t\treturn null\n\t}\n\tif (narrowBy && narrowBy.field && narrowBy.rowField) {\n\t\tconst parent = refIdOf(readPath(card, narrowBy.rowField))\n\t\tconst match = candidates.find((ref) => refIdOf(readPath(ref, narrowBy.field)) === parent)\n\t\treturn match ? { value: refIdOf(match), target: match } : null\n\t}\n\treturn { value: refIdOf(candidates[0]), target: candidates[0] }\n}\n\n/**\n * Fetch the rows a reference column is built from, one list request.\n *\n * @param {object} options The call.\n * @param {string} options.register The register slug.\n * @param {string} options.schema The schema slug.\n * @param {object} [options.filter] Equality filters, e.g. `{ isFinal: false }`.\n * @param {number} [options.limit] The page size, 500 by default.\n * @return {Promise<Array<object>>} The rows.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references\n */\nexport async function fetchReferenceObjects({ register, schema, filter = {}, limit = 500 } = {}) {\n\tif (!register || !schema) {\n\t\treturn []\n\t}\n\tconst params = { _limit: limit }\n\tfor (const [key, value] of Object.entries(filter || {})) {\n\t\tif (value !== undefined && value !== null && typeof value !== 'object') {\n\t\t\tparams[key] = typeof value === 'boolean' ? String(value) : value\n\t\t}\n\t}\n\tconst url = prefixUrl(`/apps/openregister/api/objects/${encodeURIComponent(register)}/${encodeURIComponent(schema)}${buildQueryString(params)}`)\n\tconst response = await fetch(url, { headers: buildHeaders() })\n\tif (!response.ok) {\n\t\tthrow new Error(`list returned ${response.status}`)\n\t}\n\tconst data = await response.json()\n\treturn Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : [])\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"boardReferenceColumns.js","sources":["../../../src/utils/boardReferenceColumns.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>\n * SPDX-License-Identifier: EUPL-1.2\n *\n * Board columns from a REFERENCED field (screens-board-reference-columns).\n *\n * A status that is an enum or a lifecycle list carries its stages on the\n * field, and `boardColumns.js` reads them there. A status that is a reference\n * to another object (a case's `status` pointing at a statusType row) carries\n * nothing on the field: the stages are the rows of the referenced schema. This\n * module turns those rows into the same `states` list `stagesOf()` reads, plus\n * the map from a row's raw value (the referenced id) to its column.\n *\n * 🔴 THE COLUMNS ARE STILL THE SCHEMA'S, NOT THE DATA'S. They are the\n * referenced rows, fetched, not the values present on the loaded cards, so an\n * empty stage is still a column to drop a card into. The one exception is a\n * field with no referenced schema at all (a Nextcloud user id): there the\n * values present are all there is, and a \"nobody\" column is always added so\n * work without an owner stays visible and can be dropped back to nobody.\n *\n * 🔴 MERGED COLUMNS RESOLVE PER CARD. Referenced rows are often per parent\n * (every case type has its own \"In behandeling\"). Merged by name they make one\n * column, and a drop must then write the row of THAT card's parent. A column\n * with no row for the card's parent is not a place the card can go, and the\n * drop is refused rather than written to some other parent's row.\n *\n * Pure apart from `fetchReferenceObjects`: no store, no Vue.\n */\n\nimport { capacityValue } from './boardColumns.js'\nimport { buildHeaders, buildQueryString, prefixUrl } from './headers.js'\nimport { readPath } from './readPath.js'\nimport { schemaRefSlug } from './schemaRefSlug.js'\n\n/** The column of cards with no value, for a `values` column field. */\nexport const NO_VALUE_KEY = '__none__'\n\n/**\n * The id a reference value carries: a string as is, an object by its `id`,\n * `uuid` or `@self.id`.\n *\n * @param {unknown} value A reference as a row holds it.\n * @return {string} The id, '' when there is none.\n */\nexport function refIdOf(value) {\n\tif (value === null || value === undefined) {\n\t\treturn ''\n\t}\n\tif (typeof value === 'object') {\n\t\tconst id = value.id ?? value.uuid ?? value['@self']?.id ?? value.value ?? ''\n\t\treturn id === null || id === undefined ? '' : String(id)\n\t}\n\treturn String(value)\n}\n\n/**\n * A value as text: a string or number as is, an object by its name.\n *\n * @param {unknown} value The raw value.\n * @return {string} The text.\n */\nfunction textOf(value) {\n\tif (value === null || value === undefined) {\n\t\treturn ''\n\t}\n\tif (typeof value === 'object') {\n\t\treturn String(value.displayName ?? value.name ?? value.title ?? value.label ?? '').trim()\n\t}\n\treturn String(value).trim()\n}\n\n/**\n * The column fields a board offers, normalised. Without `columnFields` the\n * board has one, its `statusField`, read from the schema as before.\n *\n * @param {object} board The board configuration (manifest `config.board`).\n * @return {Array<{field: string, label: string, source: (object|null), kind: string, readOnly: boolean, moveHandler: string, moveTargetsHandler: string}>} The fields.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from\n */\nexport function columnFieldsOf(board) {\n\tconst declared = Array.isArray(board?.columnFields) ? board.columnFields : []\n\treturn declared\n\t\t.map((entry) => (typeof entry === 'string' ? { field: entry } : entry))\n\t\t.filter((entry) => entry && typeof entry.field === 'string' && entry.field !== '')\n\t\t.map((entry) => ({\n\t\t\tfield: entry.field,\n\t\t\tlabel: typeof entry.label === 'string' && entry.label !== '' ? entry.label : entry.field,\n\t\t\tsource: entry.source && typeof entry.source === 'object' ? entry.source : null,\n\t\t\tkind: entry.kind === 'values' ? 'values' : (entry.source ? 'reference' : 'schema'),\n\t\t\treadOnly: entry.readOnly === true,\n\t\t\tmoveHandler: typeof entry.moveHandler === 'string' ? entry.moveHandler : '',\n\t\t\tmoveTargetsHandler: typeof entry.moveTargetsHandler === 'string' ? entry.moveTargetsHandler : '',\n\t\t\tvalueLabels: entry.valueLabels && typeof entry.valueLabels === 'object' ? entry.valueLabels : null,\n\t\t\temptyLabel: typeof entry.emptyLabel === 'string' ? entry.emptyLabel : '',\n\t\t}))\n}\n\n/**\n * The register and schema a reference column reads its rows from: the\n * source's own, else the page's register and the property's `$ref`.\n *\n * @param {object} source The column field's `source`.\n * @param {object} options The context.\n * @param {string} options.register The page's register.\n * @param {object} [options.property] The field's schema property.\n * @return {{register: string, schema: string}} Both, '' when unknown.\n */\nexport function referenceTargetOf(source, { register = '', property = null } = {}) {\n\tconst schema = source?.schema || schemaRefSlug(property?.$ref ?? property?.items?.$ref ?? '')\n\treturn {\n\t\tregister: String(source?.register || register || ''),\n\t\tschema: schema === '' || schema === null || schema === undefined ? '' : String(schema),\n\t}\n}\n\n/**\n * The stages of a referenced field: the referenced rows, narrowed to one\n * parent when asked, ordered, and merged by a field when asked.\n *\n * @param {object} options The call.\n * @param {Array<object>} options.refs The referenced rows.\n * @param {string} [options.labelField] The row field that names a column.\n * @param {string} [options.orderField] The numeric row field the columns are ordered by.\n * @param {string} [options.colorField] The row field that holds the dot colour.\n * @param {string} [options.mergeBy] The row field whose equal values make one column.\n * @param {{field: string, rowField: string}|null} [options.narrowBy] The parent link.\n * @param {string} [options.narrowValue] The parent the board is narrowed to, '' for all.\n * @param {string} [options.capacityField] The numeric row field that holds a column's limit.\n * A column merged from two or more rows shows none: each row has its own limit.\n * @param {string} [options.neutralColor] The colour a row holds when nobody chose one. A merged\n * column then takes its first row colour that is not this one, and this one only when no row\n * has another. Compared as written: \"Grey\" is not \"grey\", and a hex value is not a name.\n * @param {object} [options.colorMap] A stored colour to the CSS colour a column is drawn in,\n * applied after the merge. A colour it does not map is kept as stored.\n * @return {{states: Array<{key: string, label: string, color: string, capacity?: (number|null)}>, keyByValue: Map<string, string>, refsByKey: Map<string, Array<object>>}} The stages.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references\n */\nexport function buildReferenceStages({\n\trefs = [],\n\tlabelField = '',\n\torderField = '',\n\tcolorField = '',\n\tmergeBy = '',\n\tnarrowBy = null,\n\tnarrowValue = '',\n\tcapacityField = '',\n\tneutralColor = '',\n\tcolorMap = null,\n} = {}) {\n\tconst list = (Array.isArray(refs) ? refs : []).filter((ref) => ref && typeof ref === 'object' && refIdOf(ref) !== '')\n\tconst narrowed = narrowBy && narrowBy.field && narrowValue !== ''\n\t\t? list.filter((ref) => refIdOf(readPath(ref, narrowBy.field)) === String(narrowValue))\n\t\t: list\n\n\tconst orderOf = (ref) => {\n\t\tconst n = Number(orderField ? readPath(ref, orderField) : NaN)\n\t\treturn Number.isFinite(n) ? n : Number.MAX_SAFE_INTEGER\n\t}\n\tconst ordered = narrowed\n\t\t.map((ref, index) => ({ ref, index }))\n\t\t.sort((a, b) => (orderOf(a.ref) - orderOf(b.ref)) || (a.index - b.index))\n\t\t.map((entry) => entry.ref)\n\n\tconst states = []\n\tconst keyByValue = new Map()\n\tconst refsByKey = new Map()\n\tfor (const ref of ordered) {\n\t\tconst id = refIdOf(ref)\n\t\tconst label = textOf(labelField ? readPath(ref, labelField) : (ref.name ?? ref.title)) || id\n\t\tconst key = mergeBy ? (textOf(readPath(ref, mergeBy)) || id) : id\n\t\tkeyByValue.set(id, key)\n\t\tif (!refsByKey.has(key)) {\n\t\t\trefsByKey.set(key, [])\n\t\t\tconst state = { key, label, color: colorOfRef(ref, colorField) }\n\t\t\tif (capacityField) {\n\t\t\t\tstate.capacity = capacityOfRef(ref, capacityField)\n\t\t\t}\n\t\t\tstates.push(state)\n\t\t}\n\t\trefsByKey.get(key).push(ref)\n\t}\n\tfor (const state of states) {\n\t\tconst rows = refsByKey.get(state.key)\n\t\tif (capacityField && rows.length > 1) {\n\t\t\tstate.capacity = null\n\t\t}\n\t\tif (neutralColor && rows.length > 1) {\n\t\t\tstate.color = mergedColumnColor(rows.map((ref) => colorOfRef(ref, colorField)), neutralColor, state.color)\n\t\t}\n\t\tstate.color = mappedColor(state.color, colorMap)\n\t}\n\treturn { states, keyByValue, refsByKey }\n}\n\n/**\n * The colour one referenced row carries.\n *\n * @param {object} ref The referenced row.\n * @param {string} colorField The row field that holds the colour, '' for `color`.\n * @return {string} The colour, '' when it has none.\n */\nfunction colorOfRef(ref, colorField) {\n\tconst color = colorField ? readPath(ref, colorField) : ref.color\n\treturn typeof color === 'string' ? color : ''\n}\n\n/**\n * The colour a column merged from several rows takes when a neutral colour\n * is declared: the first chosen colour, so a row stored with the default\n * never outranks one somebody picked, whatever order the rows come in.\n *\n * @param {Array<string>} colors The rows' colours, in column order.\n * @param {string} neutralColor The colour a row holds when nobody chose one.\n * @param {string} fallback The colour when no row has a chosen or neutral one.\n * @return {string} The column's colour.\n * @spec openspec/changes/board-neutral-column-colour/specs/board-view/spec.md#requirement-a-merged-column-prefers-a-chosen-colour\n */\nexport function mergedColumnColor(colors, neutralColor, fallback = '') {\n\tconst chosen = colors.find((color) => color !== '' && color !== neutralColor)\n\tif (chosen !== undefined) {\n\t\treturn chosen\n\t}\n\treturn colors.includes(neutralColor) ? neutralColor : fallback\n}\n\n/**\n * The CSS colour a stored colour maps to, so a palette name such as\n * \"orange\" or \"grey-light\" can draw a theme token.\n *\n * @param {string} color The stored colour.\n * @param {object|null} colorMap A stored colour to a CSS colour.\n * @return {string} The mapped colour, else the stored one.\n * @spec openspec/changes/board-column-colour-map/specs/board-view/spec.md#requirement-a-column-colour-can-be-mapped-to-a-css-colour\n */\nexport function mappedColor(color, colorMap) {\n\tif (!colorMap || typeof colorMap !== 'object' || color === '' || !Object.hasOwn(colorMap, color)) {\n\t\treturn color\n\t}\n\tconst mapped = colorMap[color]\n\treturn typeof mapped === 'string' && mapped !== '' ? mapped : color\n}\n\n/**\n * The limit one referenced row declares.\n *\n * @param {object} ref The referenced row.\n * @param {string} capacityField The row field that holds the limit.\n * @return {number|null} The limit, or null when it has none.\n * @spec openspec/changes/board-column-capacity/specs/board-view/spec.md#requirement-a-column-can-carry-a-capacity\n */\nexport function capacityOfRef(ref, capacityField) {\n\treturn capacityField ? capacityValue(readPath(ref, capacityField)) : null\n}\n\n/**\n * Whether a drop fills a referenced row past its limit: the cards that\n * already carry that row, counted against the row's own limit. Counted per\n * row, not per column, so a column merged from several rows still refuses\n * the one that is full.\n *\n * @param {object} options The call.\n * @param {object} options.target The referenced row the drop would write.\n * @param {object} options.card The card being moved.\n * @param {Array<object>} options.rows The cards the board holds.\n * @param {string} options.field The row field the columns come from.\n * @param {string} options.capacityField The referenced row's limit field.\n * @param {string} [options.rowKey] The row key, so the moving card is not counted.\n * @return {{count: number, capacity: number}|null} The count and limit when full, else null.\n * @spec openspec/changes/board-column-capacity/specs/board-view/spec.md#requirement-a-drop-into-a-full-column-is-refused\n */\nexport function fullTargetOf({ target, card, rows = [], field, capacityField, rowKey = 'id' } = {}) {\n\tconst capacity = capacityOfRef(target, capacityField)\n\tif (capacity === null) {\n\t\treturn null\n\t}\n\tconst id = refIdOf(target)\n\tconst self = String(card?.[rowKey] ?? '')\n\tconst count = (Array.isArray(rows) ? rows : []).filter((row) => String(row?.[rowKey] ?? '') !== self && refIdOf(readPath(row, field)) === id).length\n\treturn count >= capacity ? { count, capacity } : null\n}\n\n/**\n * The stages of a field with no referenced schema (a user id): the values\n * present on the rows, by label, then one column for no value.\n *\n * @param {object} options The call.\n * @param {Array<object>} options.rows The rows the list holds.\n * @param {string} options.field The row field.\n * @param {object} [options.valueLabels] Raw value to the label to show.\n * @param {string} [options.emptyLabel] The no-value column's label.\n * @return {{states: Array<{key: string, label: string, color: string}>, keyByValue: Map<string, string>, refsByKey: Map<string, Array<object>>}} The stages.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-field-without-a-referenced-schema-takes-its-values\n */\nexport function buildValueStages({ rows = [], field = '', valueLabels = null, emptyLabel = 'Nobody' } = {}) {\n\tconst labels = valueLabels && typeof valueLabels === 'object' ? valueLabels : {}\n\tconst seen = new Map()\n\tfor (const row of Array.isArray(rows) ? rows : []) {\n\t\tconst raw = readPath(row, field)\n\t\tconst id = refIdOf(raw)\n\t\tif (id !== '' && !seen.has(id)) {\n\t\t\tseen.set(id, typeof labels[id] === 'string' ? labels[id] : (textOf(raw) || id))\n\t\t}\n\t}\n\tconst states = [...seen.entries()]\n\t\t.sort((a, b) => a[1].localeCompare(b[1]))\n\t\t.map(([key, label]) => ({ key, label, color: '' }))\n\tstates.push({ key: NO_VALUE_KEY, label: emptyLabel, color: '' })\n\tconst keyByValue = new Map(states.map((state) => [state.key, state.key]))\n\tkeyByValue.set('', NO_VALUE_KEY)\n\treturn { states, keyByValue, refsByKey: new Map() }\n}\n\n/**\n * The column a row sits in, under a value-to-column map.\n *\n * @param {object} row The row.\n * @param {string} field The row field.\n * @param {Map<string, string>} keyByValue The value-to-column map.\n * @return {string} The column key, or the raw value when the map has none\n * (which lands the card in the off-board column).\n */\nexport function columnKeyOfRow(row, field, keyByValue) {\n\tconst id = refIdOf(readPath(row, field))\n\treturn keyByValue.has(id) ? keyByValue.get(id) : id\n}\n\n/**\n * What a drop on a column writes for one card: the referenced row of that\n * column which belongs to the card's parent, or null when the column has none\n * (the card cannot go there).\n *\n * @param {object} options The call.\n * @param {object} options.card The card.\n * @param {string} options.toKey The column it was dropped on.\n * @param {string} options.kind `reference` or `values`.\n * @param {Map<string, Array<object>>} [options.refsByKey] The column's rows.\n * @param {{field: string, rowField: string}|null} [options.narrowBy] The parent link.\n * @return {{value: (string|null), target: (object|null)}|null} The value to write and its row, or null.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-drop-writes-the-reference\n */\nexport function resolveDropValue({ card, toKey, kind, refsByKey = new Map(), narrowBy = null } = {}) {\n\tif (kind === 'values') {\n\t\treturn { value: toKey === NO_VALUE_KEY ? null : String(toKey), target: null }\n\t}\n\tconst candidates = refsByKey.get(String(toKey)) || []\n\tif (candidates.length === 0) {\n\t\treturn null\n\t}\n\tif (narrowBy && narrowBy.field && narrowBy.rowField) {\n\t\tconst parent = refIdOf(readPath(card, narrowBy.rowField))\n\t\tconst match = candidates.find((ref) => refIdOf(readPath(ref, narrowBy.field)) === parent)\n\t\treturn match ? { value: refIdOf(match), target: match } : null\n\t}\n\treturn { value: refIdOf(candidates[0]), target: candidates[0] }\n}\n\n/**\n * Fetch the rows a reference column is built from, one list request.\n *\n * @param {object} options The call.\n * @param {string} options.register The register slug.\n * @param {string} options.schema The schema slug.\n * @param {object} [options.filter] Equality filters, e.g. `{ isFinal: false }`.\n * @param {number} [options.limit] The page size, 500 by default.\n * @return {Promise<Array<object>>} The rows.\n * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references\n */\nexport async function fetchReferenceObjects({ register, schema, filter = {}, limit = 500 } = {}) {\n\tif (!register || !schema) {\n\t\treturn []\n\t}\n\tconst params = { _limit: limit }\n\tfor (const [key, value] of Object.entries(filter || {})) {\n\t\tif (value !== undefined && value !== null && typeof value !== 'object') {\n\t\t\tparams[key] = typeof value === 'boolean' ? String(value) : value\n\t\t}\n\t}\n\tconst url = prefixUrl(`/apps/openregister/api/objects/${encodeURIComponent(register)}/${encodeURIComponent(schema)}${buildQueryString(params)}`)\n\tconst response = await fetch(url, { headers: buildHeaders() })\n\tif (!response.ok) {\n\t\tthrow new Error(`list returned ${response.status}`)\n\t}\n\tconst data = await response.json()\n\treturn Array.isArray(data?.results) ? data.results : (Array.isArray(data) ? data : [])\n}\n"],"names":[],"mappings":"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"}
|