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