@api-client/ui 0.6.6 → 0.6.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@api-client/ui",
3
- "version": "0.6.6",
3
+ "version": "0.6.8",
4
4
  "description": "Internal UI component library for the API Client ecosystem.",
5
5
  "license": "UNLICENSED",
6
6
  "main": "build/src/index.js",
@@ -85,7 +85,7 @@ export default class OrganizationSelector extends LitElement {
85
85
  }
86
86
 
87
87
  protected override render(): unknown {
88
- return html`<span class="container">${this.renderTrigger()} ${this.renderMenu()}</span>`
88
+ return html`${this.renderTrigger()} ${this.renderMenu()}`
89
89
  }
90
90
 
91
91
  protected renderTrigger(): TemplateResult {
@@ -97,7 +97,7 @@ export default class OrganizationSelector extends LitElement {
97
97
  aria-label="Current organization: ${orgName}"
98
98
  trailingicon
99
99
  color="tonal"
100
- popoverTarget="org-selector-menu"
100
+ popovertarget="org-selector-menu"
101
101
  >
102
102
  ${orgName}
103
103
  <ui-icon slot="icon">arrow_drop_down</ui-icon>
@@ -131,6 +131,9 @@ export default class BaseButton extends UiElement {
131
131
  /**
132
132
  * Turns a `<ui-button>` element into a popover control button; takes the ID
133
133
  * of the popover element to control as its value.
134
+ *
135
+ * Note: this is required for now as the spec only allows to control popovers
136
+ * via buttons. Custom elements are not allowed to control popovers.
134
137
  * @attribute
135
138
  */
136
139
  @property({ type: String, reflect: true }) accessor popoverTarget: string | undefined
@@ -146,7 +149,7 @@ export default class BaseButton extends UiElement {
146
149
  * it will be shown; if the popover is showing, it will be hidden. If popoverTargetAction is omitted,
147
150
  * "toggle" is the default action that will be performed by the control button.
148
151
  */
149
- @property({ type: String, reflect: true }) accessor popoverTargetAction: string | undefined
152
+ @property({ type: String, reflect: true }) accessor popoverTargetAction: 'hide' | 'show' | 'toggle' | undefined
150
153
  /**
151
154
  * When true, the focus ring effect will be constrained to the inside of the button's bounds.
152
155
  * @attribute
@@ -312,6 +315,7 @@ export default class BaseButton extends UiElement {
312
315
  } else if (action === 'show') {
313
316
  element.showPopover()
314
317
  } else {
318
+ // default to toggle
315
319
  element.togglePopover()
316
320
  }
317
321
  element.focus()
@@ -34,10 +34,15 @@ export default class DomainAutoFieldsDialog extends LitElement {
34
34
  name: 'Name',
35
35
  description: 'A human-readable name for the record.',
36
36
  },
37
+ {
38
+ id: 'display-name',
39
+ name: 'Display Name',
40
+ description: 'A user-friendly label for UI presentation.',
41
+ },
37
42
  {
38
43
  id: 'description',
39
44
  name: 'Description',
40
- description: 'A detailed description of the record.',
45
+ description: 'A detailed description of the record with support for markdown.',
41
46
  },
42
47
  {
43
48
  id: 'public-unique-name',
@@ -54,6 +59,11 @@ export default class DomainAutoFieldsDialog extends LitElement {
54
59
  name: 'Email Address',
55
60
  description: 'Email address with verification support.',
56
61
  },
62
+ {
63
+ id: 'role',
64
+ name: 'User Role',
65
+ description: 'Defines the access level or permissions for a user.',
66
+ },
57
67
  {
58
68
  id: 'first-name',
59
69
  name: 'First Name',
@@ -131,21 +141,6 @@ export default class DomainAutoFieldsDialog extends LitElement {
131
141
  },
132
142
  ],
133
143
  },
134
- {
135
- name: 'Session & Security',
136
- fields: [
137
- {
138
- id: 'session-id',
139
- name: 'Session ID',
140
- description: 'Unique identifier for user sessions.',
141
- },
142
- {
143
- id: 'expires-at',
144
- name: 'Expires At',
145
- description: 'When a session or token expires.',
146
- },
147
- ],
148
- },
149
144
  {
150
145
  name: 'Audit Trail',
151
146
  fields: [
@@ -56,9 +56,74 @@ export default class OrganizationService extends Service {
56
56
  protected override async onCreate(): Promise<void> {
57
57
  const url = new URL(window.location.href)
58
58
  this.pendingOid = url.searchParams.get('oid')
59
+ this.revalidate()
59
60
  }
60
61
 
61
- async getUserOrganization(id: string): Promise<IOrganization> {
62
+ /**
63
+ * @deprecated Use #setOrganization instead
64
+ */
65
+ setupUserOrganization(org: IOrganization): Promise<void> {
66
+ return this.setOrganization(org)
67
+ }
68
+
69
+ /**
70
+ * Sets an org as the current user org.
71
+ * @param org The organization to add.
72
+ */
73
+ async setOrganization(org: IOrganization): Promise<void> {
74
+ const hasOrg = this.organizations.some((i) => i.key === org.key)
75
+ if (!hasOrg) {
76
+ this.organizations.push(org)
77
+ }
78
+ const config = await services.get('config')
79
+ await config.local.set(CurrentOrganizationKey, org.key)
80
+ this.organizationId = org.key
81
+ }
82
+
83
+ /**
84
+ * Adds an organization to the list of organizations.
85
+ * It also updated the cache. Used when creating a new org.
86
+ * @param org The organization to add.
87
+ */
88
+ async addOrganization(org: IOrganization): Promise<void> {
89
+ const hasOrg = this.organizations.some((i) => i.key === org.key)
90
+ if (!hasOrg) {
91
+ this.organizations.push(org)
92
+ await this.#saveCache()
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Removes an organization from the list of organizations.
98
+ * It also updated the cache. Used when deleting an org.
99
+ * @param org The organization to remove.
100
+ */
101
+ async removeOrganization(org: IOrganization): Promise<void> {
102
+ const idx = this.organizations.findIndex((i) => i.key === org.key)
103
+ if (idx !== -1) {
104
+ this.organizations.splice(idx, 1)
105
+ await this.#saveCache()
106
+ if (this.organizationId === org.key) {
107
+ this.organizationId = undefined
108
+ const config = await services.get('config')
109
+ await config.local.delete(CurrentOrganizationKey)
110
+ }
111
+ }
112
+ }
113
+
114
+ /**
115
+ * @deprecated Use #readOrganization instead
116
+ */
117
+ getUserOrganization(id: string): Promise<IOrganization> {
118
+ return this.readOrganization(id)
119
+ }
120
+
121
+ /**
122
+ * Reads an organization from the list of organizations.
123
+ * @param id The organization ID.
124
+ * @returns The organization.
125
+ */
126
+ async readOrganization(id: string): Promise<IOrganization> {
62
127
  await this.#updateComplete
63
128
  const org = this.organizations.find((i) => i.key === id)
64
129
  if (!org) {
@@ -67,6 +132,10 @@ export default class OrganizationService extends Service {
67
132
  return org
68
133
  }
69
134
 
135
+ /**
136
+ * Gets the current user organization.
137
+ * @returns The current organization or undefined if not set.
138
+ */
70
139
  async currentOrganization(): Promise<IOrganization | undefined> {
71
140
  if (this.state === State.Checking) {
72
141
  await this.#updateComplete
@@ -74,11 +143,14 @@ export default class OrganizationService extends Service {
74
143
  if (!this.organizationId) {
75
144
  return undefined
76
145
  }
77
- // TODO: we will store the orgs list in the local/session store
78
- // so we won't be pinging server with every page reload.
79
146
  return this.organizations.find((i) => i.key === this.organizationId)
80
147
  }
81
148
 
149
+ /**
150
+ * Checks if the user has a specific grant type in the current organization.
151
+ * @param grantType The grant type to check.
152
+ * @returns `true` if the user has the specified grant type, `false` otherwise.
153
+ */
82
154
  protected async hasGrantType(grantType: UserOrganizationGrantType): Promise<boolean> {
83
155
  const org = await this.currentOrganization()
84
156
  if (!org) {
@@ -87,6 +159,11 @@ export default class OrganizationService extends Service {
87
159
  return org.grantType === grantType
88
160
  }
89
161
 
162
+ /**
163
+ * Checks if the user has any of the specified grant types in the current organization.
164
+ * @param types The grant types to check.
165
+ * @returns `true` if the user has any of the specified grant types, `false` otherwise.
166
+ */
90
167
  async hasRoles(types: UserOrganizationGrantType[]): Promise<boolean> {
91
168
  const org = await this.currentOrganization()
92
169
  if (!org) {
@@ -135,9 +212,6 @@ export default class OrganizationService extends Service {
135
212
  if (this.state === State.Checking) {
136
213
  return this.#updateComplete as Promise<CompletionState>
137
214
  }
138
- if (this.organizationId) {
139
- return Promise.resolve(CompletionState.OK)
140
- }
141
215
  this.state = State.Checking
142
216
  this.#updateComplete = new Promise<CompletionState>((resolver) => {
143
217
  this.#updateResolver = resolver
@@ -175,12 +249,12 @@ export default class OrganizationService extends Service {
175
249
  return false
176
250
  }
177
251
 
178
- async #saveCache(orgs: IOrganization[]): Promise<void> {
252
+ async #saveCache(): Promise<void> {
179
253
  const cache = await services.get('cache')
180
- if (orgs.length === 0) {
254
+ if (this.organizations.length === 0) {
181
255
  await cache.delete(OrgsCacheKey)
182
256
  } else {
183
- await cache.set<IOrganization[]>(OrgsCacheKey, orgs, cache.TTL.OneHour)
257
+ await cache.set<IOrganization[]>(OrgsCacheKey, this.organizations, cache.TTL.OneHour)
184
258
  }
185
259
  }
186
260
 
@@ -188,7 +262,7 @@ export default class OrganizationService extends Service {
188
262
  const sdk = await services.get('sdk')
189
263
  const orgs = await sdk.organizations.list()
190
264
  this.organizations = orgs.items || []
191
- await this.#saveCache(orgs.items)
265
+ await this.#saveCache()
192
266
  }
193
267
 
194
268
  #resolve(state: CompletionState): void {
@@ -220,19 +294,4 @@ export default class OrganizationService extends Service {
220
294
  }
221
295
  return result
222
296
  }
223
-
224
- /**
225
- * When the user has no organizations, it set the organization as the only one
226
- * and persists the organization id as the selected organization.
227
- * @param org The organization to add.
228
- */
229
- async setupUserOrganization(org: IOrganization): Promise<void> {
230
- const hasOrg = this.organizations.some((i) => i.key === org.key)
231
- if (!hasOrg) {
232
- this.organizations.push(org)
233
- }
234
- const config = await services.get('config')
235
- await config.local.set(CurrentOrganizationKey, org.key)
236
- this.organizationId = org.key
237
- }
238
297
  }