Skip to content

Commit

Permalink
fix(webapp): improve token management GUI, fixes #460
Browse files Browse the repository at this point in the history
  • Loading branch information
peterthomassen committed Nov 9, 2020
1 parent da69f48 commit 8d7bf57
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 29 deletions.
3 changes: 2 additions & 1 deletion webapp/src/components/Field/GenericText.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<v-text-field
<v-text-field v-if="!readonly"
:label="label"
:disabled="disabled || readonly"
:error-messages="errorMessages"
Expand All @@ -11,6 +11,7 @@
@input="input($event)"
@keyup="keyup($event)"
/>
<span v-else>{{ value }}</span>
</template>

<script>
Expand Down
45 changes: 22 additions & 23 deletions webapp/src/views/CrudList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,6 @@
Close
</v-btn>
</v-snackbar>
<v-snackbar
v-model="snackbarInfo"
:timeout="-1"
>
<span v-html="snackbarInfoText"></span>
<v-btn
color="pink"
text
@click="snackbarInfoText = ''"
>
Close
</v-btn>
</v-snackbar>

<!-- The Actual Table -->
<v-data-table
Expand Down Expand Up @@ -107,6 +94,14 @@
{{ errors[errors.length - 1] }}
</v-alert>

<v-alert
:value="createDialogSuccess"
type="success"
style="overflow: auto"
>
<span v-html="texts.createSuccess(createDialogItem)"></span>
</v-alert>

<v-alert
:value="!!texts.createWarning(destroyDialogItem)"
type="warning"
Expand All @@ -116,7 +111,7 @@

<v-card-text v-if="createDialog">
<!-- v-if required here to make autofocus below working for the 2nd+ times, cf stackoverflow.com/a/51476992 -->
<p>{{ texts.create() }}</p>
<span v-html="texts.create()"></span>
<!-- New Form -->
<component
:is="c.datatype"
Expand All @@ -127,30 +122,31 @@
:label="c.textCreate || c.text"
:error-messages="c.createErrors"
:required="c.required || false"
:disabled="createInhibited"
:disabled="createInhibited || createDialogSuccess"
autofocus
@input="clearErrors(c)"
/>
</v-card-text>

<v-card-actions>
<v-card-actions class="pb-4">
<v-spacer />
<v-btn
color="primary"
class="grow"
outlined
:outlined="!createDialogSuccess"
:disabled="createDialogWorking"
@click.native="close"
>
Cancel
{{ createDialogSuccess ? 'Close' : 'Cancel' }}
</v-btn>
<v-btn
type="submit"
color="primary"
class="grow"
depressed
:disabled="createInhibited || !valid || createDialogWorking"
:disabled="createInhibited || !valid || createDialogWorking || createDialogSuccess"
:loading="createDialogWorking"
v-if="!createDialogSuccess"
>
Save
</v-btn>
Expand Down Expand Up @@ -332,6 +328,7 @@ export default {
createDialogIndex: null,
createDialogItem: {},
createDialogError: false,
createDialogSuccess: false,
destroyDialog: false,
destroyDialogWorking: false,
destroyDialogItem: {},
Expand All @@ -342,7 +339,6 @@ export default {
extraComponentBind: {},
fullWidth: false,
snackbar: false,
snackbarInfoText: '',
search: '',
rows: [],
valid: false,
Expand All @@ -360,6 +356,7 @@ export default {
texts: {
banner: undefined,
create: () => ('Create a new object.'),
createSuccess: () => undefined,
createWarning: () => (false),
destroy: () => ('Delete an object permanently. This operation can likely not be undone.'),
destroyInfo: () => (false),
Expand All @@ -378,7 +375,7 @@ export default {
itemDefaults: () => ({}),
// callbacks
itemIsReadOnly: () => false,
postcreate: () => (undefined),
postcreate: this.close,
keyupHandler: (e) => {
// Intercept Enter key
if (e.keyCode === 13) {
Expand All @@ -402,7 +399,6 @@ export default {
});
return cols; // data table expects an array
},
snackbarInfo() { return !!this.snackbarInfoText; },
writeableColumns() {
const filter = function (obj, predicate) {
const result = {};
Expand Down Expand Up @@ -500,14 +496,16 @@ export default {
// new item
this.createDialogWorking = true;
this.createDialogError = false;
this.createDialogSuccess = false;
const url = this.resourcePath(
this.resourcePath(this.paths.create, this.$route.params, '::'),
this.createDialogItem,
':',
);
const r = await withWorking(this.error, () => HTTP.post(url, self.createDialogItem))
if (r) {
this.close();
this.createDialogItem = r.data;
this.createDialogSuccess = true;
const l = this.rows.push(r.data);
this.postcreate(this.rows[l - 1]);
}
Expand All @@ -522,6 +520,7 @@ export default {
this.createDialogItem = Object.assign({}, this.itemDefaults());
this.createDialogIndex = null;
this.createDialogError = false;
this.createDialogSuccess = false;
for (const c in this.columns) {
this.columns[c].createErrors = [];
}
Expand Down
5 changes: 4 additions & 1 deletion webapp/src/views/DomainList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ export default {
delete: 'domains/:{name}/',
},
itemDefaults: () => ({ name: '' }),
postcreate: d => this.showDomainInfo(d, true),
postcreate: d => {
this.close();
this.showDomainInfo(d, true);
},
async showDomainInfo(d, isNew = false) {
const url = this.resourcePath(this.paths.delete, d, ':');
if (d.keys === undefined) {
Expand Down
9 changes: 5 additions & 4 deletions webapp/src/views/TokenList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ export default {
},
texts: {
banner: () => ('Any API Token can be used to perform any DNS operation on any domain in this account. Token scoping is on our roadmap.'),
create: () => ('Names are purely for your own convenience and carry no technical meaning.'),
create: () => ('<p>You can create a new API token here. The token is displayed after submitting this form.</p><p><strong>Warning:</strong> Be sure to protect your tokens appropriately! Knowledge of an API token allows performing actions on your behalf.</p>'),
createSuccess: (item) => `Your new token is: <code>${item.token}</code><br />It is only displayed once.`,
destroy: d => (d.name ? `Delete token with name "${d.name}" and ID ${d.id}?` : `Delete unnamed token with ID ${d.id}?`),
destroyInfo: () => ('This operation is permanent. Any devices using this token will no longer be able to authenticate.'),
destroyWarning: d => (d.id == store.state.token.id ? 'This is your current session token. Deleting it will invalidate the session.' : ''),
},
columns: {
id: {
name: 'item.id',
text: 'ID',
text: 'Identifier',
align: 'left',
value: 'id',
readonly: true,
Expand All @@ -35,7 +36,7 @@ export default {
name: {
name: 'item.name',
text: 'Name',
textCreate: 'Token name',
textCreate: 'Token name (for your convenience only)',
align: 'left',
sortable: true,
value: 'name',
Expand Down Expand Up @@ -73,7 +74,7 @@ export default {
},
itemDefaults: () => ({ name: '' }),
itemIsReadOnly: (item) => item.id == store.state.token.id,
postcreate(d) { this.snackbarInfoText = `Your new token is: <code>${d.token}</code><br />It is only displayed once.`; },
postcreate: () => false, // do not close dialog
}
},
};
Expand Down

0 comments on commit 8d7bf57

Please sign in to comment.