Initial set of pages.

This commit is contained in:
James Cole
2022-02-27 10:14:08 +01:00
parent e60320a9be
commit 3a49af94d0
60 changed files with 11404 additions and 0 deletions

View File

@@ -0,0 +1,260 @@
<template>
<q-page>
<div class="row q-mx-md">
<div class="col-12">
<q-banner inline-actions rounded class="bg-orange text-white" v-if="'' !== errorMessage">
{{ errorMessage }}
<template v-slot:action>
<q-btn flat @click="dismissBanner" label="Dismiss"/>
</template>
</q-banner>
</div>
</div>
<div class="row q-mx-md q-mt-md">
<div class="col-12">
<q-card bordered>
<q-card-section>
<div class="text-h6">Info for new webhook</div>
</q-card-section>
<q-card-section>
<div class="row">
<div class="col-12 q-mb-xs">
<q-input
:error-message="submissionErrors.title"
:error="hasSubmissionErrors.title"
bottom-slots :disable="disabledInput" type="text" clearable v-model="title" :label="$t('form.title')"
outlined/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-input
:error-message="submissionErrors.url"
:error="hasSubmissionErrors.url"
bottom-slots :disable="disabledInput" type="text" clearable v-model="url" :label="$t('form.url')"
outlined/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-select
:error-message="submissionErrors.response"
:error="hasSubmissionErrors.response"
bottom-slots
:disable="disabledInput"
outlined
v-model="response"
emit-value class="q-pr-xs"
map-options :options="responses" label="Response"/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-select
:error-message="submissionErrors.delivery"
:error="hasSubmissionErrors.delivery"
bottom-slots
:disable="disabledInput"
outlined
v-model="delivery"
emit-value class="q-pr-xs"
map-options :options="deliveries" label="Delivery"/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-select
:error-message="submissionErrors.trigger"
:error="hasSubmissionErrors.trigger"
bottom-slots
:disable="disabledInput"
outlined
v-model="trigger"
emit-value class="q-pr-xs"
map-options :options="triggers" label="Triggers"/>
</div>
</div>
</q-card-section>
</q-card>
</div>
</div>
<div class="row q-mx-md">
<div class="col-12">
<q-card class="q-mt-xs">
<q-card-section>
<div class="row">
<div class="col-12 text-right">
<q-btn :disable="disabledInput" color="primary" label="Submit" @click="submitWebhook"/>
</div>
</div>
<div class="row">
<div class="col-12 text-right">
<q-checkbox :disable="disabledInput" v-model="doReturnHere" left-label
label="Return here to create another one"/>
<br/>
<q-checkbox v-model="doResetForm" left-label :disable="!doReturnHere || disabledInput"
label="Reset form after submission"/>
</div>
</div>
</q-card-section>
</q-card>
</div>
</div>
</q-page>
</template>
<script>
import Post from "../../api/webhooks/post";
import {mapGetters} from "vuex";
import {getCacheKey} from "../../store/fireflyiii/getters";
export default {
name: 'Create',
data() {
return {
submissionErrors: {},
hasSubmissionErrors: {},
submitting: false,
doReturnHere: false,
doResetForm: false,
errorMessage: '',
balance_input_mask: '#.##',
// values:
triggers: [
{value: 'TRIGGER_STORE_TRANSACTION', label: 'When transaction stored'},
{value: 'TRIGGER_UPDATE_TRANSACTION', label: 'When transaction updated'},
{value: 'TRIGGER_DESTROY_TRANSACTION', label: 'When transaction deleted'}
],
responses: [
{value: 'RESPONSE_TRANSACTIONS', label: 'Send transaction'},
{value: 'RESPONSE_ACCOUNTS', label: 'Send accounts'},
{value: 'RESPONSE_NONE', label: 'Send nothing'},
],
deliveries: [
{value: 'DELIVERY_JSON', label: 'JSON'}
],
// webhook fields:
title: '',
url: '',
response: 'RESPONSE_TRANSACTIONS',
delivery: 'DELIVERY_JSON',
trigger: 'TRIGGER_STORE_TRANSACTION',
}
},
watch: {},
computed: {
...mapGetters('fireflyiii', ['getCacheKey']),
disabledInput: function () {
return this.submitting;
}
},
created() {
this.resetForm();
},
methods: {
resetForm: function () {
this.title = '';
},
resetErrors: function () {
this.submissionErrors =
{
title: '',
url: '',
response: '',
delivery: '',
trigger: '',
};
this.hasSubmissionErrors = {
title: false,
url: false,
response: false,
delivery: false,
trigger: false,
};
},
submitWebhook: function () {
this.submitting = true;
this.errorMessage = '';
// reset errors:
this.resetErrors();
// build category array
const submission = this.buildWebhook();
(new Post())
.post(submission)
.catch(this.processErrors)
.then(this.processSuccess);
},
buildWebhook: function () {
return {
title: this.title,
url: this.url,
response: this.response,
delivery: this.delivery,
trigger: this.trigger,
active: true,
};
},
dismissBanner: function () {
this.errorMessage = '';
},
processSuccess: function (response) {
if (!response) {
return;
}
this.submitting = false;
let message = {
level: 'success',
text: 'I am new webhook',
show: true,
action: {
show: true,
text: 'Go to webhook',
link: {name: 'webhooks.show', params: {id: parseInt(response.data.data.id)}}
}
};
// store flash
this.$q.localStorage.set('flash', message);
if (this.doReturnHere) {
window.dispatchEvent(new CustomEvent('flash', {
detail: {
flash: this.$q.localStorage.getItem('flash')
}
}));
}
if (!this.doReturnHere) {
// return to previous page.
this.$router.go(-1);
}
},
processErrors: function (error) {
if (error.response) {
let errors = error.response.data; // => the response payload
this.errorMessage = errors.message;
console.log(errors);
for (let i in errors.errors) {
if (errors.errors.hasOwnProperty(i)) {
this.submissionErrors[i] = errors.errors[i][0];
this.hasSubmissionErrors[i] = true;
}
}
}
this.submitting = false;
},
}
}
</script>

