@conduction/nextcloud-vue 2.64.0 → 2.65.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/CnAppNav/CnAppNav.vue2.js +99 -3
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +23 -7
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js +13 -0
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +2 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +26 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +6 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +64 -5
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +66 -28
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +22 -5
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +22 -3
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +10 -3
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +164 -0
- package/dist/esm/store/useObjectStore.js +118 -33
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/actionsDispatcher.js +14 -0
- package/dist/esm/utils/actionsDispatcher.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 +488 -96
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +164 -0
- package/package.json +1 -1
- package/src/components/CnAppNav/CnAppNav.vue +148 -7
- package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +14 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +29 -2
- package/src/components/CnDetailPage/CnDetailPage.md +5 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +114 -6
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +34 -6
- package/src/components/CnStagesWidget/CnStagesWidget.vue +9 -0
- package/src/components/CnStatWidget/CnStatWidget.vue +33 -5
- package/src/css/detail-page.css +22 -0
- package/src/css/kpi-card.css +47 -0
- package/src/schemas/app-manifest-v2.schema.json +23 -2
- package/src/store/useObjectStore.js +118 -33
- package/src/utils/actionsDispatcher.js +14 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -1283,6 +1283,53 @@
|
|
|
1283
1283
|
font-size: var(--cn-kpi-value-size-stacked, 2rem);
|
|
1284
1284
|
}
|
|
1285
1285
|
|
|
1286
|
+
/* Stacked: the board's tile (`content.layout: 'stacked'`). A plain muted
|
|
1287
|
+
label, the number at 34px/700 in the text colour, and the caption on a line
|
|
1288
|
+
of its own; CnStatWidget draws no icon circle in this layout. The padding
|
|
1289
|
+
adds up with a dashboard card-fit cell's 8px 14px to the board's 18px 20px.
|
|
1290
|
+
Every value is a token so a theme can move it. */
|
|
1291
|
+
.cn-kpi-card--stacked {
|
|
1292
|
+
flex-direction: column;
|
|
1293
|
+
align-items: stretch;
|
|
1294
|
+
justify-content: center;
|
|
1295
|
+
gap: 0;
|
|
1296
|
+
padding: var(--cn-kpi-stacked-padding, 10px 6px);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
.cn-kpi-card--stacked .cn-kpi-card__body {
|
|
1300
|
+
gap: var(--cn-kpi-stacked-gap, 6px);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
.cn-kpi-card--stacked .cn-kpi-card__title {
|
|
1304
|
+
font-size: var(--cn-kpi-stacked-title-size, 14px);
|
|
1305
|
+
font-weight: var(--cn-kpi-stacked-title-weight, 400);
|
|
1306
|
+
color: var(--color-text-maxcontrast);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
.cn-kpi-card--stacked .cn-kpi-card__value {
|
|
1310
|
+
font-size: var(--cn-kpi-stacked-value-size, 34px);
|
|
1311
|
+
font-weight: var(--cn-kpi-value-weight, 700);
|
|
1312
|
+
line-height: 1;
|
|
1313
|
+
letter-spacing: -0.01em;
|
|
1314
|
+
color: var(--cn-kpi-stacked-value-color, var(--color-main-text));
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
.cn-kpi-card--stacked .cn-kpi-card__caption-line {
|
|
1318
|
+
flex: 0 0 auto;
|
|
1319
|
+
max-width: 100%;
|
|
1320
|
+
font-size: var(--cn-kpi-label-size, 13px);
|
|
1321
|
+
font-weight: 500;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/* A linked stacked tile reads as a tile, not as underlined link text. The
|
|
1325
|
+
NL Design theme underlines every `a` with `!important`, so the opt-out
|
|
1326
|
+
needs it too; it only applies to this opt-in layout. */
|
|
1327
|
+
a.cn-kpi-card--stacked,
|
|
1328
|
+
a.cn-kpi-card--stacked:hover,
|
|
1329
|
+
a.cn-kpi-card--stacked:focus-visible {
|
|
1330
|
+
text-decoration: none !important;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1286
1333
|
/* Filled: the card draws its own grey box, for a KPI that is NOT already
|
|
1287
1334
|
inside a wrapper that draws one. Opt-in via `content.flat: false`. */
|
|
1288
1335
|
.cn-kpi-card--filled {
|
|
@@ -2790,6 +2837,28 @@
|
|
|
2790
2837
|
min-width: 0;
|
|
2791
2838
|
}
|
|
2792
2839
|
|
|
2840
|
+
/* A widget in the header (`config.headerWidget`) takes a row of its own under
|
|
2841
|
+
the title and the actions. */
|
|
2842
|
+
.cn-detail-page__header--with-widget {
|
|
2843
|
+
flex-wrap: wrap;
|
|
2844
|
+
row-gap: var(--cn-detail-header-row-gap, 22px);
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
.cn-detail-page__header-widget {
|
|
2848
|
+
flex: 1 0 100%;
|
|
2849
|
+
min-width: 0;
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2852
|
+
/* The header as a card (`config.headerCard`): the board's case header, a
|
|
2853
|
+
bordered box on the surface colour. The 56px inset that clears the
|
|
2854
|
+
navigation toggle is not needed inside a card that starts below it. */
|
|
2855
|
+
.cn-detail-page__header--card {
|
|
2856
|
+
padding: var(--cn-detail-header-card-padding, 22px 24px);
|
|
2857
|
+
border: 1px solid var(--color-border);
|
|
2858
|
+
border-radius: var(--cn-detail-header-card-radius, 12px);
|
|
2859
|
+
background: var(--color-main-background);
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2793
2862
|
.cn-detail-page__header-left {
|
|
2794
2863
|
display: flex;
|
|
2795
2864
|
align-items: center;
|
|
@@ -16875,7 +16944,17 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
|
|
|
16875
16944
|
text-overflow: ellipsis;
|
|
16876
16945
|
white-space: nowrap;
|
|
16877
16946
|
}
|
|
16947
|
+
|
|
16948
|
+
/* A clickable label is a <button>, and Nextcloud's core stylesheet gives
|
|
16949
|
+
every `button:not(.button-vue)` a min-height of the clickable area (34 to
|
|
16950
|
+
44px) with the text centred in it. That pushed each reachable stage's label
|
|
16951
|
+
about 12px below the current one, which is a <span>. Zeroed here so all
|
|
16952
|
+
labels sit 8px under their bar, as the board draws them. The visually
|
|
16953
|
+
hidden "(current step)" is absolutely positioned and takes no space. */
|
|
16878
16954
|
button.cn-stages-widget__bar-label[data-v-358fde0f] {
|
|
16955
|
+
min-height: 0;
|
|
16956
|
+
height: auto;
|
|
16957
|
+
line-height: inherit;
|
|
16879
16958
|
cursor: pointer;
|
|
16880
16959
|
}
|
|
16881
16960
|
button.cn-stages-widget__bar-label[aria-disabled="true"][data-v-358fde0f] {
|
|
@@ -17310,6 +17389,53 @@ button.cn-stages-widget__bar-label[data-v-358fde0f]:focus-visible {
|
|
|
17310
17389
|
font-size: var(--cn-kpi-value-size-stacked, 2rem);
|
|
17311
17390
|
}
|
|
17312
17391
|
|
|
17392
|
+
/* Stacked: the board's tile (`content.layout: 'stacked'`). A plain muted
|
|
17393
|
+
label, the number at 34px/700 in the text colour, and the caption on a line
|
|
17394
|
+
of its own; CnStatWidget draws no icon circle in this layout. The padding
|
|
17395
|
+
adds up with a dashboard card-fit cell's 8px 14px to the board's 18px 20px.
|
|
17396
|
+
Every value is a token so a theme can move it. */
|
|
17397
|
+
.cn-kpi-card--stacked {
|
|
17398
|
+
flex-direction: column;
|
|
17399
|
+
align-items: stretch;
|
|
17400
|
+
justify-content: center;
|
|
17401
|
+
gap: 0;
|
|
17402
|
+
padding: var(--cn-kpi-stacked-padding, 10px 6px);
|
|
17403
|
+
}
|
|
17404
|
+
|
|
17405
|
+
.cn-kpi-card--stacked .cn-kpi-card__body {
|
|
17406
|
+
gap: var(--cn-kpi-stacked-gap, 6px);
|
|
17407
|
+
}
|
|
17408
|
+
|
|
17409
|
+
.cn-kpi-card--stacked .cn-kpi-card__title {
|
|
17410
|
+
font-size: var(--cn-kpi-stacked-title-size, 14px);
|
|
17411
|
+
font-weight: var(--cn-kpi-stacked-title-weight, 400);
|
|
17412
|
+
color: var(--color-text-maxcontrast);
|
|
17413
|
+
}
|
|
17414
|
+
|
|
17415
|
+
.cn-kpi-card--stacked .cn-kpi-card__value {
|
|
17416
|
+
font-size: var(--cn-kpi-stacked-value-size, 34px);
|
|
17417
|
+
font-weight: var(--cn-kpi-value-weight, 700);
|
|
17418
|
+
line-height: 1;
|
|
17419
|
+
letter-spacing: -0.01em;
|
|
17420
|
+
color: var(--cn-kpi-stacked-value-color, var(--color-main-text));
|
|
17421
|
+
}
|
|
17422
|
+
|
|
17423
|
+
.cn-kpi-card--stacked .cn-kpi-card__caption-line {
|
|
17424
|
+
flex: 0 0 auto;
|
|
17425
|
+
max-width: 100%;
|
|
17426
|
+
font-size: var(--cn-kpi-label-size, 13px);
|
|
17427
|
+
font-weight: 500;
|
|
17428
|
+
}
|
|
17429
|
+
|
|
17430
|
+
/* A linked stacked tile reads as a tile, not as underlined link text. The
|
|
17431
|
+
NL Design theme underlines every `a` with `!important`, so the opt-out
|
|
17432
|
+
needs it too; it only applies to this opt-in layout. */
|
|
17433
|
+
a.cn-kpi-card--stacked,
|
|
17434
|
+
a.cn-kpi-card--stacked:hover,
|
|
17435
|
+
a.cn-kpi-card--stacked:focus-visible {
|
|
17436
|
+
text-decoration: none !important;
|
|
17437
|
+
}
|
|
17438
|
+
|
|
17313
17439
|
/* Filled: the card draws its own grey box, for a KPI that is NOT already
|
|
17314
17440
|
inside a wrapper that draws one. Opt-in via `content.flat: false`. */
|
|
17315
17441
|
.cn-kpi-card--filled {
|
|
@@ -18262,6 +18388,16 @@ to { background-position: -200% 0;
|
|
|
18262
18388
|
flex: 0 0 auto;
|
|
18263
18389
|
padding: 16px;
|
|
18264
18390
|
}
|
|
18391
|
+
|
|
18392
|
+
/* On the page ground (`content.ground`): no card, so no inset around the
|
|
18393
|
+
view switch, and the heading at the board's 32px. */
|
|
18394
|
+
.cn-header-widget--ground .cn-header-widget__views[data-v-1b97430f] {
|
|
18395
|
+
padding: 0;
|
|
18396
|
+
}
|
|
18397
|
+
.cn-header-widget--ground .cn-header-widget__title[data-v-1b97430f] {
|
|
18398
|
+
font-size: var(--cn-header-ground-title-size, 32px);
|
|
18399
|
+
letter-spacing: -0.01em;
|
|
18400
|
+
}
|
|
18265
18401
|
.cn-header-widget__date[data-v-1b97430f] {
|
|
18266
18402
|
font-size: 14px;
|
|
18267
18403
|
line-height: 1.4;
|
|
@@ -33247,6 +33383,21 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
|
|
|
33247
33383
|
padding: calc(var(--default-grid-baseline, 4px) * 2);
|
|
33248
33384
|
}
|
|
33249
33385
|
|
|
33386
|
+
/*
|
|
33387
|
+
* The primary action never shrinks out of sight. NcAppNavigation renders it in
|
|
33388
|
+
* `.app-navigation__body`, a flex child with `overflow-y: scroll` (so its
|
|
33389
|
+
* minimum height is 0) beside a list of `height: 100%` and the footer. With a
|
|
33390
|
+
* card and footer entries below the list, the column overflows and the body
|
|
33391
|
+
* gives up its share of the shrink: "New case" showed as a 24px sliver of a
|
|
33392
|
+
* 42px button. All three forms carry `.app-navigation-new` (the solid and
|
|
33393
|
+
* link wrappers mirror NcAppNavigationNew's class), and the rule is scoped to
|
|
33394
|
+
* this component's navigation, so a navigation without a primary action lays
|
|
33395
|
+
* out exactly as before.
|
|
33396
|
+
*/
|
|
33397
|
+
.app-navigation[data-testid="cn-nav"] .app-navigation__body:has(> .app-navigation-new) {
|
|
33398
|
+
flex-shrink: 0;
|
|
33399
|
+
}
|
|
33400
|
+
|
|
33250
33401
|
/*
|
|
33251
33402
|
* Footer-section items (section: "footer") render in NcAppNavigation's
|
|
33252
33403
|
* #footer slot, outside the scroll container, so they stay visible above
|
|
@@ -33270,6 +33421,19 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
|
|
|
33270
33421
|
overflow: visible !important;
|
|
33271
33422
|
}
|
|
33272
33423
|
|
|
33424
|
+
/*
|
|
33425
|
+
* A declared footer that names `settings` first (`nav.footer`) puts the
|
|
33426
|
+
* foldout above the footer list. The two are siblings in NcAppNavigation's
|
|
33427
|
+
* flex column, so `order` moves them without changing either's markup; the
|
|
33428
|
+
* card above keeps order 0 and stays first.
|
|
33429
|
+
*/
|
|
33430
|
+
.cn-app-nav__settings--first {
|
|
33431
|
+
order: 1;
|
|
33432
|
+
}
|
|
33433
|
+
.cn-app-nav__footer-list--after-settings {
|
|
33434
|
+
order: 2;
|
|
33435
|
+
}
|
|
33436
|
+
|
|
33273
33437
|
/*
|
|
33274
33438
|
* Align the settings foldout's items with the main/footer list items,
|
|
33275
33439
|
* whose icons sit at a 16px inset. The foldout's items live in a bare
|
|
@@ -264,6 +264,27 @@ const baseActions = {
|
|
|
264
264
|
this.facets = { ...this.facets, [slug]: {} };
|
|
265
265
|
},
|
|
266
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Give a registered type a second schema path segment to try once when
|
|
269
|
+
* its own answers 404 (see `_fetchWithSchemaFallback`). Set by
|
|
270
|
+
* `resolveObjectOpType` for a schema title it kebab-cased, with the
|
|
271
|
+
* title as written. A type that is not registered is left alone.
|
|
272
|
+
*
|
|
273
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-schema-title-falls-back-to-its-written-form
|
|
274
|
+
* @param {string} slug The type slug
|
|
275
|
+
* @param {string} schema The fallback schema path segment
|
|
276
|
+
*/
|
|
277
|
+
setSchemaFallback(slug, schema) {
|
|
278
|
+
const config = this.objectTypeRegistry[slug];
|
|
279
|
+
if (!config || typeof schema !== 'string' || schema === '') {
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
this.objectTypeRegistry = {
|
|
283
|
+
...this.objectTypeRegistry,
|
|
284
|
+
[slug]: { ...config, schemaFallback: schema },
|
|
285
|
+
};
|
|
286
|
+
},
|
|
287
|
+
|
|
267
288
|
/**
|
|
268
289
|
* Unregister an object type and clean up all its state.
|
|
269
290
|
*
|
|
@@ -433,11 +454,12 @@ const baseActions = {
|
|
|
433
454
|
*
|
|
434
455
|
* @param {string} type The type slug
|
|
435
456
|
* @param {string|null} [id] Optional object ID
|
|
457
|
+
* @param {string|null} [schema] Schema path segment to use instead of the type's own
|
|
436
458
|
* @return {string} Full API URL path
|
|
437
459
|
*/
|
|
438
|
-
_buildUrl(type, id = null) {
|
|
460
|
+
_buildUrl(type, id = null, schema = null) {
|
|
439
461
|
const config = this._getTypeConfig(type);
|
|
440
|
-
let url = `${this._options.baseUrl}/${config.register}/${config.schema}`;
|
|
462
|
+
let url = `${this._options.baseUrl}/${config.register}/${schema ?? config.schema}`;
|
|
441
463
|
if (id) {
|
|
442
464
|
url += `/${id}`;
|
|
443
465
|
}
|
|
@@ -458,11 +480,12 @@ const baseActions = {
|
|
|
458
480
|
* @param {string} type The type slug
|
|
459
481
|
* @param {object} [params] Extra query parameters
|
|
460
482
|
* @param {string|null} [id] Optional object ID
|
|
483
|
+
* @param {string|null} [schema] Schema path segment to use instead of the type's own
|
|
461
484
|
* @return {string} Full API URL path including query string
|
|
462
485
|
*/
|
|
463
|
-
_buildUrlWithParams(type, params = {}, id = null) {
|
|
486
|
+
_buildUrlWithParams(type, params = {}, id = null, schema = null) {
|
|
464
487
|
const config = this._getTypeConfig(type);
|
|
465
|
-
let url = `${this._options.baseUrl}/${config.register}/${config.schema}`;
|
|
488
|
+
let url = `${this._options.baseUrl}/${config.register}/${schema ?? config.schema}`;
|
|
466
489
|
if (id) {
|
|
467
490
|
url += `/${id}`;
|
|
468
491
|
}
|
|
@@ -472,6 +495,54 @@ const baseActions = {
|
|
|
472
495
|
return url
|
|
473
496
|
},
|
|
474
497
|
|
|
498
|
+
/**
|
|
499
|
+
* Fetch for a type, retrying ONCE with its `schemaFallback` when the
|
|
500
|
+
* schema path segment answers 404. A type without a fallback (every type
|
|
501
|
+
* not registered by `resolveObjectOpType` for a kebab-cased title) makes
|
|
502
|
+
* exactly the one request it always made. When the retry succeeds the
|
|
503
|
+
* fallback becomes the type's schema, so later calls go straight to it;
|
|
504
|
+
* when it does not, the first answer is returned and nothing changes.
|
|
505
|
+
*
|
|
506
|
+
* @spec openspec/changes/zuiddrecht-pixel-gaps-2/specs/zuiddrecht-pixel-gaps-2/spec.md#requirement-a-schema-title-falls-back-to-its-written-form
|
|
507
|
+
* @param {string} type The type slug
|
|
508
|
+
* @param {function((string|null)): string} makeUrl Builds the URL; called with
|
|
509
|
+
* null for the type's own schema, or with the fallback segment.
|
|
510
|
+
* @param {object} init The fetch options.
|
|
511
|
+
* @return {Promise<Response>} The response to use.
|
|
512
|
+
*/
|
|
513
|
+
async _fetchWithSchemaFallback(type, makeUrl, init) {
|
|
514
|
+
// `makeUrl` wraps `_buildUrl` / `_buildUrlWithParams`, so `url` is built
|
|
515
|
+
// from the prefixed `_options.baseUrl` like every other request here.
|
|
516
|
+
let url = makeUrl(null);
|
|
517
|
+
const response = await fetch(url, init);
|
|
518
|
+
if (!response || response.status !== 404) {
|
|
519
|
+
return response
|
|
520
|
+
}
|
|
521
|
+
const config = this.objectTypeRegistry[type];
|
|
522
|
+
const fallback = config && config.schemaFallback;
|
|
523
|
+
if (!fallback || String(fallback) === String(config.schema)) {
|
|
524
|
+
return response
|
|
525
|
+
}
|
|
526
|
+
let retry;
|
|
527
|
+
try {
|
|
528
|
+
url = makeUrl(fallback);
|
|
529
|
+
retry = await fetch(url, init);
|
|
530
|
+
} catch {
|
|
531
|
+
return response
|
|
532
|
+
}
|
|
533
|
+
if (!retry || !retry.ok) {
|
|
534
|
+
discardResponseBody(retry);
|
|
535
|
+
return response
|
|
536
|
+
}
|
|
537
|
+
discardResponseBody(response);
|
|
538
|
+
const { schemaFallback: _, ...rest } = config;
|
|
539
|
+
this.objectTypeRegistry = {
|
|
540
|
+
...this.objectTypeRegistry,
|
|
541
|
+
[type]: { ...rest, schema: fallback },
|
|
542
|
+
};
|
|
543
|
+
return retry
|
|
544
|
+
},
|
|
545
|
+
|
|
475
546
|
/**
|
|
476
547
|
* Clear the error state for a type.
|
|
477
548
|
*
|
|
@@ -604,12 +675,14 @@ const baseActions = {
|
|
|
604
675
|
}
|
|
605
676
|
}
|
|
606
677
|
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
678
|
+
const response = await this._fetchWithSchemaFallback(
|
|
679
|
+
type,
|
|
680
|
+
(schema) => this._buildUrlWithParams(type, fetchParams, null, schema),
|
|
681
|
+
{
|
|
682
|
+
method: 'GET',
|
|
683
|
+
headers: this._buildHeaders(),
|
|
684
|
+
},
|
|
685
|
+
);
|
|
613
686
|
|
|
614
687
|
if (!response.ok) {
|
|
615
688
|
this.errors = { ...this.errors, [type]: await parseResponseError(response, type) };
|
|
@@ -675,11 +748,14 @@ const baseActions = {
|
|
|
675
748
|
*/
|
|
676
749
|
async fetchCollectionForOptions(type, params = {}) {
|
|
677
750
|
try {
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
751
|
+
const response = await this._fetchWithSchemaFallback(
|
|
752
|
+
type,
|
|
753
|
+
(schema) => this._buildUrlWithParams(type, params, null, schema),
|
|
754
|
+
{
|
|
755
|
+
method: 'GET',
|
|
756
|
+
headers: this._buildHeaders(),
|
|
757
|
+
},
|
|
758
|
+
);
|
|
683
759
|
|
|
684
760
|
if (!response.ok) {
|
|
685
761
|
discardResponseBody(response);
|
|
@@ -734,10 +810,14 @@ const baseActions = {
|
|
|
734
810
|
this.errors = { ...this.errors, [type]: null };
|
|
735
811
|
|
|
736
812
|
try {
|
|
737
|
-
const response = await
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
813
|
+
const response = await this._fetchWithSchemaFallback(
|
|
814
|
+
type,
|
|
815
|
+
(schema) => (schema === null ? url : this._buildUrl(type, id, schema)),
|
|
816
|
+
{
|
|
817
|
+
method: 'GET',
|
|
818
|
+
headers: this._buildHeaders(),
|
|
819
|
+
},
|
|
820
|
+
);
|
|
741
821
|
|
|
742
822
|
if (!response.ok) {
|
|
743
823
|
this.errors = { ...this.errors, [type]: await parseResponseError(response, type) };
|
|
@@ -805,16 +885,19 @@ const baseActions = {
|
|
|
805
885
|
|
|
806
886
|
try {
|
|
807
887
|
const isUpdate = !!objectData.id;
|
|
808
|
-
const url = isUpdate
|
|
809
|
-
? this._buildUrl(type, objectData.id)
|
|
810
|
-
: this._buildUrl(type);
|
|
811
888
|
const method = isUpdate ? 'PUT' : 'POST';
|
|
812
889
|
|
|
813
|
-
const response = await
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
890
|
+
const response = await this._fetchWithSchemaFallback(
|
|
891
|
+
type,
|
|
892
|
+
(schema) => (isUpdate
|
|
893
|
+
? this._buildUrl(type, objectData.id, schema)
|
|
894
|
+
: this._buildUrl(type, null, schema)),
|
|
895
|
+
{
|
|
896
|
+
method,
|
|
897
|
+
headers: this._buildHeaders(),
|
|
898
|
+
body: JSON.stringify(objectData),
|
|
899
|
+
},
|
|
900
|
+
);
|
|
818
901
|
|
|
819
902
|
if (!response.ok) {
|
|
820
903
|
this.errors = { ...this.errors, [type]: await parseResponseError(response, type) };
|
|
@@ -866,12 +949,14 @@ const baseActions = {
|
|
|
866
949
|
this.errors = { ...this.errors, [type]: null };
|
|
867
950
|
|
|
868
951
|
try {
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
952
|
+
const response = await this._fetchWithSchemaFallback(
|
|
953
|
+
type,
|
|
954
|
+
(schema) => this._buildUrl(type, id, schema),
|
|
955
|
+
{
|
|
956
|
+
method: 'DELETE',
|
|
957
|
+
headers: this._buildHeaders(),
|
|
958
|
+
},
|
|
959
|
+
);
|
|
875
960
|
|
|
876
961
|
if (!response.ok) {
|
|
877
962
|
this.errors = { ...this.errors, [type]: await parseResponseError(response, type) };
|