feat(web2): add templates page

This commit is contained in:
Denis Gukov 2020-10-04 22:11:49 +05:00
parent c855bf1f6a
commit 669a8d0128
3 changed files with 77 additions and 260 deletions

View File

@ -1,151 +0,0 @@
<template>
<v-container>
<v-row class="text-center">
<v-col cols="12">
<v-img
:src="require('../assets/logo.svg')"
class="my-3"
contain
height="200"
/>
</v-col>
<v-col class="mb-4">
<h1 class="display-2 font-weight-bold mb-3">
Welcome to Vuetify
</h1>
<p class="subheading font-weight-regular">
For help and collaboration with other Vuetify developers,
<br>please join our online
<a
href="https://community.vuetifyjs.com"
target="_blank"
>Discord Community</a>
</p>
</v-col>
<v-col
class="mb-5"
cols="12"
>
<h2 class="headline font-weight-bold mb-3">
What's next?
</h2>
<v-row justify="center">
<a
v-for="(next, i) in whatsNext"
:key="i"
:href="next.href"
class="subheading mx-3"
target="_blank"
>
{{ next.text }}
</a>
</v-row>
</v-col>
<v-col
class="mb-5"
cols="12"
>
<h2 class="headline font-weight-bold mb-3">
Important Links
</h2>
<v-row justify="center">
<a
v-for="(link, i) in importantLinks"
:key="i"
:href="link.href"
class="subheading mx-3"
target="_blank"
>
{{ link.text }}
</a>
</v-row>
</v-col>
<v-col
class="mb-5"
cols="12"
>
<h2 class="headline font-weight-bold mb-3">
Ecosystem
</h2>
<v-row justify="center">
<a
v-for="(eco, i) in ecosystem"
:key="i"
:href="eco.href"
class="subheading mx-3"
target="_blank"
>
{{ eco.text }}
</a>
</v-row>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: 'HelloWorld',
data: () => ({
ecosystem: [
{
text: 'vuetify-loader',
href: 'https://github.com/vuetifyjs/vuetify-loader',
},
{
text: 'github',
href: 'https://github.com/vuetifyjs/vuetify',
},
{
text: 'awesome-vuetify',
href: 'https://github.com/vuetifyjs/awesome-vuetify',
},
],
importantLinks: [
{
text: 'Documentation',
href: 'https://vuetifyjs.com',
},
{
text: 'Chat',
href: 'https://community.vuetifyjs.com',
},
{
text: 'Made with Vuetify',
href: 'https://madewithvuejs.com/vuetify',
},
{
text: 'Twitter',
href: 'https://twitter.com/vuetifyjs',
},
{
text: 'Articles',
href: 'https://medium.com/vuetify',
},
],
whatsNext: [
{
text: 'Explore components',
href: 'https://vuetifyjs.com/components/api-explorer',
},
{
text: 'Select a layout',
href: 'https://vuetifyjs.com/getting-started/pre-made-layouts',
},
{
text: 'Frequently Asked Questions',
href: 'https://vuetifyjs.com/getting-started/frequently-asked-questions',
},
],
}),
};
</script>

View File

