@things-factory/auth-ui 8.0.0-beta.1 → 8.0.0-beta.4

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.
Files changed (59) hide show
  1. package/package.json +4 -4
  2. package/client/auth-style-sign.ts +0 -194
  3. package/client/bootstrap.ts +0 -51
  4. package/client/components/abstract-auth-page.ts +0 -301
  5. package/client/components/abstract-password-reset.ts +0 -163
  6. package/client/components/abstract-sign.ts +0 -127
  7. package/client/components/change-password.ts +0 -153
  8. package/client/components/contact-us.ts +0 -116
  9. package/client/components/create-domain-popup.ts +0 -141
  10. package/client/components/create-role.ts +0 -123
  11. package/client/components/create-user.ts +0 -117
  12. package/client/components/credential-manager.ts +0 -64
  13. package/client/components/delete-user-popup.ts +0 -117
  14. package/client/components/domain-switch.ts +0 -127
  15. package/client/components/invite-customer.ts +0 -104
  16. package/client/components/invite-user.ts +0 -104
  17. package/client/components/my-login-history.ts +0 -101
  18. package/client/components/ownership-transfer-popup.ts +0 -110
  19. package/client/components/partner-info-card.ts +0 -89
  20. package/client/components/partner-role-editor.ts +0 -153
  21. package/client/components/profile-component.ts +0 -392
  22. package/client/components/role-edit-form.ts +0 -92
  23. package/client/components/role-privilege-editor.ts +0 -268
  24. package/client/components/role-selector.ts +0 -102
  25. package/client/components/user-role-editor.ts +0 -499
  26. package/client/constants/application.ts +0 -9
  27. package/client/constants/index.ts +0 -1
  28. package/client/entries/auth/activate.ts +0 -272
  29. package/client/entries/auth/checkin.ts +0 -190
  30. package/client/entries/auth/forgot-password.ts +0 -112
  31. package/client/entries/auth/reset-password.ts +0 -22
  32. package/client/entries/auth/result.ts +0 -193
  33. package/client/entries/auth/signin.ts +0 -18
  34. package/client/entries/auth/signup.ts +0 -115
  35. package/client/entries/auth/unlock-user.ts +0 -22
  36. package/client/entries/oauth2/oauth2-decision-error-page.ts +0 -50
  37. package/client/entries/oauth2/oauth2-decision-page.ts +0 -196
  38. package/client/entries/public/home.ts +0 -246
  39. package/client/index.ts +0 -124
  40. package/client/pages/app-binding/app-binding.ts +0 -423
  41. package/client/pages/app-binding/app-bindings.ts +0 -171
  42. package/client/pages/appliance/appliance.ts +0 -452
  43. package/client/pages/appliance/home.ts +0 -177
  44. package/client/pages/appliance/register.ts +0 -183
  45. package/client/pages/application/application.ts +0 -428
  46. package/client/pages/application/applications.ts +0 -182
  47. package/client/pages/application/register.ts +0 -211
  48. package/client/pages/attribute/attribute-set-item-list.ts +0 -237
  49. package/client/pages/attribute/attribute-set-management.ts +0 -282
  50. package/client/pages/auth-provider/auth-provider-management.ts +0 -381
  51. package/client/pages/domain/domain-management.ts +0 -410
  52. package/client/pages/partner/partner-management.ts +0 -112
  53. package/client/pages/profile.ts +0 -32
  54. package/client/pages/role/role-management.ts +0 -134
  55. package/client/pages/user/user-management.ts +0 -223
  56. package/client/route.ts +0 -67
  57. package/client/themes/auth-theme.css +0 -65
  58. package/client/utils/password-rule.ts +0 -37
  59. package/server/index.ts +0 -0
