@things-factory/auth-ui 8.0.5 → 8.0.13
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/client/bootstrap.ts +7 -3
- package/client/components/abstract-auth-page.ts +10 -10
- package/client/components/abstract-password-reset.ts +8 -13
- package/client/components/abstract-sign.ts +13 -13
- package/client/components/contact-us.ts +11 -8
- package/client/components/create-user.ts +27 -5
- package/client/components/invite-user.ts +18 -10
- package/client/components/ownership-transfer-popup.ts +3 -3
- package/client/components/profile-component.ts +64 -4
- package/client/components/user-role-editor.ts +18 -18
- package/client/entries/auth/checkin.ts +2 -9
- package/client/entries/auth/forgot-password.ts +2 -1
- package/client/entries/auth/signup.ts +13 -7
- package/client/index.ts +1 -1
- package/client/pages/domain/domain-management.ts +24 -3
- package/client/pages/user/user-management.ts +8 -9
- package/dist-client/bootstrap.d.ts +1 -1
- package/dist-client/bootstrap.js +2 -2
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/abstract-auth-page.js +10 -10
- package/dist-client/components/abstract-auth-page.js.map +1 -1
- package/dist-client/components/abstract-password-reset.d.ts +1 -2
- package/dist-client/components/abstract-password-reset.js +6 -13
- package/dist-client/components/abstract-password-reset.js.map +1 -1
- package/dist-client/components/abstract-sign.js +12 -11
- package/dist-client/components/abstract-sign.js.map +1 -1
- package/dist-client/components/contact-us.d.ts +1 -1
- package/dist-client/components/contact-us.js +10 -7
- package/dist-client/components/contact-us.js.map +1 -1
- package/dist-client/components/create-user.js +28 -5
- package/dist-client/components/create-user.js.map +1 -1
- package/dist-client/components/invite-user.js +19 -11
- package/dist-client/components/invite-user.js.map +1 -1
- package/dist-client/components/ownership-transfer-popup.js +3 -3
- package/dist-client/components/ownership-transfer-popup.js.map +1 -1
- package/dist-client/components/profile-component.d.ts +5 -1
- package/dist-client/components/profile-component.js +64 -4
- package/dist-client/components/profile-component.js.map +1 -1
- package/dist-client/components/user-role-editor.js +18 -18
- package/dist-client/components/user-role-editor.js.map +1 -1
- package/dist-client/entries/auth/checkin.d.ts +1 -1
- package/dist-client/entries/auth/checkin.js +5 -12
- package/dist-client/entries/auth/checkin.js.map +1 -1
- package/dist-client/entries/auth/forgot-password.js +2 -1
- package/dist-client/entries/auth/forgot-password.js.map +1 -1
- package/dist-client/entries/auth/signup.js +13 -7
- package/dist-client/entries/auth/signup.js.map +1 -1
- package/dist-client/index.js +1 -1
- package/dist-client/index.js.map +1 -1
- package/dist-client/pages/domain/domain-management.d.ts +2 -0
- package/dist-client/pages/domain/domain-management.js +20 -3
- package/dist-client/pages/domain/domain-management.js.map +1 -1
- package/dist-client/pages/user/user-management.d.ts +5 -1
- package/dist-client/pages/user/user-management.js +6 -7
- package/dist-client/pages/user/user-management.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/translations/en.json +4 -3
- package/translations/ja.json +4 -3
- package/translations/ko.json +4 -3
- package/translations/ms.json +4 -3
- package/translations/zh.json +4 -3
package/client/bootstrap.ts
CHANGED
|
@@ -7,12 +7,16 @@ import { html } from 'lit-html'
|
|
|
7
7
|
import { navigate, store } from '@operato/shell'
|
|
8
8
|
import { TOOL_POSITION } from '@operato/layout'
|
|
9
9
|
import { OxGristEditorPrivilege } from '@operato/app/grist-editor/ox-grist-editor-privilege.js'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
registerEditor as registerGristEditor,
|
|
12
|
+
registerRenderer as registerGristRenderer,
|
|
13
|
+
OxGristRendererJson5
|
|
14
|
+
} from '@operato/data-grist'
|
|
11
15
|
|
|
12
16
|
import { auth } from '@things-factory/auth-base/dist-client/auth.js'
|
|
13
17
|
import { ADD_MORENDA } from '@things-factory/more-base/client'
|
|
14
18
|
|
|
15
|
-
export default function bootstrap() {
|
|
19
|
+
export default async function bootstrap() {
|
|
16
20
|
registerGristEditor('privilege', OxGristEditorPrivilege)
|
|
17
21
|
registerGristRenderer('privilege', OxGristRendererJson5)
|
|
18
22
|
|
|
@@ -47,5 +51,5 @@ export default function bootstrap() {
|
|
|
47
51
|
As soon as response received, auth.on('profile', ...) handlers start to work.
|
|
48
52
|
It's very important point to build UI for the user.
|
|
49
53
|
*/
|
|
50
|
-
auth.profile()
|
|
54
|
+
await auth.profile()
|
|
51
55
|
}
|
|
@@ -176,22 +176,22 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
get formfields() {
|
|
179
|
-
const
|
|
180
|
-
// .validationMessage=${String(i18next.t('text.invalid-
|
|
179
|
+
const username = this.data?.username || ''
|
|
180
|
+
// .validationMessage=${String(i18next.t('text.invalid-username'))}
|
|
181
181
|
|
|
182
182
|
return html`
|
|
183
183
|
<input id="redirectTo" type="hidden" name="redirectTo" .value=${this.redirectTo || '/'} />
|
|
184
184
|
|
|
185
185
|
<div class="field">
|
|
186
186
|
<md-filled-text-field
|
|
187
|
-
name="
|
|
188
|
-
type="
|
|
189
|
-
label=${String(i18next.t('field.email'))}
|
|
187
|
+
name="username"
|
|
188
|
+
type="text"
|
|
189
|
+
label=${String(i18next.t('field.user-id or email'))}
|
|
190
190
|
required
|
|
191
|
-
.value=${
|
|
191
|
+
.value=${username}
|
|
192
192
|
autocomplete="off"
|
|
193
193
|
autocapitalize="off"
|
|
194
|
-
><md-icon slot="leading-icon">
|
|
194
|
+
><md-icon slot="leading-icon">id_card</md-icon></md-filled-text-field
|
|
195
195
|
>
|
|
196
196
|
</div>
|
|
197
197
|
<div class="field">
|
|
@@ -201,11 +201,11 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
|
|
|
201
201
|
label=${String(i18next.t('field.password'))}
|
|
202
202
|
autocomplete="off"
|
|
203
203
|
required
|
|
204
|
-
><md-icon slot="leading-icon">
|
|
204
|
+
><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
|
|
205
205
|
>
|
|
206
206
|
</div>
|
|
207
207
|
|
|
208
|
-
<md-elevated-button class="ui" type="
|
|
208
|
+
<md-elevated-button class="ui" type="button" raised @click=${e => this._onSubmit(e)}>
|
|
209
209
|
<ox-i18n msgid="field.${this.pageName}"> </ox-i18n>
|
|
210
210
|
</md-elevated-button>
|
|
211
211
|
`
|
|
@@ -235,7 +235,7 @@ export abstract class AbstractAuthPage extends localize(i18next)(LitElement) {
|
|
|
235
235
|
sso => html`
|
|
236
236
|
<a class="link" href=${sso.link}>
|
|
237
237
|
<md-text-button>
|
|
238
|
-
<md-icon slot="icon">
|
|
238
|
+
<md-icon slot="icon">id_card</md-icon>
|
|
239
239
|
${i18next.t('label.signin with', { title: sso.title })}
|
|
240
240
|
</md-text-button>
|
|
241
241
|
</a>
|
|
@@ -2,17 +2,16 @@ import '@material/web/icon/icon.js'
|
|
|
2
2
|
import '@material/web/button/elevated-button.js'
|
|
3
3
|
import '@material/web/textfield/filled-text-field.js'
|
|
4
4
|
|
|
5
|
-
import '@operato/lottie-player'
|
|
6
|
-
import '../components/profile-component'
|
|
7
5
|
import '@operato/i18n/ox-i18n.js'
|
|
8
6
|
import '@operato/i18n/ox-i18n-selector.js'
|
|
9
7
|
import '@operato/layout/ox-snack-bar.js'
|
|
10
8
|
|
|
9
|
+
import '../components/profile-component'
|
|
10
|
+
|
|
11
11
|
import { css, html, nothing } from 'lit'
|
|
12
12
|
import { property, query } from 'lit/decorators.js'
|
|
13
13
|
|
|
14
14
|
import { i18next } from '@operato/i18n'
|
|
15
|
-
import { isSafari } from '@operato/utils'
|
|
16
15
|
|
|
17
16
|
import { AUTH_STYLE_SIGN } from '../auth-style-sign'
|
|
18
17
|
import { generatePasswordPatternHelp, generatePasswordPatternRegExp } from '../utils/password-rule'
|
|
@@ -91,7 +90,8 @@ export abstract class AbstractPasswordReset extends AbstractAuthPage {
|
|
|
91
90
|
this.confirmPass.setAttribute('pattern', val.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '[$&]'))
|
|
92
91
|
}}
|
|
93
92
|
required
|
|
94
|
-
|
|
93
|
+
><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
|
|
94
|
+
>
|
|
95
95
|
</div>
|
|
96
96
|
|
|
97
97
|
<div class="field">
|
|
@@ -102,7 +102,8 @@ export abstract class AbstractPasswordReset extends AbstractAuthPage {
|
|
|
102
102
|
label=${String(i18next.t('field.confirm password'))}
|
|
103
103
|
autocomplete="off"
|
|
104
104
|
required
|
|
105
|
-
|
|
105
|
+
><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
|
|
106
|
+
>
|
|
106
107
|
</div>
|
|
107
108
|
|
|
108
109
|
<md-elevated-button id="submit-button" type="submit" @click=${e => this._onSubmit(e)}>
|
|
@@ -128,20 +129,14 @@ export abstract class AbstractPasswordReset extends AbstractAuthPage {
|
|
|
128
129
|
</form>
|
|
129
130
|
</div>
|
|
130
131
|
</div>
|
|
131
|
-
<ox-snack-bar id="snackbar" level="error" .message=${this.message}></ox-snack-bar>
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
? html``
|
|
135
|
-
: html`
|
|
136
|
-
<div class="lottie-container">
|
|
137
|
-
<lottie-player autoplay loop src="../../assets/images/background-animation.json"></lottie-player>
|
|
138
|
-
</div>
|
|
139
|
-
`}
|
|
133
|
+
<ox-snack-bar id="snackbar" level="error" .message=${this.message}></ox-snack-bar>
|
|
140
134
|
`
|
|
141
135
|
}
|
|
142
136
|
|
|
143
137
|
updated(changed) {
|
|
144
138
|
super.updated(changed)
|
|
139
|
+
|
|
145
140
|
if (changed.has('data')) {
|
|
146
141
|
this.token = this.data.token
|
|
147
142
|
}
|
|
@@ -44,7 +44,7 @@ export abstract class AbstractSign extends AbstractAuthPage {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
get formfields() {
|
|
47
|
-
const
|
|
47
|
+
const username = this.data?.username || ''
|
|
48
48
|
const autocompletable = this.autocompletable
|
|
49
49
|
|
|
50
50
|
return html`
|
|
@@ -52,22 +52,23 @@ export abstract class AbstractSign extends AbstractAuthPage {
|
|
|
52
52
|
|
|
53
53
|
<div class="field">
|
|
54
54
|
<md-filled-text-field
|
|
55
|
-
name="
|
|
56
|
-
type="
|
|
57
|
-
label=${String(i18next.t('field.email'))}
|
|
55
|
+
name="username"
|
|
56
|
+
type="text"
|
|
57
|
+
label=${String(i18next.t('field.user-id or email'))}
|
|
58
58
|
required
|
|
59
|
-
.value=${
|
|
60
|
-
autocomplete=${autocompletable ?
|
|
59
|
+
.value=${username}
|
|
60
|
+
autocomplete=${autocompletable ? 'username' : 'off'}
|
|
61
61
|
autocapitalize="off"
|
|
62
|
+
pattern="^(?:[A-Za-z0-9]*|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,})$"
|
|
62
63
|
@input=${(e: Event) => {
|
|
63
64
|
const target = e.target as HTMLInputElement
|
|
64
65
|
if (target.validity.typeMismatch) {
|
|
65
|
-
target.setCustomValidity(i18next.t('text.invalid-
|
|
66
|
+
target.setCustomValidity(i18next.t('text.invalid-username'))
|
|
66
67
|
} else {
|
|
67
68
|
target.setCustomValidity('')
|
|
68
69
|
}
|
|
69
70
|
}}
|
|
70
|
-
><md-icon slot="leading-icon">
|
|
71
|
+
><md-icon slot="leading-icon">id_card</md-icon></md-filled-text-field
|
|
71
72
|
>
|
|
72
73
|
</div>
|
|
73
74
|
<div class="field">
|
|
@@ -75,14 +76,14 @@ export abstract class AbstractSign extends AbstractAuthPage {
|
|
|
75
76
|
name="password"
|
|
76
77
|
type="password"
|
|
77
78
|
label=${String(i18next.t('field.password'))}
|
|
78
|
-
autocomplete=${autocompletable ?
|
|
79
|
+
autocomplete=${autocompletable ? 'current-password' : 'off'}
|
|
79
80
|
required
|
|
80
|
-
><md-icon slot="leading-icon">
|
|
81
|
+
><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
|
|
81
82
|
>
|
|
82
83
|
</div>
|
|
83
84
|
|
|
84
85
|
<div class="submit-buttons-container">
|
|
85
|
-
<md-elevated-button class="submit-button" type="
|
|
86
|
+
<md-elevated-button class="submit-button" type="button" raised @click=${e => this._onSubmit(e)}>
|
|
86
87
|
<ox-i18n msgid="field.${this.pageName}"> </ox-i18n>
|
|
87
88
|
</md-elevated-button>
|
|
88
89
|
${isAvailableWebauthn
|
|
@@ -106,7 +107,7 @@ export abstract class AbstractSign extends AbstractAuthPage {
|
|
|
106
107
|
|
|
107
108
|
if (verification.verified) {
|
|
108
109
|
const { redirectURL } = verification
|
|
109
|
-
|
|
110
|
+
|
|
110
111
|
if (redirectURL) {
|
|
111
112
|
window.location.href = redirectURL
|
|
112
113
|
}
|
|
@@ -116,7 +117,6 @@ export abstract class AbstractSign extends AbstractAuthPage {
|
|
|
116
117
|
message: verification.message
|
|
117
118
|
})
|
|
118
119
|
}
|
|
119
|
-
|
|
120
120
|
} catch (error) {
|
|
121
121
|
notify({
|
|
122
122
|
level: 'error',
|
|
@@ -33,22 +33,23 @@ export class ContactUs extends localize(i18next)(LitElement) {
|
|
|
33
33
|
]
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
@query('#dialog') dialog!: HTMLElement & {
|
|
36
|
+
@query('#dialog') dialog!: HTMLElement & { show: () => void }
|
|
37
37
|
@query('#subject-input') subjectInput!: HTMLInputElement
|
|
38
38
|
@query('#sender-input') senderInput!: HTMLInputElement
|
|
39
39
|
@query('#content-input') contentInput!: HTMLInputElement
|
|
40
40
|
|
|
41
41
|
render() {
|
|
42
42
|
return html`
|
|
43
|
-
<md-elevated-button @click=${e =>
|
|
43
|
+
<md-elevated-button @click=${e => this.dialog.show()}>${i18next.t('button.need help')}</md-elevated-button>
|
|
44
44
|
|
|
45
45
|
<md-dialog id="dialog" heading=${i18next.t('title.need help')}>
|
|
46
|
-
<form action="" method="
|
|
46
|
+
<form action="" method="post">
|
|
47
47
|
<input id="subject-input" name="subject" type="hidden" />
|
|
48
48
|
<input id="sender-input" name="sender" type="hidden" />
|
|
49
49
|
<input id="content-input" name="content" type="hidden" />
|
|
50
50
|
</form>
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
<div id="input-form" slot="content">
|
|
52
53
|
<md-filled-text-field
|
|
53
54
|
type="text"
|
|
54
55
|
label=${i18next.t('label.subject')}
|
|
@@ -59,6 +60,7 @@ export class ContactUs extends localize(i18next)(LitElement) {
|
|
|
59
60
|
this.subjectInput.value = val
|
|
60
61
|
}}
|
|
61
62
|
></md-filled-text-field>
|
|
63
|
+
|
|
62
64
|
<md-filled-text-field
|
|
63
65
|
type="text"
|
|
64
66
|
name="sender"
|
|
@@ -69,6 +71,7 @@ export class ContactUs extends localize(i18next)(LitElement) {
|
|
|
69
71
|
this.senderInput.value = val
|
|
70
72
|
}}
|
|
71
73
|
></md-filled-text-field>
|
|
74
|
+
|
|
72
75
|
<md-filled-text-field
|
|
73
76
|
name="content"
|
|
74
77
|
type="textarea"
|
|
@@ -80,11 +83,11 @@ export class ContactUs extends localize(i18next)(LitElement) {
|
|
|
80
83
|
this.contentInput.value = val
|
|
81
84
|
}}
|
|
82
85
|
></md-filled-text-field>
|
|
86
|
+
|
|
87
|
+
<md-elevated-button slot="primaryAction" type="button" @click=${e => this._submit(e)}
|
|
88
|
+
>${i18next.t('button.submit')}</md-elevated-button
|
|
89
|
+
>
|
|
83
90
|
</div>
|
|
84
|
-
<md-elevated-button slot="primaryAction" type="submit" @click=${e => this._submit(e)}
|
|
85
|
-
>${i18next.t('button.submit')}</md-elevated-button
|
|
86
|
-
>
|
|
87
|
-
<md-text-button slot="secondaryAction" dialogAction="cancel">${i18next.t('button.cancel')}</md-text-button>
|
|
88
91
|
</md-dialog>
|
|
89
92
|
`
|
|
90
93
|
}
|
|
@@ -6,6 +6,10 @@ import { customElement, query } from 'lit/decorators.js'
|
|
|
6
6
|
|
|
7
7
|
import { i18next } from '@operato/i18n'
|
|
8
8
|
|
|
9
|
+
function capitalize(str) {
|
|
10
|
+
return str ? str.charAt(0).toUpperCase() + str.slice(1) : ''
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
@customElement('create-user')
|
|
10
14
|
class CreateUser extends LitElement {
|
|
11
15
|
static styles = css`
|
|
@@ -18,7 +22,7 @@ class CreateUser extends LitElement {
|
|
|
18
22
|
box-shadow: var(--box-shadow);
|
|
19
23
|
|
|
20
24
|
display: grid;
|
|
21
|
-
grid-template-columns: 1fr 2fr auto;
|
|
25
|
+
grid-template-columns: 1fr 2fr 2fr auto;
|
|
22
26
|
gap: 5px 15px;
|
|
23
27
|
clear: both;
|
|
24
28
|
max-width: var(--input-container-max-width);
|
|
@@ -44,26 +48,42 @@ class CreateUser extends LitElement {
|
|
|
44
48
|
`
|
|
45
49
|
|
|
46
50
|
@query('[name=name]') nameInput!: HTMLInputElement
|
|
51
|
+
@query('[name=username]') usernameInput!: HTMLInputElement
|
|
47
52
|
@query('[name=email]') emailInput!: HTMLInputElement
|
|
48
53
|
|
|
49
54
|
render() {
|
|
50
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
|
+
|
|
51
64
|
<md-filled-text-field
|
|
52
65
|
type="text"
|
|
53
66
|
name="name"
|
|
54
|
-
label=${
|
|
55
|
-
|
|
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
|
+
>
|
|
56
70
|
|
|
57
|
-
<md-filled-text-field type="email" name="email" label=${
|
|
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
|
+
>
|
|
58
74
|
|
|
59
75
|
<md-outlined-button @click=${this.onCreateUser.bind(this)}
|
|
60
|
-
>${
|
|
76
|
+
>${capitalize(i18next.t('button.create'))}</md-outlined-button
|
|
61
77
|
>
|
|
62
78
|
`
|
|
63
79
|
}
|
|
64
80
|
|
|
65
81
|
async onCreateUser() {
|
|
66
82
|
try {
|
|
83
|
+
if (!this.usernameInput.value) {
|
|
84
|
+
throw new Error(i18next.t('error.value is empty', { value: 'name' }))
|
|
85
|
+
}
|
|
86
|
+
|
|
67
87
|
if (!this.emailInput.checkValidity()) {
|
|
68
88
|
throw new Error(i18next.t('error.not valid pattern of type', { type: 'e-mail' }))
|
|
69
89
|
}
|
|
@@ -73,12 +93,14 @@ class CreateUser extends LitElement {
|
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
const user = {
|
|
96
|
+
username: this.usernameInput.value.trim(),
|
|
76
97
|
name: this.nameInput.value.trim(),
|
|
77
98
|
email: this.emailInput.value.trim()
|
|
78
99
|
}
|
|
79
100
|
|
|
80
101
|
await this.dispatchEvent(new CustomEvent('create-user', { detail: user }))
|
|
81
102
|
|
|
103
|
+
this.usernameInput.value = ''
|
|
82
104
|
this.nameInput.value = ''
|
|
83
105
|
this.emailInput.value = ''
|
|
84
106
|
} catch (e: any) {
|
|
@@ -32,11 +32,19 @@ class InviteUser extends localize(i18next)(LitElement) {
|
|
|
32
32
|
}
|
|
33
33
|
`
|
|
34
34
|
|
|
35
|
-
@query('input[name=
|
|
35
|
+
@query('input[name=username]') userIdInput!: HTMLInputElement
|
|
36
36
|
|
|
37
37
|
render() {
|
|
38
38
|
return html`
|
|
39
|
-
<input
|
|
39
|
+
<input
|
|
40
|
+
name="username"
|
|
41
|
+
type="text"
|
|
42
|
+
required
|
|
43
|
+
name="username"
|
|
44
|
+
autocapitalize="off"
|
|
45
|
+
placeholder=${String(i18next.t('text.user invitation prompt'))}
|
|
46
|
+
pattern="^(?:[A-Za-z0-9]*|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,})$"
|
|
47
|
+
/>
|
|
40
48
|
<md-outlined-button @click=${this.invite.bind(this)}>
|
|
41
49
|
<md-icon slot="icon">group_add</md-icon>${String(i18next.t('label.invite user'))}
|
|
42
50
|
</md-outlined-button>
|
|
@@ -45,8 +53,8 @@ class InviteUser extends localize(i18next)(LitElement) {
|
|
|
45
53
|
|
|
46
54
|
async invite() {
|
|
47
55
|
try {
|
|
48
|
-
if (!this.
|
|
49
|
-
throw new Error(i18next.t('error.not valid pattern of type', { type: '
|
|
56
|
+
if (!this.userIdInput.checkValidity()) {
|
|
57
|
+
throw new Error(i18next.t('error.not valid pattern of type', { type: 'user-id or email' }))
|
|
50
58
|
}
|
|
51
59
|
|
|
52
60
|
if (
|
|
@@ -57,7 +65,7 @@ class InviteUser extends localize(i18next)(LitElement) {
|
|
|
57
65
|
cancelButton: { text: i18next.t('button.cancel') }
|
|
58
66
|
})
|
|
59
67
|
) {
|
|
60
|
-
await this.inviteUser(this.
|
|
68
|
+
await this.inviteUser(this.userIdInput.value)
|
|
61
69
|
|
|
62
70
|
this.dispatchEvent(new CustomEvent('invitationCompleted'))
|
|
63
71
|
}
|
|
@@ -73,14 +81,14 @@ class InviteUser extends localize(i18next)(LitElement) {
|
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
|
|
76
|
-
async inviteUser(
|
|
84
|
+
async inviteUser(username) {
|
|
77
85
|
const response = await client.mutate({
|
|
78
86
|
mutation: gql`
|
|
79
|
-
mutation inviteUser($
|
|
80
|
-
inviteUser(
|
|
87
|
+
mutation inviteUser($username: String!) {
|
|
88
|
+
inviteUser(username: $username)
|
|
81
89
|
}
|
|
82
90
|
`,
|
|
83
|
-
variables: {
|
|
91
|
+
variables: { username },
|
|
84
92
|
context: gqlContext()
|
|
85
93
|
})
|
|
86
94
|
|
|
@@ -90,7 +98,7 @@ class InviteUser extends localize(i18next)(LitElement) {
|
|
|
90
98
|
confirmButton: { text: i18next.t('button.confirm') }
|
|
91
99
|
})
|
|
92
100
|
|
|
93
|
-
this.
|
|
101
|
+
this.userIdInput.value = ''
|
|
94
102
|
}
|
|
95
103
|
}
|
|
96
104
|
}
|
|
@@ -75,11 +75,11 @@ class OwnershipTransferPopup extends localize(i18next)(LitElement) {
|
|
|
75
75
|
) {
|
|
76
76
|
const response = await client.mutate({
|
|
77
77
|
mutation: gql`
|
|
78
|
-
mutation transferOwner($
|
|
79
|
-
transferOwner(
|
|
78
|
+
mutation transferOwner($username: String!) {
|
|
79
|
+
transferOwner(username: $username)
|
|
80
80
|
}
|
|
81
81
|
`,
|
|
82
|
-
variables: {
|
|
82
|
+
variables: { username: this.user.username || this.user.email },
|
|
83
83
|
context: gqlContext()
|
|
84
84
|
})
|
|
85
85
|
|
|
@@ -111,7 +111,7 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
111
111
|
`
|
|
112
112
|
]
|
|
113
113
|
|
|
114
|
-
@property({ type: String })
|
|
114
|
+
@property({ type: String }) username?: string
|
|
115
115
|
@property({ type: String }) email?: string
|
|
116
116
|
@property({ type: String }) name?: string
|
|
117
117
|
|
|
@@ -128,7 +128,9 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
128
128
|
looseCharacterLength?: number
|
|
129
129
|
} = {}
|
|
130
130
|
|
|
131
|
+
@query('#username') usernameEl!: HTMLInputElement
|
|
131
132
|
@query('#name') nameEl!: HTMLInputElement
|
|
133
|
+
@query('#email') emailEl!: HTMLInputElement
|
|
132
134
|
@query('#locale') localeEl!: HTMLInputElement
|
|
133
135
|
|
|
134
136
|
async connectedCallback(): Promise<void> {
|
|
@@ -167,11 +169,11 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
167
169
|
|
|
168
170
|
setCredential(credential) {
|
|
169
171
|
if (credential) {
|
|
170
|
-
this.
|
|
172
|
+
this.username = credential.username
|
|
171
173
|
this.name = credential.name
|
|
172
174
|
this.email = credential.email
|
|
173
175
|
} else {
|
|
174
|
-
this.
|
|
176
|
+
this.username = ''
|
|
175
177
|
this.name = ''
|
|
176
178
|
this.email = ''
|
|
177
179
|
}
|
|
@@ -180,13 +182,23 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
180
182
|
render() {
|
|
181
183
|
return html`
|
|
182
184
|
<div class="wrap">
|
|
183
|
-
<div class="user">${this.
|
|
185
|
+
<div class="user">${this.username || ''}</div>
|
|
186
|
+
|
|
187
|
+
<label for="username"><ox-i18n slot="title" msgid="label.user-id"></ox-i18n></label>
|
|
188
|
+
<input id="username" @change=${e => this.onUsernameChanged(e.target.value)} .value=${this.username || ''} />
|
|
189
|
+
|
|
190
|
+
<hr />
|
|
184
191
|
|
|
185
192
|
<label for="name"><ox-i18n slot="title" msgid="label.name"></ox-i18n></label>
|
|
186
193
|
<input id="name" @change=${e => this.onNameChanged(e.target.value)} .value=${this.name || ''} />
|
|
187
194
|
|
|
188
195
|
<hr />
|
|
189
196
|
|
|
197
|
+
<label for="email"><ox-i18n slot="title" msgid="label.email"></ox-i18n></label>
|
|
198
|
+
<input id="email" type="email" @change=${e => this.onEmailChanged(e.target.value)} .value=${this.email || ''} />
|
|
199
|
+
|
|
200
|
+
<hr />
|
|
201
|
+
|
|
190
202
|
<label for="locale"><ox-i18n slot="title" msgid="label.language"></ox-i18n></label>
|
|
191
203
|
<ox-i18n-selector
|
|
192
204
|
id="locale"
|
|
@@ -223,6 +235,30 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
223
235
|
`
|
|
224
236
|
}
|
|
225
237
|
|
|
238
|
+
async onUsernameChanged(username) {
|
|
239
|
+
if (!username) return
|
|
240
|
+
|
|
241
|
+
var oldUsername = this.username
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
const message = await auth.updateProfile({
|
|
245
|
+
username
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
notify({
|
|
249
|
+
level: 'info',
|
|
250
|
+
message
|
|
251
|
+
})
|
|
252
|
+
} catch (e: any) {
|
|
253
|
+
this.usernameEl.value = oldUsername || ''
|
|
254
|
+
|
|
255
|
+
notify({
|
|
256
|
+
level: 'error',
|
|
257
|
+
message: 'message' in e ? e.message : e
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
226
262
|
async onNameChanged(name) {
|
|
227
263
|
if (!name) return
|
|
228
264
|
|
|
@@ -247,6 +283,30 @@ export class ProfileComponent extends localize(i18next)(LitElement) {
|
|
|
247
283
|
}
|
|
248
284
|
}
|
|
249
285
|
|
|
286
|
+
async onEmailChanged(email) {
|
|
287
|
+
if (!email) return
|
|
288
|
+
|
|
289
|
+
var oldEmail = this.email
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const message = await auth.updateProfile({
|
|
293
|
+
email
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
notify({
|
|
297
|
+
level: 'info',
|
|
298
|
+
message
|
|
299
|
+
})
|
|
300
|
+
} catch (e: any) {
|
|
301
|
+
this.emailEl.value = oldEmail || ''
|
|
302
|
+
|
|
303
|
+
notify({
|
|
304
|
+
level: 'error',
|
|
305
|
+
message: 'message' in e ? e.message : e
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
250
310
|
async onLocaleChanged(value) {
|
|
251
311
|
if (!value) return
|
|
252
312
|
|
|
@@ -113,8 +113,8 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
113
113
|
? html`
|
|
114
114
|
<li>
|
|
115
115
|
<span>
|
|
116
|
-
<md-icon>email</md-icon>
|
|
117
|
-
${user.email}
|
|
116
|
+
${user.username || user.email} (<md-icon>email</md-icon>
|
|
117
|
+
${user.email})
|
|
118
118
|
</span>
|
|
119
119
|
</li>
|
|
120
120
|
`
|
|
@@ -330,8 +330,8 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
330
330
|
if (user?.id) {
|
|
331
331
|
const response = await client.mutate({
|
|
332
332
|
mutation: gql`
|
|
333
|
-
mutation ($
|
|
334
|
-
updateUserRoles(
|
|
333
|
+
mutation ($username: String!, $availableRoles: [ObjectRef!]!, $selectedRoles: [ObjectRef!]!) {
|
|
334
|
+
updateUserRoles(username: $username, availableRoles: $availableRoles, selectedRoles: $selectedRoles) {
|
|
335
335
|
id
|
|
336
336
|
name
|
|
337
337
|
roles {
|
|
@@ -341,7 +341,7 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
343
|
`,
|
|
344
|
-
variables: {
|
|
344
|
+
variables: { username: user.username || user.email, availableRoles, selectedRoles },
|
|
345
345
|
context: gqlContext()
|
|
346
346
|
})
|
|
347
347
|
|
|
@@ -355,11 +355,11 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
355
355
|
async onActivate(user) {
|
|
356
356
|
const response = await client.mutate({
|
|
357
357
|
mutation: gql`
|
|
358
|
-
mutation activateUser($
|
|
359
|
-
activateUser(
|
|
358
|
+
mutation activateUser($username: String!) {
|
|
359
|
+
activateUser(username: $username)
|
|
360
360
|
}
|
|
361
361
|
`,
|
|
362
|
-
variables: {
|
|
362
|
+
variables: { username: user.username || user.email },
|
|
363
363
|
context: gqlContext()
|
|
364
364
|
})
|
|
365
365
|
|
|
@@ -373,16 +373,16 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
373
373
|
async onInactivate(user) {
|
|
374
374
|
const response = await client.mutate({
|
|
375
375
|
mutation: gql`
|
|
376
|
-
mutation inactivateUser($
|
|
377
|
-
inactivateUser(
|
|
376
|
+
mutation inactivateUser($username: String!) {
|
|
377
|
+
inactivateUser(username: $username)
|
|
378
378
|
}
|
|
379
379
|
`,
|
|
380
|
-
variables: {
|
|
380
|
+
variables: { username: user.username || user.email },
|
|
381
381
|
context: gqlContext()
|
|
382
382
|
})
|
|
383
383
|
|
|
384
384
|
if (!response.errors) {
|
|
385
|
-
this.showToast(i18next.t('text.user
|
|
385
|
+
this.showToast(i18next.t('text.user inactivated successfully'))
|
|
386
386
|
|
|
387
387
|
this.dispatchUserUpdated()
|
|
388
388
|
}
|
|
@@ -414,11 +414,11 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
414
414
|
) {
|
|
415
415
|
const response = await client.mutate({
|
|
416
416
|
mutation: gql`
|
|
417
|
-
mutation deleteDomaineUser($
|
|
418
|
-
deleteDomainUser(
|
|
417
|
+
mutation deleteDomaineUser($username: String!) {
|
|
418
|
+
deleteDomainUser(username: $username)
|
|
419
419
|
}
|
|
420
420
|
`,
|
|
421
|
-
variables: {
|
|
421
|
+
variables: { username: user.username || user.email },
|
|
422
422
|
context: gqlContext()
|
|
423
423
|
})
|
|
424
424
|
|
|
@@ -460,11 +460,11 @@ class UserRoleEditor extends connect(store)(LitElement) {
|
|
|
460
460
|
) {
|
|
461
461
|
const response = await client.mutate({
|
|
462
462
|
mutation: gql`
|
|
463
|
-
mutation resetPasswordToDefault($
|
|
464
|
-
resetPasswordToDefault(
|
|
463
|
+
mutation resetPasswordToDefault($username: String!) {
|
|
464
|
+
resetPasswordToDefault(username: $username)
|
|
465
465
|
}
|
|
466
466
|
`,
|
|
467
|
-
variables: {
|
|
467
|
+
variables: { username: user.username || user.email },
|
|
468
468
|
context: gqlContext()
|
|
469
469
|
})
|
|
470
470
|
|