@ -1,7 +1,7 @@
<template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform"> <template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<div v-if="users != null"> <div v-if="items != null">
<v-dialog <v-dialog
v-model="deleteUserDialog" v-model="deleteItemDialog"
max-width="290"> max-width="290">
<v-card> <v-card>
<v-card-title class="headline">Delete template</v-card-title> <v-card-title class="headline">Delete template</v-card-title>
@ -16,7 +16,7 @@
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
flat="flat" flat="flat"
@click="deleteUserDialog = false" @click="deleteItemDialog = false"
> >
Cancel Cancel
</v-btn> </v-btn>
@ -33,84 +33,44 @@
</v-dialog> </v-dialog>
<v-dialog <v-dialog
v-model="userDialog" v-model="itemDialog"
max-width="290" max-width="290"
persistent persistent
> >
<v-card> <v-card>
<v-card-title class="headline">{{ isNewUser ? 'New user' : 'Edit user' }}</v-card-title> <v-card-title class="headline">
{{ isNewItem ? 'New Template' : 'Edit Template' }}
</v-card-title>
<v-alert <v-alert
:value="userFormError" :value="itemFormError"
color="error" color="error"
> >
{{ userFormError }} {{ itemFormError }}
</v-alert> </v-alert>
<v-card-text> <v-card-text>
<v-form <v-form
ref="userForm" ref="itemForm"
lazy-validation lazy-validation
v-model="userFormValid" v-model="itemFormValid"
> >
<div style="display: none">
<input type="password" tabindex="-1"/>
</div>
<v-text-field
v-model="user.username"
label="Username"
:rules="[v => !!v || 'Username is required']"
required
:disabled="!isNewUser || userFormSaving"
></v-text-field>
<v-text-field
v-model="user.email"
label="Email"
:rules="[v => !!v || 'Email is required']"
required
:disabled="userFormSaving"
></v-text-field>
<v-text-field
v-model="user.fullName"
label="Full Name"
:rules="[v => !!v || 'Full Name is required']"
required
:disabled="userFormSaving"
></v-text-field>
<v-select
:items="userTypes"
v-model="user.type"
label="Type"
:disabled="userFormSaving"
></v-select>
<v-text-field
v-model="user.password"
label="Password"
type="password"
:rules="[v => !v || v.length === 0 || v.length >= 6 || 'Min 6 characters']"
:disabled="userFormSaving"
></v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
flat="flat" text
:disabled="userFormSaving" :disabled="itemFormSaving"
@click="userDialog = false" @click="itemDialog = false"
> >
Cancel Cancel
</v-btn> </v-btn>
<v-btn <v-btn
color="blue darken-1" color="blue darken-1"
flat="flat" text
:disabled="userFormSaving" :disabled="itemFormSaving"
@click="saveUser" @click="saveUser"
> >
Save Save
@ -120,9 +80,9 @@
</v-dialog> </v-dialog>
<v-toolbar flat color="white"> <v-toolbar flat color="white">
<v-toolbar-title>Users</v-toolbar-title> <v-toolbar-title>Task Templates</v-toolbar-title>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn color="primary" @click="addUser">New User</v-btn> <v-btn color="primary" @click="addUser">New template</v-btn>
</v-toolbar> </v-toolbar>
<v-divider></v-divider> <v-divider></v-divider>
@ -130,8 +90,8 @@
<v-container> <v-container>
<v-data-table <v-data-table
:headers="headers" :headers="headers"
:items="users" :items="items"
hide-actions hide-default-footer
> >
<template v-slot:items="props"> <template v-slot:items="props">
<td>{{ props.item.username }}</td> <td>{{ props.item.username }}</td>
@ -167,51 +127,59 @@ import EventBus from '@/event-bus';
import { getErrorMessage } from '@/lib/error'; import { getErrorMessage } from '@/lib/error';
export default { export default {
props: {
projectId: Number,
},
data() { data() {
return { return {
userTypes: ['admin', 'user'],
headers: [ headers: [
{ {
text: 'Username', text: 'Alias',
value: 'username', value: 'alias',
}, },
{ {
text: 'Full Name', text: 'Playbook',
value: 'fullName', value: 'playbook',
sortable: false, sortable: false,
}, },
{ {
text: 'Email', text: 'SSH key',
value: 'email', value: 'email',
sortable: false, sortable: false,
}, },
{ {
text: 'Type', text: 'Inventory',
value: 'type', value: 'inventory',
sortable: false, sortable: false,
}, },
{ {
text: '', text: 'Environment',
value: 'environment',
sortable: false,
},
{
text: 'Repository',
value: 'repository',
sortable: false, sortable: false,
}, },
], ],
users: null, items: null,
user: {}, item: {},
isNewUser: false, isNewItem: false,
userDialog: false, itemDialog: false,
userFormValid: false, itemFormValid: false,
userFormError: null, itemFormError: null,
userFormSaving: false, itemFormSaving: false,
username: '', username: '',
fullName: '', fullName: '',
email: '', email: '',
type: '', type: '',
password: '', password: '',
deleteUserDialog: false, deleteItemDialog: false,
deleteUsername: null, deleteItemId: null,
}; };
}, },
@ -221,26 +189,26 @@ export default {
methods: { methods: {
askDeleteUser(username) { askDeleteUser(username) {
this.deleteUsername = username; this.deleteItemId = username;
this.deleteUserDialog = true; this.deleteItemDialog = true;
}, },
async deleteUser() { async deleteUser() {
try { try {
await axios({ await axios({
method: 'delete', method: 'delete',
url: `/api/users/${this.deleteUsername}`, url: `/api/project/${this.projectId}/${this.deleteItemId}`,
responseType: 'json', responseType: 'json',
}); });
const userIndex = this.users.findIndex((user) => user.username === this.deleteUsername); const userIndex = this.items.findIndex((item) => item.username === this.deleteItemId);
if (userIndex !== -1) { if (userIndex !== -1) {
this.users.splice(userIndex, 1); this.items.splice(userIndex, 1);
} }
EventBus.$emit('i-snackbar', { EventBus.$emit('i-snackbar', {
color: 'success', color: 'success',
text: `User "${this.deleteUsername}" deleted`, text: `User "${this.deleteItemId}" deleted`,
}); });
} catch (err) { } catch (err) {
EventBus.$emit('i-snackbar', { EventBus.$emit('i-snackbar', {
@ -248,7 +216,7 @@ export default {
text: getErrorMessage(err), text: getErrorMessage(err),
}); });
} finally { } finally {
this.deleteUserDialog = false; this.deleteItemDialog = false;
} }
}, },
@ -257,61 +225,61 @@ export default {
}, },
async editUser(username) { async editUser(username) {
this.isNewUser = !username; this.isNewItem = !username;
this.userFormError = null; this.itemFormError = null;
this.user = username ? (await axios({ this.item = username ? (await axios({
method: 'get', method: 'get',
url: `/api/templates/${username}`, url: `/api/project/${this.projectId}/templates/${username}`,
responseType: 'json', responseType: 'json',
})).data : { type: 'user' }; })).data : { type: 'item' };
this.itemDialog = true;
this.$refs.userForm.resetValidation();
this.userDialog = true;
}, },
async saveUser() { async saveUser() {
this.userFormError = null; this.itemFormError = null;
if (!this.$refs.userForm.validate()) { if (!this.$refs.itemForm.validate()) {
return; return;
} }
this.userFormSaving = true; this.itemFormSaving = true;
try { try {
await axios({ await axios({
method: this.isNewUser ? 'post' : 'put', method: this.isNewItem ? 'post' : 'put',
url: this.isNewUser ? '/api/templates' : `/api/templates/${this.user.id}`, url: this.isNewItem
? `/api/project/${this.projectId}/templates`
: `/api/project/${this.projectId}/templates/${this.item.id}`,
responseType: 'json', responseType: 'json',
data: this.user, data: this.item,
}); });
if (this.isNewUser) { if (this.isNewItem) {
this.users.push(this.user); this.items.push(this.item);
} else { } else {
const userIndex = this.users.findIndex((user) => this.user.id === user.id); const userIndex = this.items.findIndex((item) => this.item.id === item.id);
if (userIndex !== -1) { if (userIndex !== -1) {
this.users.splice(userIndex, 1, this.user); this.items.splice(userIndex, 1, this.item);
} }
} }
this.userDialog = false; this.itemDialog = false;
EventBus.$emit('i-snackbar', { EventBus.$emit('i-snackbar', {
color: 'success', color: 'success',
text: this.isNewUser ? `User "${this.user.username}" created` : `User "${this.user.username}" changed`, text: this.isNewItem ? `User "${this.item.username}" created` : `User "${this.item.username}" changed`,
}); });
} catch (err) { } catch (err) {
this.userFormError = getErrorMessage(err); this.itemFormError = getErrorMessage(err);
} finally { } finally {
this.userFormSaving = false; this.itemFormSaving = false;
} }
}, },
async loadUsers() { async loadUsers() {
this.users = (await axios({ this.items = (await axios({
method: 'get', method: 'get',
url: '/api/templates', url: `/api/project/${this.projectId}/templates`,
responseType: 'json', responseType: 'json',
})).data; })).data;
}, },