@@ -1,123 +0,0 @@
1
- import '@material/web/textfield/filled-text-field.js'
2
-
3
- import gql from 'graphql-tag'
4
- import { css, html, LitElement } from 'lit'
5
- import { customElement, query } from 'lit/decorators.js'
6
-
7
- import { client, gqlContext } from '@operato/graphql'
8
- import { i18next, localize } from '@operato/i18n'
9
- import { OxPrompt } from '@operato/popup/ox-prompt.js'
10
-
11
- @customElement('create-role')
12
- class CreateRole extends localize(i18next)(LitElement) {
13
- static styles = css`
14
- :host {
15
- --md-text-field-fill-color: var(--md-sys-color-on-primary);
16
- background-color: var(--md-sys-color-surface);
17
- margin: var(--spacing-large) 0;
18
- padding: var(--spacing-large);
19
- border-radius: var(--border-radius);
20
- box-shadow: var(--box-shadow);
21
-
22
- display: grid;
23
- grid-template-columns: 1fr 2fr auto;
24
- gap: 5px 15px;
25
- clear: both;
26
- max-width: var(--input-container-max-width);
27
-
28
- align-items: center;
29
- }
30
-
31
- md-outlined-button {
32
- margin: var(--input-margin);
33
- text-transform: capitalize;
34
- }
35
-
36
- @media screen and (max-width: 480px) {
37
- :host {
38
- grid-template-columns: 1fr 1fr;
39
- }
40
-
41
- md-outlined-button {
42
- grid-column: span 2;
43
-
44
- margin: var(--input-margin);
45
- }
46
- }
47
- `
48
-
49
- @query('[name=name]') nameInput!: HTMLInputElement
50
- @query('[name=description]') descriptionInput!: HTMLInputElement
51
-
52
- render() {
53
- return html`
54
- <md-filled-text-field
55
- type="text"
56
- name="name"
57
- label=${String(i18next.t('label.x name', { x: i18next.t('label.role') }))}
58
- ></md-filled-text-field>
59
- <md-filled-text-field
60
- type="text"
61
- name="description"
62
- label=${String(i18next.t('label.x description', { x: i18next.t('label.role') }))}
63
- ></md-filled-text-field>
64
-
65
- <md-outlined-button @click=${this.onCreateRole.bind(this)}
66
- >${String(i18next.t('button.create'))}</md-outlined-button
67
- >
68
- `
69
- }
70
-
71
- async onCreateRole() {
72
- let role: { name?: string; description?: string } = {}
73
-
74
- const name = this.nameInput.value.trim()
75
- const description = this.descriptionInput.value
76
-
77
- if (!name) {
78
- return this.showToast(i18next.t('error.value is empty', { value: i18next.t('field.name') }))
79
- }
80
-
81
- role.name = name
82
- role.description = description
83
-
84
- if (
85
- await OxPrompt.open({
86
- title: i18next.t('text.are_you_sure'),
87
- text: i18next.t('text.do_you_want_to_create_x', { x: i18next.t('label.role') }),
88
- confirmButton: { text: i18next.t('button.confirm') },
89
- cancelButton: { text: i18next.t('button.cancel') }
90
- })
91
- ) {
92
- const response = await client.mutate({
93
- mutation: gql`
94
- mutation createRole($role: NewRole!) {
95
- createRole(role: $role) {
96
- name
97
- }
98
- }
99
- `,
100
- variables: { role },
101
- context: gqlContext()
102
- })
103
-
104
- if (!response.errors) {
105
- await this.dispatchEvent(new CustomEvent('fetch-roles'))
106
-
107
- await OxPrompt.open({
108
- type: 'success',
109
- title: i18next.t('text.completed'),
110
- text: i18next.t('text.data_uploaded_successfully'),
111
- confirmButton: { text: i18next.t('button.confirm') }
112
- })
113
-
114
- this.nameInput.value = ''
115
- this.descriptionInput.value = ''
116
- }
117
- }
118
- }
119
-
120
- showToast(message) {
121
- document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))
122
- }
123
- }
@@ -1,117 +0,0 @@
1
- import '@material/web/button/outlined-button.js'
2
- import '@material/web/textfield/filled-text-field.js'
3
-
4
- import { css, html, LitElement } from 'lit'
5
- import { customElement, query } from 'lit/decorators.js'
6
-
7
- import { i18next } from '@operato/i18n'
8
-
9
- function capitalize(str) {
10
- return str ? str.charAt(0).toUpperCase() + str.slice(1) : ''
11
- }
12
-
13
- @customElement('create-user')
14
- class CreateUser extends LitElement {
15
- static styles = css`
16
- :host {
17
- --md-text-field-fill-color: var(--md-sys-color-on-primary);
18
- background-color: var(--md-sys-color-surface);
19
- margin: var(--spacing-large) 0;
20
- padding: var(--spacing-large);
21
- border-radius: var(--border-radius);
22
- box-shadow: var(--box-shadow);
23
-
24
- display: grid;
25
- grid-template-columns: 1fr 2fr 2fr auto;
26
- gap: 5px 15px;
27
- clear: both;
28
- max-width: var(--input-container-max-width);
29
-
30
- align-items: center;
31
- }
32
-
33
- md-outlined-button {
34
- margin: var(--input-margin);
35
- }
36
-
37
- @media screen and (max-width: 480px) {
38
- :host {
39
- grid-template-columns: 1fr 1fr;
40
- }
41
-
42
- md-outlined-button {
43
- grid-column: span 2;
44
-
45
- margin: var(--input-margin);
46
- }
47
- }
48
- `
49
-
50
- @query('[name=name]') nameInput!: HTMLInputElement
51
- @query('[name=username]') usernameInput!: HTMLInputElement
52
- @query('[name=email]') emailInput!: HTMLInputElement
53
-
54
- render() {
55
- return html`
56
- <md-filled-text-field
57
- type="text"
58
- name="username"
59
- label=${capitalize(i18next.t('label.user-id'))}
60
- pattern="^(?:[A-Za-z0-9]*|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,})$"
61
- ><md-icon slot="leading-icon">badge</md-icon></md-filled-text-field
62
- >
63
-
64
- <md-filled-text-field
65
- type="text"
66
- name="name"
67
- label=${capitalize(i18next.t('label.x name', { x: i18next.t('label.user') }))}
68
- ><md-icon slot="leading-icon">id_card</md-icon></md-filled-text-field
69
- >
70
-
71
- <md-filled-text-field type="email" name="email" label=${capitalize(i18next.t('field.email'))}
72
- ><md-icon slot="leading-icon">mail</md-icon></md-filled-text-field
73
- >
74
-
75
- <md-outlined-button @click=${this.onCreateUser.bind(this)}
76
- >${capitalize(i18next.t('button.create'))}</md-outlined-button
77
- >
78
- `
79
- }
80
-
81
- async onCreateUser() {
82
- try {
83
- if (!this.usernameInput.value) {
84
- throw new Error(i18next.t('error.value is empty', { value: 'name' }))
85
- }
86
-
87
- if (!this.emailInput.checkValidity()) {
88
- throw new Error(i18next.t('error.not valid pattern of type', { type: 'e-mail' }))
89
- }
90
-
91
- if (!this.nameInput.value) {
92
- throw new Error(i18next.t('error.value is empty', { value: 'name' }))
93
- }
94
-
95
- const user = {
96
- username: this.usernameInput.value.trim(),
97
- name: this.nameInput.value.trim(),
98
- email: this.emailInput.value.trim()
99
- }
100
-
101
- await this.dispatchEvent(new CustomEvent('create-user', { detail: user }))
102
-
103
- this.usernameInput.value = ''
104
- this.nameInput.value = ''
105
- this.emailInput.value = ''
106
- } catch (e: any) {
107
- document.dispatchEvent(
108
- new CustomEvent('notify', {
109
- detail: {
110
- level: 'error',
111
- message: 'message' in e ? e.message : e
112
- }
113
- })
114
- )
115
- }
116
- }
117
- }
@@ -1,64 +0,0 @@
1
- import gql from 'graphql-tag'
2
- import { LitElement, html, css } from 'lit'
3
- import { customElement, property } from 'lit/decorators.js'
4
-
5
- import { client } from '@operato/graphql'
6
-
7
- @customElement('credential-manager')
8
- export class CredentialManager extends LitElement {
9
- @property({ type: Array }) credentials: {
10
- credentialId: string
11
- }[] = []
12
-
13
- static styles = css`
14
- div {
15
- margin: 20px;
16
- }
17
- button {
18
- margin: 5px;
19
- }
20
- `
21
-
22
- connectedCallback() {
23
- super.connectedCallback()
24
- this.fetchCredentials()
25
- }
26
-
27
- async fetchCredentials() {
28
- const response = await fetch('/auth/credentials', {
29
- method: 'GET',
30
- credentials: 'include'
31
- })
32
- this.credentials = await response.json()
33
- }
34
-
35
- async deleteCredential(credentialId: string) {
36
- const response = await fetch(`/credentials/${credentialId}`, {
37
- method: 'DELETE',
38
- credentials: 'include'
39
- })
40
- if (response.ok) {
41
- this.fetchCredentials()
42
- } else {
43
- console.error('Failed to delete credential')
44
- }
45
- }
46
-
47
- render() {
48
- return html`
49
- <div>
50
- <h2>Manage Your WebAuthn Credentials</h2>
51
- <ul>
52
- ${this.credentials.map(
53
- credential => html`
54
- <li>
55
- ${credential.credentialId}
56
- <button @click=${() => this.deleteCredential(credential.credentialId)}>Delete</button>
57
- </li>
58
- `
59
- )}
60
- </ul>
61
- </div>
62
- `
63
- }
64
- }
@@ -1,117 +0,0 @@
1
- import '@operato/i18n/ox-i18n.js'
2
-
3
- import { css, html, LitElement } from 'lit'
4
- import { customElement } from 'lit/decorators.js'
5
-
6
- import { i18next, localize } from '@operato/i18n'
7
- import { notify } from '@operato/layout'
8
- import { auth } from '@things-factory/auth-base/dist-client/auth.js'
9
-
10
- @customElement('delete-user-popup')
11
- export class DeleteUserPopup extends localize(i18next)(LitElement) {
12
- static styles = [
13
- css`
14
- :host {
15
- display: flex;
16
- flex-direction: column;
17
- color: var(--popup-content-color);
18
- background-color: var(--popup-content-background-color);
19
- padding: var(--popup-content-padding);
20
- }
21
-
22
- * {
23
- box-sizing: border-box;
24
- }
25
- *:focus {
26
- outline: none;
27
- }
28
-
29
- label {
30
- font: bold 14px var(--theme-font);
31
- color: var(--md-sys-color-primary);
32
- }
33
-
34
- input {
35
- border: var(--change-password-field-border);
36
- border-radius: var(--change-password-field-border-radius);
37
- padding: var(--change-password-field-padding);
38
-
39
- font: var(--change-password-field-font);
40
- width: var(--change-password-field-width);
41
- }
42
- input:focus {
43
- border: 1px solid var(--focus-background-color);
44
- }
45
-
46
- div.field {
47
- padding-bottom: 10px;
48
- }
49
-
50
- ::placeholder {
51
- font-size: 0.8rem;
52
- text-transform: capitalize;
53
- }
54
-
55
- button {
56
- background-color: var(--status-danger-color, #d14946);
57
- margin: 2px 2px 10px 2px;
58
- height: var(--button-height, 28px);
59
- color: var(--button-color, #fff);
60
- font: var(--button-font);
61
- border-radius: var(--button-radius, 5px);
62
- border: var(--button-border, 1px solid transparent);
63
- line-height: 1.5;
64
- }
65
- button:hover,
66
- button:active {
67
- background-color: var(--button-active-background-color, #22a6a7);
68
- border: var(--button-active-border);
69
- }
70
- `
71
- ]
72
-
73
- render() {
74
- return html`
75
- <h1><ox-i18n msgid="label.delete account"></ox-i18n></h1>
76
- <span><ox-i18n msgid="text.delete account warning message"></ox-i18n></span>
77
- <form @submit=${e => this.submit(e)}>
78
- <div class="field">
79
- <label for="email"><ox-i18n msgid="label.email"></ox-i18n></label>
80
- <input id="email" type="email" name="email" autocapitalize="off" required />
81
- <label for="password"><ox-i18n msgid="label.password"></ox-i18n></label>
82
- <input id="password" type="password" name="password" required />
83
- </div>
84
-
85
- <button class="ui button" type="submit"><ox-i18n msgid="label.delete account"></ox-i18n></button>
86
- </form>
87
- `
88
- }
89
-
90
- async submit(e: Event) {
91
- e.preventDefault()
92
-
93
- const form = e.target as HTMLFormElement
94
-
95
- var params = {}
96
- new FormData(form).forEach((value, key) => {
97
- params[key] = value
98
- })
99
-
100
- try {
101
- const message = await auth.deleteUser(params)
102
- notify({
103
- level: 'info',
104
- message
105
- })
106
-
107
- auth.signout()
108
- } catch (e: any) {
109
- form.reset()
110
-
111
- notify({
112
- level: 'error',
113
- message: 'message' in e ? e.message : e
114
- })
115
- }
116
- }
117
- }
@@ -1,127 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
-
3
- import { css, html, LitElement, nothing } from 'lit'
4
- import { customElement, property } from 'lit/decorators.js'
5
- import { connect } from 'pwa-helpers/connect-mixin'
6
-
7
- import { store } from '@operato/shell'
8
- import { ScrollbarStyles } from '@operato/styles'
9
-
10
- @customElement('domain-switch')
11
- export class DomainSwitch extends connect(store)(LitElement) {
12
- static styles = [
13
- ScrollbarStyles,
14
- css`
15
- :host {
16
- display: flex;
17
- max-width: 100%;
18
- background-color: var(--md-sys-color-primary-container, rgb(215 231 241));
19
- border-bottom: var(--border-dim-color);
20
- }
21
-
22
- :host * {
23
- vertical-align: middle;
24
- }
25
-
26
- div {
27
- flex: 1;
28
- display: flex;
29
- flex-direction: row;
30
- padding: var(--spacing-small);
31
- }
32
-
33
- md-icon {
34
- background-color: var(--md-sys-color-primary, rgb(46 121 190));
35
- margin-right: var(--spacing-small);
36
- padding: 2px;
37
- border-radius: 50%;
38
- font-size: var(--fontsize-large);
39
- color: var(--md-sys-color-on-primary, rgba(255,255,255,.9));
40
- }
41
- span,
42
- select {
43
- flex: 1;
44
- color: var(--md-sys-color-on-primary-container, rgb(50 66 82));
45
- font: bold 14px/20px var(--theme-font);
46
- }
47
-
48
- select {
49
- border: none;
50
- background-color: transparent;
51
- }
52
-
53
- select:focus {
54
- outline: 0;
55
- }
56
- :host([dark]) {
57
- background-color: rgba(0, 0, 0, 0.2);
58
- padding: 0 !important;
59
- border-bottom: none;
60
- }
61
- :host([dark]) md-icon {
62
- background-color: var(--secondary-text-color);
63
- margin: 1px 4px 0px 0px;
64
- padding: 1px 2px;
65
- border-radius: 50%;
66
- line-height: 19px;
67
- }
68
- :host([dark]) span,
69
- :host([dark]) select {
70
- color: var(--md-sys-color-on-primary);
71
- font: bold 13px/13px var(--theme-font);
72
- }
73
- :host([dark]) option {
74
- background-color: var(--primary-color, #585858);
75
- color: var(--md-sys-color-on-primary, #fff);
76
- }
77
- :host([dark]) span {
78
- line-height: 23px;
79
- }
80
-
81
- :host([rounded-corner]) {
82
- height: 30px;
83
- border-radius: 20px;
84
- border: var(--border-dim-color);
85
- }
86
- :host([rounded-corner]) div {
87
- padding: var(--spacing-small) var(--spacing-medium);
88
- }
89
- `
90
- ]
91
-
92
- @property({ type: Array }) domains: any[] = []
93
- @property({ type: Object }) domain: any
94
- @property({ type: String, attribute: true }) attrname: string = 'name'
95
- @property({ type: String, attribute: true }) icon?: string
96
-
97
- render() {
98
- const domains = this.domains || []
99
- const domain = this.domain || {}
100
- const attrname = this.attrname || 'name'
101
-
102
- return html`
103
- <div>
104
- ${this.icon ? html`<md-icon>${this.icon}</md-icon>` : nothing}
105
- ${domains.length <= 1
106
- ? html` <span>${domains[0]?.[attrname] || domain.name}</span> `
107
- : html`
108
- <select
109
- .value=${domain.subdomain}
110
- @change=${e => (window.location.pathname = `/auth/checkin/${e.target.value}`)}
111
- >
112
- ${domains.map(
113
- d => html`
114
- <option .value=${d.subdomain} ?selected=${d.subdomain == domain.subdomain}>${d[attrname]}</option>
115
- `
116
- )}
117
- </select>
118
- `}
119
- </div>
120
- `
121
- }
122
-
123
- stateChanged(state) {
124
- this.domains = state.app.domains
125
- this.domain = state.app.domain
126
- }
127
- }
@@ -1,104 +0,0 @@
1
- import gql from 'graphql-tag'
2
- import { css, html, LitElement } from 'lit'
3
- import { customElement, property, query } from 'lit/decorators.js'
4
-
5
- import { client, gqlContext } from '@operato/graphql'
6
- import { i18next, localize } from '@operato/i18n'
7
- import { OxPrompt } from '@operato/popup/ox-prompt.js'
8
-
9
- @customElement('invite-customer')
10
- class InviteCustomer extends localize(i18next)(LitElement) {
11
- static styles = [
12
- css`
13
- input {
14
- border: var(--border-dim-color);
15
- border-radius: var(--border-radius);
16
- margin: var(--input-margin);
17
- padding: var(--input-padding);
18
- min-width: 250px;
19
- font: var(--input-font);
20
- }
21
- md-outlined-button {
22
- margin: var(--input-margin);
23
- }
24
- @media screen and (max-width: 480px) {
25
- div {
26
- display: grid;
27
- }
28
- }
29
- `
30
- ]
31
-
32
- @property({ type: Array }) customers: any[] = []
33
-
34
- @query('input#customer-name') customerNameInput!: HTMLInputElement
35
-
36
- render() {
37
- return html`
38
- <div>
39
- <input id="customer-name" required />
40
- <md-outlined-button @click=${this.invite.bind(this)}>
41
- <md-icon slot="icon">group_add</md-icon>
42
- ${String(i18next.t('label.invite customer'))}
43
- </md-outlined-button>
44
- </div>
45
- `
46
- }
47
-
48
- async invite() {
49
- try {
50
- if (!this.customerNameInput.value)
51
- throw new Error(i18next.t('error.value is empty', { value: i18next.t('field.name') }))
52
-
53
- if (this.customers.find(c => c.name?.toLowerCase() === this.customerNameInput.value.toLowerCase())) {
54
- throw new Error(
55
- i18next.t('error.x already exists in y', { x: this.customerNameInput.value, y: i18next.t('field.customer') })
56
- )
57
- }
58
-
59
- if (
60
- await OxPrompt.open({
61
- title: i18next.t('text.are_you_sure'),
62
- text: i18next.t('text.do_you_want_to_invite_x', { x: i18next.t(`label.partner`) }),
63
- confirmButton: { text: i18next.t('button.confirm') },
64
- cancelButton: { text: i18next.t('button.cancel') }
65
- })
66
- ) {
67
- const customerDomainName = this.customerNameInput.value
68
-
69
- const response = await client.mutate({
70
- mutation: gql`
71
- mutation inviteCustomer($customerDomainName: String!) {
72
- inviteCustomer(customerDomainName: $customerDomainName)
73
- }
74
- `,
75
- variables: { customerDomainName },
76
- context: gqlContext()
77
- })
78
-
79
- if (!response.errors) {
80
- const answer = this.dispatchEvent(new CustomEvent('invitationCompleted'))
81
-
82
- if (answer) {
83
- await OxPrompt.open({
84
- type: 'success',
85
- title: i18next.t('text.completed'),
86
- confirmButton: { text: i18next.t('button.confirm') }
87
- })
88
- }
89
-
90
- this.customerNameInput.value = ''
91
- }
92
- }
93
- } catch (e: any) {
94
- document.dispatchEvent(
95
- new CustomEvent('notify', {
96
- detail: {
97
- level: 'error',
98
- message: 'message' in e ? e.message : e
99
- }
100
- })
101
- )
102
- }
103
- }
104
- }