@things-factory/auth-ui 10.1.17 → 10.1.20
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/dist-client/components/app-binding-detail.d.ts +46 -0
- package/dist-client/components/app-binding-detail.js +384 -0
- package/dist-client/components/app-binding-detail.js.map +1 -0
- package/dist-client/components/appliance-editor.d.ts +37 -0
- package/dist-client/components/appliance-editor.js +489 -0
- package/dist-client/components/appliance-editor.js.map +1 -0
- package/dist-client/components/application-editor.d.ts +31 -0
- package/dist-client/components/application-editor.js +491 -0
- package/dist-client/components/application-editor.js.map +1 -0
- package/dist-client/components/profile-component.js +28 -11
- package/dist-client/components/profile-component.js.map +1 -1
- package/dist-client/constants/application-type-parity.test.js +62 -0
- package/dist-client/constants/application-type-parity.test.js.map +1 -0
- package/dist-client/constants/application.d.ts +17 -7
- package/dist-client/constants/application.js +18 -8
- package/dist-client/constants/application.js.map +1 -1
- package/dist-client/pages/app-binding/app-bindings.d.ts +2 -0
- package/dist-client/pages/app-binding/app-bindings.js +19 -1
- package/dist-client/pages/app-binding/app-bindings.js.map +1 -1
- package/dist-client/pages/appliance/home.d.ts +2 -0
- package/dist-client/pages/appliance/home.js +21 -3
- package/dist-client/pages/appliance/home.js.map +1 -1
- package/dist-client/pages/application/applications.d.ts +2 -0
- package/dist-client/pages/application/applications.js +21 -3
- package/dist-client/pages/application/applications.js.map +1 -1
- package/dist-client/pages/secrets-are-not-printed.test.js +21 -3
- package/dist-client/pages/secrets-are-not-printed.test.js.map +1 -1
- package/dist-client/route.js +0 -15
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/utils/form-values.d.ts +29 -0
- package/dist-client/utils/form-values.js +45 -0
- package/dist-client/utils/form-values.js.map +1 -1
- package/dist-client/utils/form-values.test.js +59 -1
- package/dist-client/utils/form-values.test.js.map +1 -1
- package/dist-client/utils/webauthn-verification.d.ts +56 -0
- package/dist-client/utils/webauthn-verification.js +79 -0
- package/dist-client/utils/webauthn-verification.js.map +1 -0
- package/dist-client/utils/webauthn-verification.test.js +79 -0
- package/dist-client/utils/webauthn-verification.test.js.map +1 -0
- package/package.json +4 -4
- package/things-factory.config.js +0 -5
- package/translations/en.json +25 -0
- package/translations/ja.json +26 -0
- package/translations/ko.json +25 -0
- package/translations/ms.json +26 -0
- package/translations/zh.json +26 -0
- package/dist-client/pages/app-binding/app-binding.d.ts +0 -2
- package/dist-client/pages/app-binding/app-binding.js +0 -371
- package/dist-client/pages/app-binding/app-binding.js.map +0 -1
- package/dist-client/pages/appliance/appliance.d.ts +0 -2
- package/dist-client/pages/appliance/appliance.js +0 -390
- package/dist-client/pages/appliance/appliance.js.map +0 -1
- package/dist-client/pages/appliance/register.js +0 -166
- package/dist-client/pages/appliance/register.js.map +0 -1
- package/dist-client/pages/application/application.d.ts +0 -2
- package/dist-client/pages/application/application.js +0 -384
- package/dist-client/pages/application/application.js.map +0 -1
- package/dist-client/pages/application/register.js +0 -246
- package/dist-client/pages/application/register.js.map +0 -1
- /package/dist-client/{pages/appliance/register.d.ts → constants/application-type-parity.test.d.ts} +0 -0
- /package/dist-client/{pages/application/register.d.ts → utils/webauthn-verification.test.d.ts} +0 -0
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import '@material/web/icon/icon.js';
|
|
3
|
-
import Clipboard from 'clipboard';
|
|
4
|
-
import gql from 'graphql-tag';
|
|
5
|
-
import { css, html } from 'lit';
|
|
6
|
-
import { customElement, property, state } from 'lit/decorators.js';
|
|
7
|
-
import { asyncReplace } from 'lit/directives/async-replace.js';
|
|
8
|
-
import { client } from '@operato/graphql';
|
|
9
|
-
import { i18next } from '@operato/i18n';
|
|
10
|
-
import { navigate, PageView } from '@operato/shell';
|
|
11
|
-
import '../../components/secret-field.js';
|
|
12
|
-
import { parseJwt, sleep } from '@operato/utils';
|
|
13
|
-
let AppBinding = class AppBinding extends PageView {
|
|
14
|
-
static { this.styles = [
|
|
15
|
-
css `
|
|
16
|
-
:host { display: flex;
|
|
17
|
-
flex-direction: column;
|
|
18
|
-
overflow-y: auto;
|
|
19
|
-
|
|
20
|
-
position: relative;
|
|
21
|
-
|
|
22
|
-
background-color: var(--md-sys-color-background);
|
|
23
|
-
padding: var(--spacing-large);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
h2 { margin: var(--title-margin);
|
|
27
|
-
font: var(--title-font);
|
|
28
|
-
color: var(--title-text-color);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
[page-description] { margin: var(--page-description-margin);
|
|
32
|
-
font: var(--page-description-font);
|
|
33
|
-
color: var(--page-description-color);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
[icon] { position: absolute;
|
|
37
|
-
top: 10px;
|
|
38
|
-
right: 10px;
|
|
39
|
-
|
|
40
|
-
max-width: 80px;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
[icon] img { max-width: 100%;
|
|
44
|
-
max-height: 100%;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
[fieldset-container] { background-color: var(--md-sys-color-surface);
|
|
48
|
-
margin: var(--spacing-large) 0 var(--spacing-medium) 0;
|
|
49
|
-
padding: var(--spacing-medium);
|
|
50
|
-
border-radius: var(--border-radius);
|
|
51
|
-
box-shadow: var(--box-shadow);
|
|
52
|
-
|
|
53
|
-
label { font: var(--label-font);
|
|
54
|
-
color: var(--label-color, var(--md-sys-color-on-surface));
|
|
55
|
-
text-transform: var(--label-text-transform);
|
|
56
|
-
}
|
|
57
|
-
input {
|
|
58
|
-
background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));
|
|
59
|
-
color: var(--input-field-color, var(--md-sys-color-on-surface));
|
|
60
|
-
border: var(--border-dim-color);
|
|
61
|
-
border-radius: var(--border-radius);
|
|
62
|
-
margin: var(--input-margin);
|
|
63
|
-
padding: var(--input-padding);
|
|
64
|
-
font: var(--input-font);
|
|
65
|
-
|
|
66
|
-
flex: 1;
|
|
67
|
-
}
|
|
68
|
-
select:focus,
|
|
69
|
-
input:focus,
|
|
70
|
-
button { outline: none;
|
|
71
|
-
}
|
|
72
|
-
form { max-width: var(--content-container-max-width);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
[fieldset-container] fieldset { margin: 0;
|
|
77
|
-
margin-top: -15px;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
fieldset { border-radius: var(--border-radius);
|
|
81
|
-
border: var(--border-dim-color);
|
|
82
|
-
margin: var(--fieldset-margin);
|
|
83
|
-
padding: var(--fieldset-padding);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
legend { padding: var(--legend-padding);
|
|
87
|
-
font-weight: bold;
|
|
88
|
-
color: var(--legend-color);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
[field-2column] { display: grid;
|
|
92
|
-
grid-template-columns: 1fr 1fr;
|
|
93
|
-
grid-gap: 15px;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
[field] { display: flex;
|
|
97
|
-
flex-direction: column;
|
|
98
|
-
position: relative;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
[grid-span] { grid-column: span 2;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
button,
|
|
105
|
-
[button-in-field] { background-color: var(--button-background-color);
|
|
106
|
-
border: var(--button-border);
|
|
107
|
-
border-radius: var(--button-border-radius);
|
|
108
|
-
padding: var(--button-padding);
|
|
109
|
-
color: var(--button-color);
|
|
110
|
-
font: var(--button-font);
|
|
111
|
-
text-transform: var(--button-text-transform);
|
|
112
|
-
|
|
113
|
-
margin: var(--spacing-medium) 0 var(--spacing-medium) var(--spacing-medium);
|
|
114
|
-
float: right;
|
|
115
|
-
text-decoration: none;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
button:hover { border: var(--button-activ-border);
|
|
119
|
-
box-shadow: var(--button-active-box-shadow);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
[button-in-field] { border-radius: 0 var(--button-border-radius) var(--button-border-radius) 0;
|
|
123
|
-
position: absolute;
|
|
124
|
-
top: 12px;
|
|
125
|
-
right: 0;
|
|
126
|
-
max-height: 36px;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
[input-hint] { font: var(--input-hint-font);
|
|
130
|
-
color: var(--input-hint-color);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
@media screen and (max-width: 480px) { [field] { grid-column: span 2;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
`
|
|
137
|
-
]; }
|
|
138
|
-
get context() {
|
|
139
|
-
return { title: { icon: 'link',
|
|
140
|
-
text: this.appbinding.name
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
render() {
|
|
145
|
-
var binding = this.appbinding || {};
|
|
146
|
-
var app = this.appbinding?.application || {};
|
|
147
|
-
var refreshTokenExp = this._refreshTokenInfo?.exp;
|
|
148
|
-
var accessTokenExp = this._accessTokenInfo?.exp;
|
|
149
|
-
return html `
|
|
150
|
-
<div>
|
|
151
|
-
<h2><md-icon>link</md-icon> ${app.name}</h2>
|
|
152
|
-
<p page-description>${app.description}</p>
|
|
153
|
-
</div>
|
|
154
|
-
|
|
155
|
-
${app.icon
|
|
156
|
-
? html `
|
|
157
|
-
<div icon>
|
|
158
|
-
<img src=${app.icon} />
|
|
159
|
-
</div>
|
|
160
|
-
`
|
|
161
|
-
: html ``}
|
|
162
|
-
|
|
163
|
-
<form>
|
|
164
|
-
<div fieldset-container>
|
|
165
|
-
<fieldset>
|
|
166
|
-
<legend>application</legend>
|
|
167
|
-
<div field-2column>
|
|
168
|
-
<div field grid-span>
|
|
169
|
-
<label for="app-name">app name</label>
|
|
170
|
-
<input id="app-name" type="text" .value=${app.name} readonly />
|
|
171
|
-
</div>
|
|
172
|
-
|
|
173
|
-
<div field grid-span>
|
|
174
|
-
<label for="app-description">description</label>
|
|
175
|
-
<input id="app-description" type="text" .value=${app.description} readonly />
|
|
176
|
-
</div>
|
|
177
|
-
|
|
178
|
-
<div field>
|
|
179
|
-
<label for="contact-email">contact email</label>
|
|
180
|
-
<input id="contact-email" type="text" .value=${app.email} readonly />
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
</fieldset>
|
|
184
|
-
</div>
|
|
185
|
-
|
|
186
|
-
<div fieldset-container>
|
|
187
|
-
<fieldset>
|
|
188
|
-
<legend>binding</legend>
|
|
189
|
-
<div field-2column>
|
|
190
|
-
<div field grid-span>
|
|
191
|
-
<label for="id">id</label>
|
|
192
|
-
<input id="id" type="text" .value=${binding.id} readonly />
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
<div field grid-span>
|
|
196
|
-
<label for="name">name</label>
|
|
197
|
-
<input id="name" type="text" .value=${binding.email} readonly />
|
|
198
|
-
</div>
|
|
199
|
-
|
|
200
|
-
<div field>
|
|
201
|
-
<label for="status">status</label>
|
|
202
|
-
<input id="status" type="text" .value=${binding.status} readonly />
|
|
203
|
-
</div>
|
|
204
|
-
|
|
205
|
-
<div field>
|
|
206
|
-
<label for="scope">scope</label>
|
|
207
|
-
<input id="scope" type="text" .value=${binding.scope} readonly />
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
</fieldset>
|
|
211
|
-
</div>
|
|
212
|
-
|
|
213
|
-
<div fieldset-container>
|
|
214
|
-
<fieldset>
|
|
215
|
-
<legend>binding credential</legend>
|
|
216
|
-
<div field-2column>
|
|
217
|
-
<div field grid-span>
|
|
218
|
-
<label for="access-token">${i18next.t('label.access token')}</label>
|
|
219
|
-
<secret-field id="access-token" .value=${this.accessToken || ''}></secret-field>
|
|
220
|
-
${accessTokenExp
|
|
221
|
-
? html `<div input-hint>
|
|
222
|
-
${i18next.t('text.expires at x', { x: new Date(accessTokenExp).toLocaleString() })} ·
|
|
223
|
-
${asyncReplace(this.expTimer(accessTokenExp))}
|
|
224
|
-
</div>`
|
|
225
|
-
: html ``}
|
|
226
|
-
</div>
|
|
227
|
-
|
|
228
|
-
<div field grid-span>
|
|
229
|
-
<label for="refresh-token">${i18next.t('label.refresh token')}</label>
|
|
230
|
-
<secret-field id="refresh-token" .value=${binding.refreshToken || ''}></secret-field>
|
|
231
|
-
${refreshTokenExp
|
|
232
|
-
? html `<div input-hint>
|
|
233
|
-
${i18next.t('text.expires at x', { x: new Date(refreshTokenExp).toLocaleString() })} ·
|
|
234
|
-
${asyncReplace(this.expTimer(refreshTokenExp))}
|
|
235
|
-
</div>`
|
|
236
|
-
: html ``}
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
</fieldset>
|
|
240
|
-
</div>
|
|
241
|
-
|
|
242
|
-
<button @click=${this.deleteAppBinding.bind(this)}>delete this application binding</button>
|
|
243
|
-
<button @click=${this.renewApplicationAccessToken.bind(this)}>renew access token</button>
|
|
244
|
-
</form>
|
|
245
|
-
`;
|
|
246
|
-
}
|
|
247
|
-
async *expTimer(exp) {
|
|
248
|
-
const DAY = 24 * 60 * 60;
|
|
249
|
-
const HOUR = 60 * 60;
|
|
250
|
-
const MIN = 60;
|
|
251
|
-
while (this.active) {
|
|
252
|
-
var remain = Math.floor(Number(exp) - Date.now() / 1000);
|
|
253
|
-
const days = Math.floor(remain / DAY);
|
|
254
|
-
remain -= days * DAY;
|
|
255
|
-
const hours = Math.floor(remain / HOUR);
|
|
256
|
-
remain -= hours * HOUR;
|
|
257
|
-
const mins = Math.floor(remain / MIN);
|
|
258
|
-
const secs = remain - mins * MIN;
|
|
259
|
-
yield `${days} days ${hours} hours ${mins} mins ${secs} seconds remain`;
|
|
260
|
-
await sleep(1000);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
firstUpdated() {
|
|
264
|
-
const copybuttons = this.renderRoot.querySelectorAll('[clipboard-copy]');
|
|
265
|
-
this.clipboard = new Clipboard(copybuttons, { target: (trigger => trigger.parentElement.querySelector('input'))
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
updated(changes) {
|
|
269
|
-
if (changes.has('appbinding')) {
|
|
270
|
-
const { refreshToken } = this.appbinding || {};
|
|
271
|
-
this._refreshTokenInfo = refreshToken ? parseJwt(refreshToken) : {};
|
|
272
|
-
}
|
|
273
|
-
if (changes.has('accessToken')) {
|
|
274
|
-
this._accessTokenInfo = this.accessToken ? parseJwt(this.accessToken) : {};
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
async pageUpdated(changes, lifecycle, before) {
|
|
278
|
-
if (this.active) { /*
|
|
279
|
-
* this page is activated
|
|
280
|
-
*/
|
|
281
|
-
await this.fetchAppBinding();
|
|
282
|
-
}
|
|
283
|
-
else { /* this page is deactivated */
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
async fetchAppBinding() {
|
|
287
|
-
const response = await client.query({ query: gql `
|
|
288
|
-
query ($id: String!) { appBinding(id: $id) { id
|
|
289
|
-
name
|
|
290
|
-
description
|
|
291
|
-
email
|
|
292
|
-
scope
|
|
293
|
-
status
|
|
294
|
-
application { id
|
|
295
|
-
name
|
|
296
|
-
description
|
|
297
|
-
email
|
|
298
|
-
icon
|
|
299
|
-
}
|
|
300
|
-
refreshToken
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
`,
|
|
304
|
-
variables: { id: this.lifecycle.resourceId
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
this.appbinding = response.data.appBinding;
|
|
308
|
-
}
|
|
309
|
-
async deleteAppBinding(e) {
|
|
310
|
-
e.preventDefault();
|
|
311
|
-
const id = this.lifecycle.resourceId;
|
|
312
|
-
const response = await client.mutate({ mutation: gql `
|
|
313
|
-
mutation ($id: String!) { deleteAppBinding(id: $id)
|
|
314
|
-
}
|
|
315
|
-
`,
|
|
316
|
-
variables: { id
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
const result = response.data.deleteAppBinding;
|
|
320
|
-
if (result) {
|
|
321
|
-
console.log('delete sucess');
|
|
322
|
-
navigate(`app-bindings`);
|
|
323
|
-
}
|
|
324
|
-
else {
|
|
325
|
-
console.error('delete fail');
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
async renewApplicationAccessToken(e) {
|
|
329
|
-
e.preventDefault();
|
|
330
|
-
const id = this.lifecycle.resourceId;
|
|
331
|
-
const response = await client.mutate({ mutation: gql `
|
|
332
|
-
mutation ($id: String!) { renewApplicationAccessToken(id: $id) { accessToken
|
|
333
|
-
refreshToken
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
`,
|
|
337
|
-
variables: { id
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
if (response.errors) {
|
|
341
|
-
console.error('renew application access token fail');
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
const { accessToken, refreshToken } = response.data.renewApplicationAccessToken;
|
|
345
|
-
this.accessToken = accessToken;
|
|
346
|
-
this.appbinding = { ...this.appbinding,
|
|
347
|
-
refreshToken
|
|
348
|
-
};
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
};
|
|
352
|
-
__decorate([
|
|
353
|
-
property({ type: Object }),
|
|
354
|
-
__metadata("design:type", Object)
|
|
355
|
-
], AppBinding.prototype, "appbinding", void 0);
|
|
356
|
-
__decorate([
|
|
357
|
-
property({ type: String }),
|
|
358
|
-
__metadata("design:type", String)
|
|
359
|
-
], AppBinding.prototype, "accessToken", void 0);
|
|
360
|
-
__decorate([
|
|
361
|
-
state(),
|
|
362
|
-
__metadata("design:type", Object)
|
|
363
|
-
], AppBinding.prototype, "_refreshTokenInfo", void 0);
|
|
364
|
-
__decorate([
|
|
365
|
-
state(),
|
|
366
|
-
__metadata("design:type", Object)
|
|
367
|
-
], AppBinding.prototype, "_accessTokenInfo", void 0);
|
|
368
|
-
AppBinding = __decorate([
|
|
369
|
-
customElement('app-binding-page')
|
|
370
|
-
], AppBinding);
|
|
371
|
-
//# sourceMappingURL=app-binding.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"app-binding.js","sourceRoot":"","sources":["../../../client/pages/app-binding/app-binding.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport Clipboard from 'clipboard'\nimport gql from 'graphql-tag'\nimport { css, html } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { asyncReplace } from 'lit/directives/async-replace.js'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\nimport { navigate, PageView } from '@operato/shell'\n\nimport '../../components/secret-field.js'\nimport { parseJwt, sleep } from '@operato/utils'\n\n@customElement('app-binding-page')\nclass AppBinding extends PageView { static styles = [\n css`\n :host { display: flex;\n flex-direction: column;\n overflow-y: auto;\n\n position: relative;\n\n background-color: var(--md-sys-color-background);\n padding: var(--spacing-large);\n }\n\n h2 { margin: var(--title-margin);\n font: var(--title-font);\n color: var(--title-text-color);\n }\n\n [page-description] { margin: var(--page-description-margin);\n font: var(--page-description-font);\n color: var(--page-description-color);\n }\n\n [icon] { position: absolute;\n top: 10px;\n right: 10px;\n\n max-width: 80px;\n }\n\n [icon] img { max-width: 100%;\n max-height: 100%;\n }\n\n [fieldset-container] { background-color: var(--md-sys-color-surface);\n margin: var(--spacing-large) 0 var(--spacing-medium) 0;\n padding: var(--spacing-medium);\n border-radius: var(--border-radius);\n box-shadow: var(--box-shadow);\n\n label { font: var(--label-font);\n color: var(--label-color, var(--md-sys-color-on-surface));\n text-transform: var(--label-text-transform);\n }\n input {\n background-color: var(--input-field-background, var(--md-sys-color-surface-container-highest));\n color: var(--input-field-color, var(--md-sys-color-on-surface));\n border: var(--border-dim-color);\n border-radius: var(--border-radius);\n margin: var(--input-margin);\n padding: var(--input-padding);\n font: var(--input-font);\n\n flex: 1;\n }\n select:focus,\n input:focus,\n button { outline: none;\n }\n form { max-width: var(--content-container-max-width);\n }\n }\n\n [fieldset-container] fieldset { margin: 0;\n margin-top: -15px;\n }\n\n fieldset { border-radius: var(--border-radius);\n border: var(--border-dim-color);\n margin: var(--fieldset-margin);\n padding: var(--fieldset-padding);\n }\n\n legend { padding: var(--legend-padding);\n font-weight: bold;\n color: var(--legend-color);\n }\n\n [field-2column] { display: grid;\n grid-template-columns: 1fr 1fr;\n grid-gap: 15px;\n }\n\n [field] { display: flex;\n flex-direction: column;\n position: relative;\n }\n\n [grid-span] { grid-column: span 2;\n }\n\n button,\n [button-in-field] { background-color: var(--button-background-color);\n border: var(--button-border);\n border-radius: var(--button-border-radius);\n padding: var(--button-padding);\n color: var(--button-color);\n font: var(--button-font);\n text-transform: var(--button-text-transform);\n\n margin: var(--spacing-medium) 0 var(--spacing-medium) var(--spacing-medium);\n float: right;\n text-decoration: none;\n }\n\n button:hover { border: var(--button-activ-border);\n box-shadow: var(--button-active-box-shadow);\n }\n\n [button-in-field] { border-radius: 0 var(--button-border-radius) var(--button-border-radius) 0;\n position: absolute;\n top: 12px;\n right: 0;\n max-height: 36px;\n }\n\n [input-hint] { font: var(--input-hint-font);\n color: var(--input-hint-color);\n }\n\n @media screen and (max-width: 480px) { [field] { grid-column: span 2;\n }\n }\n `\n ]\n\n @property({ type: Object }) appbinding: any\n @property({ type: String }) accessToken?: string\n\n @state() _refreshTokenInfo: any\n @state() _accessTokenInfo: any\n\n private clipboard?: Clipboard\n\n get context() { return { title: { icon: 'link',\n text: this.appbinding.name\n }\n }\n }\n\n render() { var binding = this.appbinding || {}\n var app = this.appbinding?.application || {}\n var refreshTokenExp = this._refreshTokenInfo?.exp\n var accessTokenExp = this._accessTokenInfo?.exp\n\n return html`\n <div>\n <h2><md-icon>link</md-icon> ${app.name}</h2>\n <p page-description>${app.description}</p>\n </div>\n\n ${app.icon\n ? html`\n <div icon>\n <img src=${app.icon} />\n </div>\n `\n : html``}\n\n <form>\n <div fieldset-container>\n <fieldset>\n <legend>application</legend>\n <div field-2column>\n <div field grid-span>\n <label for=\"app-name\">app name</label>\n <input id=\"app-name\" type=\"text\" .value=${app.name} readonly />\n </div>\n\n <div field grid-span>\n <label for=\"app-description\">description</label>\n <input id=\"app-description\" type=\"text\" .value=${app.description} readonly />\n </div>\n\n <div field>\n <label for=\"contact-email\">contact email</label>\n <input id=\"contact-email\" type=\"text\" .value=${app.email} readonly />\n </div>\n </div>\n </fieldset>\n </div>\n\n <div fieldset-container>\n <fieldset>\n <legend>binding</legend>\n <div field-2column>\n <div field grid-span>\n <label for=\"id\">id</label>\n <input id=\"id\" type=\"text\" .value=${binding.id} readonly />\n </div>\n\n <div field grid-span>\n <label for=\"name\">name</label>\n <input id=\"name\" type=\"text\" .value=${binding.email} readonly />\n </div>\n\n <div field>\n <label for=\"status\">status</label>\n <input id=\"status\" type=\"text\" .value=${binding.status} readonly />\n </div>\n\n <div field>\n <label for=\"scope\">scope</label>\n <input id=\"scope\" type=\"text\" .value=${binding.scope} readonly />\n </div>\n </div>\n </fieldset>\n </div>\n\n <div fieldset-container>\n <fieldset>\n <legend>binding credential</legend>\n <div field-2column>\n <div field grid-span>\n <label for=\"access-token\">${i18next.t('label.access token')}</label>\n <secret-field id=\"access-token\" .value=${this.accessToken || ''}></secret-field>\n ${accessTokenExp\n ? html`<div input-hint>\n ${i18next.t('text.expires at x', { x: new Date(accessTokenExp).toLocaleString() })} ·\n ${asyncReplace(this.expTimer(accessTokenExp))}\n </div>`\n : html``}\n </div>\n\n <div field grid-span>\n <label for=\"refresh-token\">${i18next.t('label.refresh token')}</label>\n <secret-field id=\"refresh-token\" .value=${binding.refreshToken || ''}></secret-field>\n ${refreshTokenExp\n ? html`<div input-hint>\n ${i18next.t('text.expires at x', { x: new Date(refreshTokenExp).toLocaleString() })} ·\n ${asyncReplace(this.expTimer(refreshTokenExp))}\n </div>`\n : html``}\n </div>\n </div>\n </fieldset>\n </div>\n\n <button @click=${this.deleteAppBinding.bind(this)}>delete this application binding</button>\n <button @click=${this.renewApplicationAccessToken.bind(this)}>renew access token</button>\n </form>\n `\n }\n\n async *expTimer(exp) { const DAY = 24 * 60 * 60\n const HOUR = 60 * 60\n const MIN = 60\n\n while (this.active) { var remain = Math.floor(Number(exp) - Date.now() / 1000)\n const days = Math.floor(remain / DAY)\n remain -= days * DAY\n const hours = Math.floor(remain / HOUR)\n remain -= hours * HOUR\n const mins = Math.floor(remain / MIN)\n const secs = remain - mins * MIN\n\n yield `${days} days ${hours} hours ${mins} mins ${secs} seconds remain`\n\n await sleep(1000)\n }\n }\n\n firstUpdated() { const copybuttons = this.renderRoot.querySelectorAll('[clipboard-copy]')\n\n this.clipboard = new Clipboard(copybuttons, { target: (trigger => trigger.parentElement.querySelector('input')) as any\n })\n }\n\n updated(changes) { /*\n * If this page properties are changed, this callback will be invoked.\n * This callback will be called back only when this page is activated.\n */\n if (changes.has('appbinding')) { const { refreshToken } = this.appbinding || {}\n this._refreshTokenInfo = refreshToken ? parseJwt(refreshToken) : {}\n }\n\n if (changes.has('accessToken')) { this._accessTokenInfo = this.accessToken ? parseJwt(this.accessToken) : {}\n }\n }\n\n async pageUpdated(changes, lifecycle, before) { if (this.active) { /*\n * this page is activated\n */\n await this.fetchAppBinding()\n } else { /* this page is deactivated */\n }\n }\n\n async fetchAppBinding() { const response = await client.query({ query: gql`\n query ($id: String!) { appBinding(id: $id) { id\n name\n description\n email\n scope\n status\n application { id\n name\n description\n email\n icon\n }\n refreshToken\n }\n }\n `,\n variables: { id: this.lifecycle.resourceId\n }\n })\n\n this.appbinding = response.data.appBinding\n }\n\n async deleteAppBinding(e) { e.preventDefault()\n\n const id = this.lifecycle.resourceId\n\n const response = await client.mutate({ mutation: gql`\n mutation ($id: String!) { deleteAppBinding(id: $id)\n }\n `,\n variables: { id\n }\n })\n\n const result = response.data.deleteAppBinding\n if (result) { console.log('delete sucess')\n navigate(`app-bindings`)\n } else { console.error('delete fail')\n }\n }\n\n async renewApplicationAccessToken(e) { e.preventDefault()\n\n const id = this.lifecycle.resourceId\n\n const response = await client.mutate({ mutation: gql`\n mutation ($id: String!) { renewApplicationAccessToken(id: $id) { accessToken\n refreshToken\n }\n }\n `,\n variables: { id\n }\n })\n\n if (response.errors) { console.error('renew application access token fail')\n } else { const { accessToken, refreshToken } = response.data.renewApplicationAccessToken\n this.accessToken = accessToken\n this.appbinding = { ...this.appbinding,\n refreshToken\n }\n }\n }\n}\n"]}
|