@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,163 +0,0 @@
1
- import '@material/web/icon/icon.js'
2
- import '@material/web/button/elevated-button.js'
3
- import '@material/web/textfield/filled-text-field.js'
4
-
5
- import '@operato/i18n/ox-i18n.js'
6
- import '@operato/i18n/ox-i18n-selector.js'
7
- import '@operato/layout/ox-snack-bar.js'
8
-
9
- import '../components/profile-component'
10
-
11
- import { css, html, nothing } from 'lit'
12
- import { property, query } from 'lit/decorators.js'
13
-
14
- import { i18next } from '@operato/i18n'
15
-
16
- import { AUTH_STYLE_SIGN } from '../auth-style-sign'
17
- import { generatePasswordPatternHelp, generatePasswordPatternRegExp } from '../utils/password-rule'
18
- import { AbstractAuthPage } from './abstract-auth-page'
19
-
20
- export abstract class AbstractPasswordReset extends AbstractAuthPage {
21
- static styles = [
22
- css`
23
- :host {
24
- position: relative;
25
- overflow: hidden;
26
-
27
- display: flex;
28
- flex-direction: row;
29
-
30
- width: 100vw;
31
- height: 100vh;
32
- height: 100dvh;
33
- }
34
-
35
- @media print {
36
- :host {
37
- width: 100%;
38
- height: 100%;
39
- min-height: 100vh;
40
- min-height: 100dvh;
41
- }
42
- }
43
- `,
44
- AUTH_STYLE_SIGN
45
- ]
46
-
47
- @property({ type: Object }) data: any
48
- @property({ type: String }) token?: string
49
-
50
- @query('#confirm-password') confirmPass!: HTMLElement
51
-
52
- private passwordPattern: string = ''
53
- private passwordHelp: string = ''
54
-
55
- abstract get submitButtonLabel(): string
56
-
57
- render() {
58
- var { icon, title, description } = this.applicationMeta
59
- const { disableUserFavoredLanguage, languages } = this.data || {}
60
-
61
- return html`
62
- <div class="wrap">
63
- <div class="auth-brand">
64
- <img src=${icon} />
65
- <strong class="name">${title}</strong>
66
- <span class="welcome-msg">${description}</span>
67
- </div>
68
-
69
- <div class="auth-form">
70
- <h3><ox-i18n msgid="title.${this.title}"></ox-i18n></h3>
71
- <form
72
- id="form"
73
- action="${this.actionUrl}"
74
- method="post"
75
- @keypress=${e => {
76
- if (e.key == 'Enter') this._onSubmit(e)
77
- }}
78
- >
79
- <input name="token" type="hidden" .value=${this.token || ''} required />
80
- <div class="field">
81
- <md-filled-text-field
82
- name="password"
83
- type="password"
84
- label=${String(i18next.t('label.password'))}
85
- pattern=${this.passwordPattern || ''}
86
- supporting-text=${this.passwordHelp}
87
- autocomplete="off"
88
- @input=${e => {
89
- var val = e.target.value
90
- this.confirmPass.setAttribute('pattern', val.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '[$&]'))
91
- }}
92
- required
93
- ><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
94
- >
95
- </div>
96
-
97
- <div class="field">
98
- <md-filled-text-field
99
- id="confirm-password"
100
- name="confirm-password"
101
- type="password"
102
- label=${String(i18next.t('field.confirm password'))}
103
- autocomplete="off"
104
- required
105
- ><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
106
- >
107
- </div>
108
-
109
- <md-elevated-button id="submit-button" type="button" @click=${e => this._onSubmit(e)}>
110
- <ox-i18n msgid="${this.submitButtonLabel}"></ox-i18n>
111
- </md-elevated-button>
112
-
113
- ${!disableUserFavoredLanguage
114
- ? html` <div id="locale-area">
115
- <label for="locale-selector"><md-icon>language</md-icon></label>
116
- <ox-i18n-selector
117
- id="locale-selector"
118
- value=${i18next.language || 'en-US'}
119
- .languages=${languages}
120
- @change=${e => {
121
- var locale = e.detail
122
- if (!locale) return
123
-
124
- i18next.changeLanguage(locale)
125
- }}
126
- ></ox-i18n-selector>
127
- </div>`
128
- : nothing}
129
- </form>
130
- </div>
131
- </div>
132
-
133
- <ox-snack-bar id="snackbar" level="error" .message=${this.message}></ox-snack-bar>
134
- `
135
- }
136
-
137
- updated(changed) {
138
- super.updated(changed)
139
-
140
- if (changed.has('data')) {
141
- this.token = this.data.token
142
- }
143
-
144
- if (changed.has('message')) {
145
- if (!this.message) {
146
- this.hideSnackbar()
147
- } else {
148
- this.showSnackbar({
149
- timer: -1
150
- })
151
- }
152
- }
153
- }
154
-
155
- languageUpdated() {
156
- this.passwordPattern = generatePasswordPatternRegExp(this.data.passwordRule).source
157
- this.passwordHelp = generatePasswordPatternHelp(this.data.passwordRule)
158
- }
159
-
160
- async submit() {
161
- this.formEl.submit()
162
- }
163
- }
@@ -1,127 +0,0 @@
1
- import '@operato/i18n/ox-i18n.js'
2
-
3
- import { html, nothing } from 'lit'
4
- import { startAuthentication } from '@simplewebauthn/browser'
5
-
6
- import { i18next } from '@operato/i18n'
7
- import { notify } from '@operato/layout'
8
-
9
- import { AbstractAuthPage } from './abstract-auth-page.js'
10
-
11
- const isAvailableWebauthn = 'PublicKeyCredential' in window
12
-
13
- interface AssertionResponse {
14
- id: string
15
- rawId?: number[]
16
- response: {
17
- authenticatorData: string
18
- clientDataJSON: string
19
- signature: string
20
- userHandle: string | null
21
- }
22
- type: PublicKeyCredentialType
23
- authenticatorAttachment?: AuthenticatorAttachment
24
- }
25
-
26
- export abstract class AbstractSign extends AbstractAuthPage {
27
- async submit() {
28
- this.formEl.submit()
29
- }
30
-
31
- updated(changed) {
32
- super.updated(changed)
33
-
34
- if (changed.has('message')) {
35
- if (!this.message) {
36
- this.hideSnackbar()
37
- } else {
38
- this.showSnackbar({
39
- level: 'error',
40
- timer: -1
41
- })
42
- }
43
- }
44
- }
45
-
46
- get formfields() {
47
- const username = this.data?.username || ''
48
- const autocompletable = this.autocompletable
49
-
50
- return html`
51
- <input id="redirectTo" type="hidden" name="redirectTo" .value=${this.redirectTo || '/'} />
52
-
53
- <div class="field">
54
- <md-filled-text-field
55
- name="username"
56
- type="text"
57
- label=${String(i18next.t('field.user-id or email'))}
58
- required
59
- .value=${username}
60
- autocomplete=${autocompletable ? 'username' : 'off'}
61
- autocapitalize="off"
62
- pattern="^(?:[A-Za-z0-9]*|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Za-z]{2,})$"
63
- @input=${(e: Event) => {
64
- const target = e.target as HTMLInputElement
65
- if (target.validity.typeMismatch) {
66
- target.setCustomValidity(i18next.t('text.invalid-username'))
67
- } else {
68
- target.setCustomValidity('')
69
- }
70
- }}
71
- ><md-icon slot="leading-icon">id_card</md-icon></md-filled-text-field
72
- >
73
- </div>
74
- <div class="field">
75
- <md-filled-text-field
76
- name="password"
77
- type="password"
78
- label=${String(i18next.t('field.password'))}
79
- autocomplete=${autocompletable ? 'current-password' : 'off'}
80
- required
81
- ><md-icon slot="leading-icon">password</md-icon></md-filled-text-field
82
- >
83
- </div>
84
-
85
- <div class="submit-buttons-container">
86
- <md-elevated-button class="submit-button" type="button" raised @click=${e => this._onSubmit(e)}>
87
- <ox-i18n msgid="field.${this.pageName}"> </ox-i18n>
88
- </md-elevated-button>
89
- ${isAvailableWebauthn
90
- ? html` <md-icon class="fingerprint" raised @click=${e => this.authenticateUser()}> fingerprint </md-icon>`
91
- : nothing}
92
- </div>
93
- `
94
- }
95
-
96
- async authenticateUser() {
97
- try {
98
- const options = await fetch('/auth/signin-webauthn/challenge').then(res => res.json())
99
- const assertionResp = await startAuthentication(options)
100
- const verification = await fetch('/auth/signin-webauthn', {
101
- method: 'POST',
102
- headers: {
103
- 'Content-Type': 'application/json'
104
- },
105
- body: JSON.stringify(assertionResp)
106
- }).then(res => res.json())
107
-
108
- if (verification.verified) {
109
- const { redirectURL } = verification
110
-
111
- if (redirectURL) {
112
- window.location.href = redirectURL
113
- }
114
- } else {
115
- notify({
116
- level: 'error',
117
- message: verification.message
118
- })
119
- }
120
- } catch (error) {
121
- notify({
122
- level: 'error',
123
- message: i18next.t('error.authn verification failed')
124
- })
125
- }
126
- }
127
- }
@@ -1,153 +0,0 @@
1
- import { css, html, LitElement, PropertyValues } from 'lit'
2
- import { customElement, property, query } from 'lit/decorators.js'
3
-
4
- import { i18next, localize } from '@operato/i18n'
5
- import { auth } from '@things-factory/auth-base/dist-client/auth.js'
6
- import { generatePasswordPatternHelp, generatePasswordPatternRegExp } from '../utils/password-rule'
7
-
8
- @customElement('change-password')
9
- export class ChangePassword extends localize(i18next)(LitElement) {
10
- static styles = [
11
- css`
12
- * {
13
- box-sizing: border-box;
14
- }
15
-
16
- *:focus {
17
- outline: none;
18
- }
19
-
20
- form {
21
- display: flex;
22
- flex-direction: column;
23
- }
24
-
25
- input {
26
- border: var(--change-password-field-border);
27
- border-radius: var(--change-password-field-border-radius);
28
- margin: var(--change-password-field-margin);
29
- padding: var(--change-password-field-padding);
30
-
31
- font: var(--change-password-field-font);
32
- width: var(--change-password-field-width);
33
- }
34
-
35
- input:focus {
36
- border: 1px solid var(--focus-background-color);
37
- }
38
-
39
- ::placeholder {
40
- font-size: 0.8rem;
41
- text-transform: capitalize;
42
- }
43
-
44
- md-elevated-button {
45
- margin: var(--spacing-small) auto var(--spacing-medium) auto;
46
- text-transform: capitalize;
47
- }
48
-
49
- button {
50
- background-color: var(--secondary-color, #394e64);
51
- margin: 2px 2px 10px 2px;
52
- height: var(--button-height, 28px);
53
- color: var(--button-color, #fff);
54
- font: var(--button-font);
55
- border-radius: var(--button-radius, 5px);
56
- border: var(--button-border, 1px solid transparent);
57
- line-height: 1.5;
58
- }
59
-
60
- button:hover,
61
- button:active {
62
- background-color: var(--button-active-background-color, #22a6a7);
63
- border: var(--button-active-border);
64
- }
65
-
66
- .helper-text {
67
- font-size: 12px;
68
- color: var(--md-sys-color-) #6c757d;
69
- margin-top: 4px;
70
- display: block; /* 텍스트를 입력 필드 아래에 배치 */
71
- line-height: 1.5; /* 텍스트 줄 간격 조절 */
72
- }
73
- `
74
- ]
75
-
76
- @property({ type: Object }) passwordRule: {
77
- lowerCase?: boolean
78
- upperCase?: boolean
79
- digit?: boolean
80
- specialCharacter?: boolean
81
- allowRepeat?: boolean
82
- useTightPattern?: boolean
83
- useLoosePattern?: boolean
84
- tightCharacterLength?: number
85
- looseCharacterLength?: number
86
- } = {}
87
-
88
- @query('form') form!: HTMLFormElement
89
-
90
- private passwordPattern: string = ''
91
- private passwordHelp: string = ''
92
-
93
- render() {
94
- return html`
95
- <form>
96
- <div class="field">
97
- <input type="password" name="current_pass" placeholder=${i18next.t('text.current password')} required />
98
- </div>
99
- <span id="password-helper" class="helper-text">${this.passwordHelp}</span>
100
- <div class="field">
101
- <input
102
- type="password"
103
- name="new_pass"
104
- placeholder=${i18next.t('text.new password')}
105
- required
106
- pattern=${this.passwordPattern}
107
- aria-describedby="password-helper"
108
- />
109
- </div>
110
- <div class="field">
111
- <input type="password" name="confirm_pass" placeholder=${i18next.t('text.confirm password')} required />
112
- </div>
113
-
114
- <md-elevated-button @click=${this.submit.bind(this)}>${i18next.t('text.change password')}</md-elevated-button>
115
- </form>
116
- `
117
- }
118
-
119
- updated(changes: PropertyValues<this>) {
120
- if (changes.has('passwordRule')) {
121
- this.passwordPattern = generatePasswordPatternRegExp(this.passwordRule).source
122
- this.passwordHelp = generatePasswordPatternHelp(this.passwordRule)
123
- }
124
- }
125
-
126
- languageUpdated() {
127
- this.passwordPattern = generatePasswordPatternRegExp(this.passwordRule).source
128
- this.passwordHelp = generatePasswordPatternHelp(this.passwordRule)
129
- }
130
-
131
- async submit() {
132
- const formData = new FormData(this.form)
133
- let params = {}
134
- for (const [key, value] of formData.entries()) {
135
- if (!value) {
136
- const placeholder = (this.form.querySelector(`[name=${key}]`) as HTMLInputElement)?.placeholder
137
- return this.showToast(i18next.t('error.value is empty', { value: placeholder || key }))
138
- }
139
- params[key] = value
140
- }
141
-
142
- if (params['new_pass'] !== params['confirm_pass']) {
143
- return this.showToast(i18next.t('error.new-password-and-confirm-password-do-not-match'))
144
- }
145
-
146
- auth.changePassword(params)
147
- this.form.reset()
148
- }
149
-
150
- showToast(message) {
151
- document.dispatchEvent(new CustomEvent('notify', { detail: { message } }))
152
- }
153
- }
@@ -1,116 +0,0 @@
1
- import '@material/web/button/text-button.js'
2
- import '@material/web/button/elevated-button.js'
3
- import '@material/web/textfield/filled-text-field.js'
4
- import '@material/web/dialog/dialog.js'
5
-
6
- import '@operato/i18n'
7
-
8
- import { css, html, LitElement } from 'lit'
9
- import { customElement, query } from 'lit/decorators.js'
10
-
11
- import { i18next, localize } from '@operato/i18n'
12
- import { auth } from '@things-factory/auth-base/dist-client/auth.js'
13
-
14
- @customElement('contact-us')
15
- export class ContactUs extends localize(i18next)(LitElement) {
16
- static get styles() {
17
- return [
18
- css`
19
- * {
20
- box-sizing: border-box;
21
- }
22
-
23
- *:focus {
24
- outline: none;
25
- }
26
-
27
- #input-form {
28
- display: grid;
29
- grid-template-rows: 1fr 1fr 3fr;
30
- grid-gap: 10px 0;
31
- }
32
- `
33
- ]
34
- }
35
-
36
- @query('#dialog') dialog!: HTMLElement & { show: () => void }
37
- @query('#subject-input') subjectInput!: HTMLInputElement
38
- @query('#sender-input') senderInput!: HTMLInputElement
39
- @query('#content-input') contentInput!: HTMLInputElement
40
-
41
- render() {
42
- return html`
43
- <md-elevated-button @click=${e => this.dialog.show()}>${i18next.t('button.need help')}</md-elevated-button>
44
-
45
- <md-dialog id="dialog" heading=${i18next.t('title.need help')}>
46
- <form action="" method="post">
47
- <input id="subject-input" name="subject" type="hidden" />
48
- <input id="sender-input" name="sender" type="hidden" />
49
- <input id="content-input" name="content" type="hidden" />
50
- </form>
51
-
52
- <div id="input-form" slot="content">
53
- <md-filled-text-field
54
- type="text"
55
- label=${i18next.t('label.subject')}
56
- dialogInitialFocus
57
- required
58
- @input=${e => {
59
- const val = e.target.value
60
- this.subjectInput.value = val
61
- }}
62
- ></md-filled-text-field>
63
-
64
- <md-filled-text-field
65
- type="text"
66
- name="sender"
67
- label=${i18next.t('label.email')}
68
- required
69
- @input=${e => {
70
- const val = e.target.value
71
- this.senderInput.value = val
72
- }}
73
- ></md-filled-text-field>
74
-
75
- <md-filled-text-field
76
- name="content"
77
- type="textarea"
78
- label=${i18next.t('label.content')}
79
- required
80
- @keydown=${e => e.stopPropagation()}
81
- @input=${e => {
82
- const val = e.target.value
83
- this.contentInput.value = val
84
- }}
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
- >
90
- </div>
91
- </md-dialog>
92
- `
93
- }
94
-
95
- _checkValidity(): boolean {
96
- return false
97
- }
98
-
99
- _submit(e: MouseEvent) {
100
- if (!this._checkValidity()) return
101
-
102
- const form = e.target as HTMLFormElement
103
-
104
- const formData = new FormData(form)
105
- let json = {}
106
-
107
- //convert form into json
108
- for (const [key, value] of formData.entries()) {
109
- json[key] = value
110
- }
111
-
112
- auth.changePassword(json)
113
-
114
- form.reset()
115
- }
116
- }
@@ -1,141 +0,0 @@
1
- import '@material/web/icon/icon.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 } from '@operato/graphql'
8
- import { i18next, localize } from '@operato/i18n'
9
- import { OxPrompt } from '@operato/popup/ox-prompt.js'
10
- import { CommonHeaderStyles } from '@operato/styles'
11
-
12
- @customElement('create-domain-popup')
13
- class CreateDomainPopup extends localize(i18next)(LitElement) {
14
- static styles = [
15
- CommonHeaderStyles,
16
- css`
17
- :host {
18
- display: flex;
19
- flex-direction: column;
20
- background-color: var(--md-sys-color-background);
21
- overflow: auto;
22
- }
23
-
24
- form {
25
- flex: 1;
26
- padding: var(--spacing-large);
27
- }
28
-
29
- input.checkValidName {
30
- background-color: #fce6e6;
31
- }
32
-
33
- label {
34
- display: flex;
35
- flex-direction: column;
36
-
37
- font: var(--label-font);
38
- color: var(--label-color, var(--md-sys-color-on-surface));
39
- text-transform: var(--label-text-transform);
40
- }
41
-
42
- input {
43
- border: var(--border-dim-color);
44
- border-radius: var(--border-radius);
45
- margin: var(--input-margin);
46
- padding: var(--input-padding);
47
- background-color: var(--md-sys-color-surface);
48
- font: var(--input-font);
49
- }
50
-
51
- [field] {
52
- grid-column: span 2;
53
- }
54
- `
55
- ]
56
-
57
- @query('input[name="name"]') nameInput!: HTMLInputElement
58
-
59
- render() {
60
- return html`
61
- <form>
62
- <div field grid-span>
63
- <label
64
- >${i18next.t('label.x name', { x: i18next.t('label.domain') })}<input
65
- type="text"
66
- name="name"
67
- @input=${this.checkValidation}
68
- autofocus
69
- /></label>
70
- </div>
71
-
72
- <div field grid-span>
73
- <label>${i18next.t('label.description')}<input type="text" name="description" /></label>
74
- </div>
75
- </form>
76
-
77
- <div class="footer">
78
- <div filler></div>
79
- <button @click=${e => this.onCreateDomain()} done><md-icon>add</md-icon>${i18next.t('button.create')}</button>
80
- </div>
81
- `
82
- }
83
-
84
- firstUpdated() {
85
- this.nameInput.focus() // autofocus
86
- }
87
-
88
- get inputData() {
89
- return this.renderRoot.querySelectorAll('input')
90
- }
91
-
92
- checkValidation(e) {
93
- const currentInput = e.currentTarget
94
- const regExp = /^[a-zA-Z ]+$/
95
-
96
- if (!regExp.test(currentInput.value)) {
97
- currentInput.classList.add('checkValidName')
98
- } else {
99
- currentInput.classList.remove('checkValidName')
100
- }
101
- }
102
-
103
- async onCreateDomain() {
104
- const domainInput: { [prop: string]: string } = {}
105
- this.inputData.forEach(data => (domainInput[data.name] = data.value))
106
- const regExp = /^[a-zA-z0-9- ]+$/
107
-
108
- if (!regExp.test(domainInput.name)) {
109
- return this.showToast(i18next.t('error: domain name should consist only of letters or dashes'))
110
- }
111
-
112
- const response = await client.mutate({
113
- mutation: gql`
114
- mutation domainRegister($domainInput: DomainGeneratorInput!) {
115
- domainRegister(domainInput: $domainInput) {
116
- id
117
- name
118
- }
119
- }
120
- `,
121
- variables: { domainInput }
122
- })
123
-
124
- if (!response.errors) {
125
- await OxPrompt.open({
126
- type: 'success',
127
- title: i18next.t('text.completed'),
128
- text: i18next.t('text.x_created_successfully', { x: i18next.t('label.domain') }),
129
- confirmButton: { text: i18next.t('button.confirm') }
130
- })
131
-
132
- history.back()
133
-
134
- this.dispatchEvent(new CustomEvent('fetch-data'))
135
- }
136
- }
137
-
138
- showToast(message) {
139
- document.dispatchEvent(new CustomEvent('notify', { detail: { message } }))
140
- }
141
- }