@things-factory/auth-ui 8.0.0 → 9.0.0-beta.3

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 (99) hide show
  1. package/dist-client/components/abstract-auth-page.js +10 -10
  2. package/dist-client/components/abstract-auth-page.js.map +1 -1
  3. package/dist-client/components/abstract-password-reset.d.ts +1 -2
  4. package/dist-client/components/abstract-password-reset.js +7 -14
  5. package/dist-client/components/abstract-password-reset.js.map +1 -1
  6. package/dist-client/components/abstract-sign.js +12 -11
  7. package/dist-client/components/abstract-sign.js.map +1 -1
  8. package/dist-client/components/contact-us.d.ts +1 -1
  9. package/dist-client/components/contact-us.js +10 -7
  10. package/dist-client/components/contact-us.js.map +1 -1
  11. package/dist-client/components/create-user.js +28 -5
  12. package/dist-client/components/create-user.js.map +1 -1
  13. package/dist-client/components/invite-user.js +19 -11
  14. package/dist-client/components/invite-user.js.map +1 -1
  15. package/dist-client/components/ownership-transfer-popup.js +3 -3
  16. package/dist-client/components/ownership-transfer-popup.js.map +1 -1
  17. package/dist-client/components/profile-component.d.ts +5 -1
  18. package/dist-client/components/profile-component.js +64 -4
  19. package/dist-client/components/profile-component.js.map +1 -1
  20. package/dist-client/components/role-privilege-editor.js +2 -1
  21. package/dist-client/components/role-privilege-editor.js.map +1 -1
  22. package/dist-client/components/user-role-editor.js +18 -18
  23. package/dist-client/components/user-role-editor.js.map +1 -1
  24. package/dist-client/entries/auth/checkin.js +1 -1
  25. package/dist-client/entries/auth/checkin.js.map +1 -1
  26. package/dist-client/entries/auth/forgot-password.js +11 -2
  27. package/dist-client/entries/auth/forgot-password.js.map +1 -1
  28. package/dist-client/entries/auth/signup.js +13 -7
  29. package/dist-client/entries/auth/signup.js.map +1 -1
  30. package/dist-client/index.js +1 -1
  31. package/dist-client/index.js.map +1 -1
  32. package/dist-client/pages/user/user-management.d.ts +5 -1
  33. package/dist-client/pages/user/user-management.js +6 -7
  34. package/dist-client/pages/user/user-management.js.map +1 -1
  35. package/dist-client/tsconfig.tsbuildinfo +1 -1
  36. package/package.json +12 -12
  37. package/translations/en.json +6 -2
  38. package/translations/ja.json +6 -2
  39. package/translations/ko.json +6 -2
  40. package/translations/ms.json +6 -2
  41. package/translations/zh.json +6 -2
  42. package/client/auth-style-sign.ts +0 -194
  43. package/client/bootstrap.ts +0 -51
  44. package/client/components/abstract-auth-page.ts +0 -301
  45. package/client/components/abstract-password-reset.ts +0 -168
  46. package/client/components/abstract-sign.ts +0 -127
  47. package/client/components/change-password.ts +0 -153
  48. package/client/components/contact-us.ts +0 -113
  49. package/client/components/create-domain-popup.ts +0 -141
  50. package/client/components/create-role.ts +0 -123
  51. package/client/components/create-user.ts +0 -95
  52. package/client/components/credential-manager.ts +0 -64
  53. package/client/components/delete-user-popup.ts +0 -117
  54. package/client/components/domain-switch.ts +0 -127
  55. package/client/components/invite-customer.ts +0 -104
  56. package/client/components/invite-user.ts +0 -96
  57. package/client/components/my-login-history.ts +0 -101
  58. package/client/components/ownership-transfer-popup.ts +0 -110
  59. package/client/components/partner-info-card.ts +0 -89
  60. package/client/components/partner-role-editor.ts +0 -153
  61. package/client/components/profile-component.ts +0 -332
  62. package/client/components/role-edit-form.ts +0 -92
  63. package/client/components/role-privilege-editor.ts +0 -267
  64. package/client/components/role-selector.ts +0 -102
  65. package/client/components/user-role-editor.ts +0 -499
  66. package/client/constants/application.ts +0 -9
  67. package/client/constants/index.ts +0 -1
  68. package/client/entries/auth/activate.ts +0 -272
  69. package/client/entries/auth/checkin.ts +0 -190
  70. package/client/entries/auth/forgot-password.ts +0 -103
  71. package/client/entries/auth/reset-password.ts +0 -22
  72. package/client/entries/auth/result.ts +0 -193
  73. package/client/entries/auth/signin.ts +0 -18
  74. package/client/entries/auth/signup.ts +0 -109
  75. package/client/entries/auth/unlock-user.ts +0 -22
  76. package/client/entries/oauth2/oauth2-decision-error-page.ts +0 -50
  77. package/client/entries/oauth2/oauth2-decision-page.ts +0 -196
  78. package/client/entries/public/home.ts +0 -246
  79. package/client/index.ts +0 -124
  80. package/client/pages/app-binding/app-binding.ts +0 -423
  81. package/client/pages/app-binding/app-bindings.ts +0 -171
  82. package/client/pages/appliance/appliance.ts +0 -452
  83. package/client/pages/appliance/home.ts +0 -177
  84. package/client/pages/appliance/register.ts +0 -183
  85. package/client/pages/application/application.ts +0 -428
  86. package/client/pages/application/applications.ts +0 -182
  87. package/client/pages/application/register.ts +0 -211
  88. package/client/pages/attribute/attribute-set-item-list.ts +0 -237
  89. package/client/pages/attribute/attribute-set-management.ts +0 -282
  90. package/client/pages/auth-provider/auth-provider-management.ts +0 -381
  91. package/client/pages/domain/domain-management.ts +0 -410
  92. package/client/pages/partner/partner-management.ts +0 -112
  93. package/client/pages/profile.ts +0 -32
  94. package/client/pages/role/role-management.ts +0 -134
  95. package/client/pages/user/user-management.ts +0 -224
  96. package/client/route.ts +0 -67
  97. package/client/themes/auth-theme.css +0 -65
  98. package/client/utils/password-rule.ts +0 -37
  99. package/server/index.ts +0 -0
