@wssto2/vue-core 0.5.1 → 0.5.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.2 — 2026-10-13
4
+
5
+ Access for service accounts, a working "turn on all", worded constraints, and this browser's push state for an app's own screens. Found by ARV's moves to the library's access and notifications.
6
+
7
+ ### Changed (no backward compatibility)
8
+ - **Access takes the subject's kind.** `accessFeature({ subjects: { service: { base, bindable } } })` says where an application serves the routes of a kind other than `user` (`${base}/:id/{access,scopes,bindings,bindings/:binding_id}`, in go-core's wire). `PersonAccess` and *Add role* read and write there; a kind with no entry is refused with an error that names it, never sent to the user routes. `createAccessApi(http, subjects)` takes the entries, and its `bindable(subject, level, scopeId)` now takes the subject first.
9
+
10
+ ### New
11
+ - **`usePushState()`** from `/notifications`: `ready`, `available`, `permission`, `subscribed`, `busy`, `enable()`, `disable()`, built on the settings page's own state. `subscribed` is true as soon as `ready` for a browser that already has push on. Type `PushState`.
12
+
13
+ ### Fixed
14
+ - **Turn on all** granted only part of a module: it read "all on" inside its loop, and once the closures had granted everything the rest were revoked again.
15
+ - **Constraints are worded.** A role's constraints on a person's roles (`BindingRow`) use the `roleConstraints` option labels ("Used only"); an attribute or value with no label stays `attribute: value`.
16
+
17
+ ### Docs
18
+ - The access recipe gains subjects and constraint labels; the notifications recipe gains `usePushState` and loses the stale "devices and push permission are not in these screens".
19
+
3
20
  ## 0.5.1 — 2026-10-13
4
21
 
5
22
  One renewal, sessions that do not renew, and the language before the first page. Found by ARV's move to the library's sign-in.
@@ -4,7 +4,7 @@ import { i as k } from "./error-Bb_dr_Ay.js";
4
4
  import { u as V, _ as N } from "./CollectionPage.vue_vue_type_script_setup_true_lang-l-e-6WeS.js";
5
5
  import { u as P } from "./describeError-BqGAUZgX.js";
6
6
  import { u as I } from "./format-D8X4zsx6.js";
7
- import { e as a, R as O } from "./index-BTRv8mcf.js";
7
+ import { e as a, R as O } from "./index-BPwfLD7i.js";
8
8
  import { _ as W } from "./AlertDialog.vue_vue_type_script_setup_true_lang-whA4WLdl.js";
9
9
  import { t as i } from "./toast-CqSDTWRX.js";
10
10
  import { u as Y } from "./useLoad-W4tfxmm5.js";
@@ -4,8 +4,8 @@ import { useRoute as k, useRouter as R } from "vue-router";
4
4
  import { a as $ } from "./AdaptivePageShell.vue_vue_type_script_setup_true_lang-GUTIXuNd.js";
5
5
  import { _ as b } from "./AsyncSection.vue_vue_type_script_setup_true_lang-B0NfvG3B.js";
6
6
  import { u as g } from "./useLoad-W4tfxmm5.js";