View File

@@ -0,0 +1,266 @@
<template>
<q-page>
<div class="row q-mx-md">
<div class="col-12">
<q-banner inline-actions rounded class="bg-orange text-white" v-if="'' !== errorMessage">
{{ errorMessage }}
<template v-slot:action>
<q-btn flat @click="dismissBanner" label="Dismiss"/>
</template>
</q-banner>
</div>
</div>
<div class="row q-mx-md q-mt-md">
<div class="col-12">
<q-card bordered>
<q-card-section>
<div class="text-h6">Edit webhook</div>
</q-card-section>
<q-card-section>
<div class="row">
<div class="col-12 q-mb-xs">
<q-input
:error-message="submissionErrors.title"
:error="hasSubmissionErrors.title"
bottom-slots :disable="disabledInput" type="text" clearable v-model="title" :label="$t('form.title')"
outlined/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-input
:error-message="submissionErrors.url"
:error="hasSubmissionErrors.url"
bottom-slots :disable="disabledInput" type="text" clearable v-model="url" :label="$t('form.url')"
outlined/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-select
:error-message="submissionErrors.response"
:error="hasSubmissionErrors.response"
bottom-slots
:disable="disabledInput"
outlined
v-model="response"
emit-value class="q-pr-xs"
map-options :options="responses" label="Response"/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-select
:error-message="submissionErrors.delivery"
:error="hasSubmissionErrors.delivery"
bottom-slots
:disable="disabledInput"
outlined
v-model="delivery"
emit-value class="q-pr-xs"
map-options :options="deliveries" label="Delivery"/>
</div>
</div>
<div class="row">
<div class="col-12 q-mb-xs">
<q-select
:error-message="submissionErrors.trigger"
:error="hasSubmissionErrors.trigger"
bottom-slots
:disable="disabledInput"
outlined
v-model="trigger"
emit-value class="q-pr-xs"
map-options :options="triggers" label="Triggers"/>
</div>
</div>
</q-card-section>
</q-card>
</div>
</div>
<div class="row q-mx-md">
<div class="col-12">
<q-card class="q-mt-xs">
<q-card-section>
<div class="row">
<div class="col-12 text-right">
<q-btn :disable="disabledInput" color="primary" label="Update" @click="submitWebhook"/>
</div>
</div>
<div class="row">
<div class="col-12 text-right">
<q-checkbox :disable="disabledInput" v-model="doReturnHere" left-label label="Return here"/>
</div>
</div>
</q-card-section>
</q-card>
</div>
</div>
</q-page>
</template>
<script>
import Get from "../../api/webhooks/get";
import Put from "../../api/webhooks/put";
export default {
name: "Edit",
data() {
return {
submissionErrors: {},
hasSubmissionErrors: {},
submitting: false,
doReturnHere: false,
doResetForm: false,
errorMessage: '',
// webhook options
triggers: [
{value: 'TRIGGER_STORE_TRANSACTION', label: 'When transaction stored'},
{value: 'TRIGGER_UPDATE_TRANSACTION', label: 'When transaction updated'},
{value: 'TRIGGER_DESTROY_TRANSACTION', label: 'When transaction deleted'}
],
responses: [
{value: 'RESPONSE_TRANSACTIONS', label: 'Send transaction'},
{value: 'RESPONSE_ACCOUNTS', label: 'Send accounts'},
{value: 'RESPONSE_NONE', label: 'Send nothing'},
],
deliveries: [
{value: 'DELIVERY_JSON', label: 'JSON'}
],
// webhook fields:
id: 0,
title: '',
url: '',
response: '',
delivery: '',
trigger: '',
}
},
computed: {
disabledInput: function () {
return this.submitting;
}
},
created() {
this.id = parseInt(this.$route.params.id);
this.collectWebhook();
},
methods: {
collectWebhook: function () {
let get = new Get;
get.get(this.id).then((response) => this.parseWebhook(response));
},
parseWebhook: function (response) {
this.title = response.data.data.attributes.title;
this.url = response.data.data.attributes.url;
this.response = response.data.data.attributes.response;
this.delivery = response.data.data.attributes.delivery;
this.trigger = response.data.data.attributes.trigger;
},
resetErrors: function () {
this.submissionErrors =
{
title: '',
url: '',
response: '',
delivery: '',
trigger: '',
};
this.hasSubmissionErrors = {
title: false,
url: false,
response: false,
delivery: false,
trigger: false,
};
},
submitWebhook: function () {
this.submitting = true;
this.errorMessage = '';
// reset errors:
this.resetErrors();
// build account array
const submission = this.buildWebhook();
(new Put())
.put(this.id, submission)
.catch(this.processErrors)
.then(this.processSuccess);
},
buildWebhook: function () {
return {
title: this.title,
url: this.url,
response: this.response,
delivery: this.delivery,
trigger: this.trigger
};
},
dismissBanner: function () {
this.errorMessage = '';
},
processSuccess: function (response) {
this.$store.dispatch('fireflyiii/refreshCacheKey');
if (!response) {
return;
}
this.submitting = false;
let message = {
level: 'success',
text: 'Webhook is updated',
show: true,
action: {
show: true,
text: 'Go to webhook',
link: {name: 'webhooks.show', params: {id: parseInt(response.data.data.id)}}
}
};
// store flash
this.$q.localStorage.set('flash', message);
if (this.doReturnHere) {
window.dispatchEvent(new CustomEvent('flash', {
detail: {
flash: this.$q.localStorage.getItem('flash')
}
}));
}
if (!this.doReturnHere) {
// return to previous page.
this.$router.go(-1);
}
},
processErrors: function (error) {
if (error.response) {
let errors = error.response.data; // => the response payload
this.errorMessage = errors.message;
console.log(errors);
for (let i in errors.errors) {
if (errors.errors.hasOwnProperty(i)) {
this.submissionErrors[i] = errors.errors[i][0];
this.hasSubmissionErrors[i] = true;
}
}
}
this.submitting = false;
},
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,166 @@
<template>
<q-page>
<q-table
:title="$t('firefly.webhooks')"
:rows="rows"
:columns="columns"
row-key="id"
@request="onRequest"
v-model:pagination="pagination"
:loading="loading"
class="q-ma-md"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
>
{{ col.label }}
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td key="title" :props="props">
<router-link :to="{ name: 'webhooks.show', params: {id: props.row.id} }" class="text-primary">
{{ props.row.title }}
</router-link>
</q-td>
<q-td key="menu" :props="props">
<q-btn-dropdown color="primary" label="Actions" size="sm">
<q-list>
<q-item clickable v-close-popup :to="{name: 'webhooks.edit', params: {id: props.row.id}}">
<q-item-section>
<q-item-label>Edit</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="deleteWebhook(props.row.id, props.row.title)">
<q-item-section>
<q-item-label>Delete</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</q-td>
</q-tr>
</template>
</q-table>
<q-page-sticky position="bottom-right" :offset="[18, 18]">
<q-fab
label="Actions"
square
vertical-actions-align="right"
label-position="left"
color="green"
icon="fas fa-chevron-up"
direction="up"
>
<q-fab-action color="primary" square :to="{ name: 'webhooks.create'}" icon="fas fa-exchange-alt"
label="New webhook"/>
</q-fab>
</q-page-sticky>
</q-page>
</template>
<script>
import {mapGetters} from "vuex";
import Destroy from "../../api/webhooks/destroy";
import List from "../../api/webhooks/list";
export default {
name: 'Index',
watch: {
$route(to) {
// react to route changes...
if ('webhooks.index' === to.name) {
this.page = 1;
this.updateBreadcrumbs();
this.triggerUpdate();
}
}
},
data() {
return {
rows: [],
pagination: {
sortBy: 'desc',
descending: false,
page: 1,
rowsPerPage: 5,
rowsNumber: 100
},
loading: false,
columns: [
{name: 'title', label: 'Title', field: 'title', align: 'left'},
{name: 'menu', label: ' ', field: 'menu', align: 'right'},
],
}
},
computed: {
...mapGetters('fireflyiii', ['getCacheKey', 'getListPageSize']),
},
created() {
this.pagination.rowsPerPage = this.getListPageSize;
},
mounted() {
this.triggerUpdate();
},
methods: {
deleteWebhook: function (id, name) {
this.$q.dialog({
title: 'Confirm',
message: 'Do you want to delete webhook "' + name + '"?',
cancel: true,
persistent: true
}).onOk(() => {
this.destroyWebhook(id);
});
},
destroyWebhook: function (id) {
let destr = new Destroy;
destr.destroy(id).then(() => {
this.$store.dispatch('fireflyiii/refreshCacheKey');
this.triggerUpdate();
});
},
updateBreadcrumbs: function () {
this.$route.meta.pageTitle = 'firefly.webhooks';
this.$route.meta.breadcrumbs = [{title: 'webhooks'}];
},
onRequest: function (props) {
this.page = props.pagination.page;
this.triggerUpdate();
},
triggerUpdate: function () {
if (this.loading) {
return;
}
this.loading = true;
const list = new List();
this.rows = [];
list.list(this.page, this.getCacheKey).then(
(response) => {
this.pagination.rowsPerPage = response.data.meta.pagination.per_page;
this.pagination.rowsNumber = response.data.meta.pagination.total;
this.pagination.page = this.page;
for (let i in response.data.data) {
if (response.data.data.hasOwnProperty(i)) {
let current = response.data.data[i];
let account = {
id: current.id,
title: current.attributes.title,
};
this.rows.push(account);
}
}
this.loading = false;
}
)
;
}
}
}
</script>

View File

@@ -0,0 +1,53 @@
<template>
<q-page>
<div class="row q-mx-md">
<div class="col-12">
<!-- Balance chart -->
<q-card bordered>
<q-card-section>
<div class="text-h6">{{ webhook.title }}</div>
</q-card-section>
<q-card-section>
<div class="row">
<div class="col-12 q-mb-xs">
Name: {{ webhook.title }}<br>
</div>
</div>
</q-card-section>
</q-card>
</div>
</div>
</q-page>
</template>
<script>
import Get from "../../api/webhooks/get";
export default {
name: "Show",
data() {
return {
webhook: {},
id: 0
}
},
created() {
this.id = parseInt(this.$route.params.id);
this.getWebhook();
},
methods: {
getWebhook: function () {
(new Get).get(this.id).then((response) => this.parseWebhook(response));
},
parseWebhook: function (response) {
this.webhook = {
title: response.data.data.attributes.title,
};
},
}
}
</script>
<style scoped>
</style>