@@ -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,113 +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 & { open: boolean }
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.open = true)}>${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
- <div id="input-form">
52
- <md-filled-text-field
53
- type="text"
54
- label=${i18next.t('label.subject')}
55
- dialogInitialFocus
56
- required
57
- @input=${e => {
58
- const val = e.target.value
59
- this.subjectInput.value = val
60
- }}
61
- ></md-filled-text-field>
62
- <md-filled-text-field
63
- type="text"
64
- name="sender"
65
- label=${i18next.t('label.email')}
66
- required
67
- @input=${e => {
68
- const val = e.target.value
69
- this.senderInput.value = val
70
- }}
71
- ></md-filled-text-field>
72
- <md-filled-text-field
73
- name="content"
74
- type="textarea"
75
- label=${i18next.t('label.content')}
76
- required
77
- @keydown=${e => e.stopPropagation()}
78
- @input=${e => {
79
- const val = e.target.value
80
- this.contentInput.value = val
81
- }}
82
- ></md-filled-text-field>
83
- </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
- </md-dialog>
89
- `
90
- }
91
-
92
- _checkValidity(): boolean {
93
- return false
94
- }
95
-
96
- _submit(e: MouseEvent) {
97
- if (!this._checkValidity()) return
98
-
99
- const form = e.target as HTMLFormElement
100
-
101
- const formData = new FormData(form)
102
- let json = {}
103
-
104
- //convert form into json
105
- for (const [key, value] of formData.entries()) {
106
- json[key] = value
107
- }
108
-
109
- auth.changePassword(json)
110
-
111
- form.reset()
112
- }
113
- }
@@ -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
- }
@@ -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,95 +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
- @customElement('create-user')
10
- class CreateUser extends LitElement {
11
- static styles = css`
12
- :host {
13
- --md-text-field-fill-color: var(--md-sys-color-on-primary);
14
- background-color: var(--md-sys-color-surface);
15
- margin: var(--spacing-large) 0;
16
- padding: var(--spacing-large);
17
- border-radius: var(--border-radius);
18
- box-shadow: var(--box-shadow);
19
-
20
- display: grid;
21
- grid-template-columns: 1fr 2fr auto;
22
- gap: 5px 15px;
23
- clear: both;
24
- max-width: var(--input-container-max-width);
25
-
26
- align-items: center;
27
- }
28
-
29
- md-outlined-button {
30
- margin: var(--input-margin);
31
- }
32
-
33
- @media screen and (max-width: 480px) {
34
- :host {
35
- grid-template-columns: 1fr 1fr;
36
- }
37
-
38
- md-outlined-button {
39
- grid-column: span 2;
40
-
41
- margin: var(--input-margin);
42
- }
43
- }
44
- `
45
-
46
- @query('[name=name]') nameInput!: HTMLInputElement
47
- @query('[name=email]') emailInput!: HTMLInputElement
48
-
49
- render() {
50
- return html`
51
- <md-filled-text-field
52
- type="text"
53
- name="name"
54
- label=${String(i18next.t('label.x name', { x: i18next.t('label.user') }))}
55
- ></md-filled-text-field>
56
-
57
- <md-filled-text-field type="email" name="email" label=${String(i18next.t('field.email'))}></md-filled-text-field>
58
-
59
- <md-outlined-button @click=${this.onCreateUser.bind(this)}
60
- >${String(i18next.t('button.create'))}</md-outlined-button
61
- >
62
- `
63
- }
64
-
65
- async onCreateUser() {
66
- try {
67
- if (!this.emailInput.checkValidity()) {
68
- throw new Error(i18next.t('error.not valid pattern of type', { type: 'e-mail' }))
69
- }
70
-
71
- if (!this.nameInput.value) {
72
- throw new Error(i18next.t('error.value is empty', { value: 'name' }))
73
- }
74
-
75
- const user = {
76
- name: this.nameInput.value.trim(),
77
- email: this.emailInput.value.trim()
78
- }
79
-
80
- await this.dispatchEvent(new CustomEvent('create-user', { detail: user }))
81
-
82
- this.nameInput.value = ''
83
- this.emailInput.value = ''
84
- } catch (e: any) {
85
- document.dispatchEvent(
86
- new CustomEvent('notify', {
87
- detail: {
88
- level: 'error',
89
- message: 'message' in e ? e.message : e
90
- }
91
- })
92
- )
93
- }
94
- }
95
- }
@@ -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
- }