7
- import { a as x, c as u } from "./index-VPzJJN6Z.js";
8
- import { _ as P } from "./RoleEditor.vue_vue_type_script_setup_true_lang-BqqilJGF.js";
7
+ import { a as x, c as u } from "./index-BVlbcaKs.js";
8
+ import { _ as P } from "./RoleEditor.vue_vue_type_script_setup_true_lang-BGtyOyWL.js";
9
9
  const V = /* @__PURE__ */ _({
10
10
  __name: "NewRolePage",
11
11
  setup(h) {
@@ -10,7 +10,7 @@ import { u as ne } from "./useSaveChrome-7huA3FzR.js";
10
10
  import { t as le } from "./toast-CqSDTWRX.js";
11
11
  import { _ as E } from "./Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js";
12
12
  import { _ as R } from "./Banner.vue_vue_type_script_setup_true_lang-DSStj_5z.js";
13
- import { d as W, u as G, p as re, o as T, r as K, g as M, s as ie, e as ce, a as ue, f as de, b as me, h as fe } from "./index-VPzJJN6Z.js";
13
+ import { d as W, u as G, p as re, o as T, r as K, g as M, s as ie, e as ce, a as ue, f as de, b as me, h as fe } from "./index-BVlbcaKs.js";
14
14
  import { _ as pe } from "./Button.vue_vue_type_script_setup_true_lang-CL9Qh5yq.js";
15
15
  import { _ as _e } from "./Tabs.vue_vue_type_script_setup_true_lang-CcMcE38r.js";
16
16
  import { _ as ve } from "./SegmentedField.vue_vue_type_script_setup_true_lang-BwyMvkis.js";
@@ -50,9 +50,10 @@ const ke = {
50
50
  return { granted: s.filter((e) => e in c.grants).length, total: s.length };
51
51
  }, B = (a) => `${w(a).granted} / ${w(a).total}`, L = k(() => l.value.map((a) => ({ value: a.key, label: u.groupLabel(a.key), badge: B(a.key) }))), P = k(() => i.value !== void 0 && w(i.value.key).granted === w(i.value.key).total);
52
52
  function m() {
53
- if (i.value)
54
- for (const a of b(i.value.key))
55
- P.value ? K(o, c.grants, a) : M(o, c.grants, a);
53
+ if (!i.value) return;
54
+ const a = P.value;
55
+ for (const s of b(i.value.key))
56
+ a ? K(o, c.grants, s) : M(o, c.grants, s);
56
57
  }
57
58
  const U = (a) => [...new Set(a.permissions.map((s) => s.ownable).filter((s) => s !== null))], N = k(() => ["own", "own_location", "all"].map((a) => ({ value: a, label: u.qualifierLabel(a) })));
58
59
  function $(a, s) {
@@ -12,11 +12,11 @@ import { a as le, u as se } from "./routeResource-CcYA75T2.js";
12
12
  import { a as re } from "./ResourcePage.vue_vue_type_script_setup_true_lang-BFBGvevP.js";
13
13
  import { _ as ce } from "./AsyncSection.vue_vue_type_script_setup_true_lang-B0NfvG3B.js";
14
14
  import { _ as H } from "./Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js";
15
- import { u as O, a as U, f as ne, i as ie, d as ue, b as M, c as T } from "./index-VPzJJN6Z.js";
15
+ import { u as O, a as U, f as ne, i as ie, d as ue, b as M, c as T } from "./index-BVlbcaKs.js";
16
16
  import { _ as J } from "./SelectField.vue_vue_type_script_setup_true_lang-BzQC1qDQ.js";
17
17
  import { u as me, _ as pe } from "./useCommand-CtqheKUv.js";
18
18
  import { _ as de } from "./Modal.vue_vue_type_script_setup_true_lang-DpBb8ans.js";
19
- import { _ as fe } from "./RoleEditor.vue_vue_type_script_setup_true_lang-BqqilJGF.js";
19
+ import { _ as fe } from "./RoleEditor.vue_vue_type_script_setup_true_lang-BGtyOyWL.js";
20
20
  const _e = { "data-test": "role-replace" }, ve = /* @__PURE__ */ I({
21
21
  __name: "ReplaceRoleDialog",
22
22
  props: {
@@ -11,7 +11,7 @@ import { u as K } from "./platform-Dx6STiwY.js";
11
11
  import { _ as T } from "./AsyncSection.vue_vue_type_script_setup_true_lang-B0NfvG3B.js";
12
12
  import { _ as q } from "./Badge.vue_vue_type_script_setup_true_lang-DJyZc0C7.js";
13
13
  import { u as z } from "./useLoad-W4tfxmm5.js";
14
- import { u as G, a as H, b as J, c as x } from "./index-VPzJJN6Z.js";
14
+ import { u as G, a as H, b as J, c as x } from "./index-BVlbcaKs.js";
15
15
  const M = {
16
16
  class: "flex min-w-0 flex-col gap-group-gap",
17
17
  "data-test": "roles-index"
@@ -5,7 +5,7 @@ import { a as oe } from "./AdaptivePageShell.vue_vue_type_script_setup_true_lang
5
5
  import { t as C } from "./toast-CqSDTWRX.js";
6
6
  import { u as U } from "./fieldMessages-DTXpWnBd.js";
7
7
  import { _ as W } from "./AsyncSection.vue_vue_type_script_setup_true_lang-B0NfvG3B.js";
8
- import { n as T, u as le, a as re } from "./index-BTRv8mcf.js";
8
+ import { n as T, u as le, a as re } from "./index-BPwfLD7i.js";
9
9
  import { _ as H } from "./SectionIntro.vue_vue_type_script_setup_true_lang-CZtPrmXD.js";
10
10
  import { _ as j } from "./Button.vue_vue_type_script_setup_true_lang-CL9Qh5yq.js";
11
11
  import { _ as ce } from "./IconTile.vue_vue_type_script_setup_true_lang-_FXvaj93.js";
@@ -1,11 +1,12 @@
1
1
  import type { HttpClient } from "../client";
2
2
  import type { BindInput, CreateRoleInput, UpdateRoleInput } from "../modules/access/schemas";
3
- import type { SubjectRef } from "../modules/access/entities";
3
+ import type { Binding, ScopeOptions, SubjectAccess, SubjectRef } from "../modules/access/entities";
4
+ import type { AccessSubjects } from "./context";
4
5
  type Options = {
5
6
  readonly signal?: AbortSignal;
6
7
  };
7
- /** go-core's access routes as calls; `data` of each answer already read. */
8
- export declare function createAccessApi(http: HttpClient): {
8
+ /** go-core's access routes as calls; `data` of each answer already read. A subject of another kind than `user` goes to `subjects[kind]`. */
9
+ export declare function createAccessApi(http: HttpClient, subjects?: AccessSubjects): {
9
10
  roles: (options?: Options) => Promise<import(".").RoleSummary[]>;
10
11
  role: (ref: string, options?: Options) => Promise<import(".").Role>;
11
12
  holders: (ref: string, options?: Options) => Promise<import(".").RoleHolder[]>;
@@ -14,10 +15,10 @@ export declare function createAccessApi(http: HttpClient): {
14
15
  update: (input: UpdateRoleInput) => Promise<import(".").Role>;
15
16
  remove: (ref: string) => Promise<undefined>;
16
17
  replace: (ref: string, other: string) => Promise<number>;
17
- access: (subject: SubjectRef, options?: Options) => Promise<import(".").SubjectAccess>;
18
- scopes: (subject: SubjectRef, options?: Options) => Promise<import(".").ScopeOptions>;
19
- bindable: (level: string, scopeId: number | null, options?: Options) => Promise<import(".").Role[]>;
20
- bind: (subject: SubjectRef, input: Omit<BindInput, "id">) => Promise<import(".").Binding>;
18
+ access: (subject: SubjectRef, options?: Options) => Promise<SubjectAccess>;
19
+ scopes: (subject: SubjectRef, options?: Options) => Promise<ScopeOptions>;
20
+ bindable: (subject: SubjectRef, level: string, scopeId: number | null, options?: Options) => Promise<import(".").Role[]>;
21
+ bind: (subject: SubjectRef, input: Omit<BindInput, "id">) => Promise<Binding>;
21
22
  unbind: (subject: SubjectRef, bindingId: number) => Promise<undefined>;
22
23
  };
23
24
  export type AccessApi = ReturnType<typeof createAccessApi>;
@@ -2,6 +2,12 @@ import type { RouteLocationRaw } from "vue-router";
2
2
  import type { ScopeOptions, SubjectRef } from "../modules/access/entities";
3
3
  import type { PermissionCatalogue } from "./catalogue";
4
4
  import type { RoleConstraint } from "./constraints";
5
+ /** Where an application serves the access routes of a subject kind other than `user`: `${base}/:id/{access,scopes,bindings,bindings/:binding_id}`, and the roles it may be given. */
6
+ export interface SubjectRoutes {
7
+ readonly base: string;
8
+ readonly bindable: string;
9
+ }
10
+ export type AccessSubjects = Readonly<Partial<Record<Exclude<SubjectRef["kind"], "user">, SubjectRoutes>>>;
5
11
  /** What the access screens need from the feature that installed them. */
6
12
  export interface AccessContext {
7
13
  readonly catalogue: PermissionCatalogue;
@@ -12,6 +18,7 @@ export interface AccessContext {
12
18
  readonly constraints: readonly RoleConstraint[];
13
19
  /** The i18n key of the sentence for each of the application's own role-problem codes (`authz.invalid`). */
14
20
  readonly problems: Readonly<Record<string, string>>;
21
+ readonly subjects: AccessSubjects;
15
22
  readonly scopes: ((subject: SubjectRef, signal: AbortSignal) => Promise<ScopeOptions>) | null;
16
23
  }
17
24
  export declare const accessContextKey: import("vue").InjectionKey<AccessContext>, useAccessContext: () => AccessContext;
@@ -4,6 +4,7 @@ import type { ScopeOptions, SubjectRef } from "../modules/access/entities";
4
4
  import type { Destination } from "../router";
5
5
  import type { PermissionCatalogue } from "./catalogue";
6
6
  import type { RoleConstraint } from "./constraints";
7
+ import { type AccessSubjects } from "./context";
7
8
  export interface AccessFeatureOptions {
8
9
  /**
9
10
  * The application's permissions: the `permissions` object go-core's `authzts` writes (`frontend/generated/permissions.ts`).
@@ -30,6 +31,13 @@ export interface AccessFeatureOptions {
30
31
  * accessFeature({ catalogue, problems: { vehicle_kind_conflict: "roles.problems.vehicle_kind_conflict" } })
31
32
  */
32
33
  problems?: Readonly<Record<string, string>>;
34
+ /**
35
+ * Where the routes of a subject kind other than `user` are (go-core leaves them to the application); the paths answer in go-core's own wire.
36
+ * `PersonAccess` and the add dialog with such a subject read and write there. Without an entry the subject is refused, never sent to the user routes.
37
+ *
38
+ * accessFeature({ catalogue, subjects: { service: { base: "/v1/iam/service-accounts", bindable: "/v1/iam/service-accounts/bindable-roles" } } })
39
+ */
40
+ subjects?: AccessSubjects;
33
41
  /** The backend's navigation destination that opens the roles list. Without it the application links to `accessPages.roles` itself. */
34
42
  destination?: Destination;
35
43
  }
@@ -1,4 +1,4 @@
1
- import { _ as a, j as c, k as r, c as o, b as u, l as i, m as n, p as l, n as t, q as m, t as p, u as R, i as b, f as d } from "../index-VPzJJN6Z.js";
1
+ import { _ as a, j as c, k as r, c as o, b as u, l as i, m as n, p as l, n as t, q as m, t as p, u as R, i as b, f as d } from "../index-BVlbcaKs.js";
2
2
  export {
3
3
  a as BindingRow,
4
4
  c as PersonAccess,
@@ -28,6 +28,11 @@ export declare function useAccessLabels(): {
28
28
  levelLabel: (level: string) => string;
29
29
  /** A place: the level and its name (`Dealer · Auto Zagreb`); the root, which has no name, by its level. */
30
30
  scopeLabel: (scope: ScopeName) => string;
31
+ /** A role's constraint as the application worded it (`Used only`); an attribute or value it gave no text for stays as `attribute: value`. */
32
+ constraintLabel: (attr: {
33
+ attribute: string;
34
+ values: readonly string[];
35
+ }) => string;
31
36
  roleKind: (role: {
32
37
  predefined: boolean;
33
38
  computed: boolean;