web: WIP edit measure configuration.

This commit is contained in:
Jonathan Bernard 2020-03-14 22:47:30 -05:00
parent c685f55d15
commit f4f695ce80
8 changed files with 139 additions and 17 deletions

View File

@ -8,6 +8,7 @@ import Measures from '@/views/Measures.vue';
import NewMeasure from '@/views/NewMeasure.vue';
import NewMeasurement from '@/views/NewMeasurement.vue';
import DeleteMeasure from '@/views/DeleteMeasure.vue';
import EditMeasure from '@/views/EditMeasure.vue';
import NotFound from '@/views/NotFound.vue';
import QuickPanels from '@/views/QuickPanels.vue';
import UserAccount from '@/views/UserAccount.vue';
@ -74,6 +75,11 @@ const router = new Router({
name: 'delete-measure',
component: DeleteMeasure
},
{
path: '/edit/measure/:slug',
name: 'edit-measure',
component: EditMeasure
},
{
path: '*',
name: 'not-found',

View File

@ -123,6 +123,11 @@ export class PmApiClient {
return resp.data;
}
public async updateMeasure<T extends MeasureConfig>(measure: Measure<T>): Promise<Measure<T>> {
const resp = await this.http.post(`/measures/${measure.slug}`, measure);
return resp.data;
}
public async deleteMeasure(slug: string): Promise<boolean> {
const resp = await this.http.delete(`/measures/${slug}`);
return true;

View File

@ -30,18 +30,24 @@ export class MeasureStoreModule extends VuexModule {
}
@Action({ rawError: true })
public async createMeasure(m: Measure<MeasureConfig>) {
public async createMeasure<T extends MeasureConfig>(m: Measure<T>) {
const newMeasure = await api.createMeasure(m);
this.context.commit('SET_MEASURE', newMeasure);
return newMeasure;
}
@Action({ rawError: true })
public async deleteMeasure(m: Measure<MeasureConfig>) {
public async deleteMeasure<T extends MeasureConfig>(m: Measure<T>) {
const delResponse = await api.deleteMeasure(m.slug);
this.context.commit('DELETE_MEASURE', m);
}
@Action({ rawError: true })
public async updateMeasure<T extends MeasureConfig>(m: Measure<T>) {
const updatedMeasure = await api.updateMeasure(m);
return updatedMeasure;
}
@Mutation private SET_MEASURE<T extends MeasureConfig>(measure: Measure<T>) {
this.measures = assign({}, this.measures, {[measure.slug]: measure});
}

View File

@ -0,0 +1,52 @@
<template>
<div id=edit-measure>
<div class=header>
<h1>Edit Measure</h1>
<h2>{{measure.name}}</h2>
</div>
<form @submit.prevent=updateMeasure() class=edit-measure-form>
<fieldset>
<div>
<label for=measureName>Display Name</label>
<input
:disabled=waiting
type=text
name=measureName
placeholder="what you are measuring"
required
v-model="measure.name" />
</div>
<div>
<label for=measureDescription>Description</label>
<textarea
:disabled=waiting
name=measureDescription
placeholder="optional description"
v-model="measure.description" ></textarea>
</div>
<div>
<label for=measureSlug>Short name (slug)</label>
<input
:disabled=waiting
type=text
name=measureDescription
:placeholder='slugFromName + " (default)"'
:value="measure.slug"
@input="measure.slug = slugify($event.target.value)"/>
</div>
</fieldset>
<MeasureConfigForm
v-model=measure.config
:disabled=waiting
measureExists=false />
<div v-if='!waiting' class=form-actions>
<button class=btn-action>Update</button>
<a class=btn @click="$router.go(-1)">Cancel</a>
</div>
<div v-if='waiting' class=form-waiting>
<div class=wait-spinner>working <fa-icon icon=sync spin /></div>
</div>
</form>
</div>
</template>
<script lang=ts src=./edit-measure.ts></script>

View File

@ -5,12 +5,26 @@
<h1>{{measure.name}}</h1>
<h2>{{measure.description}}</h2>
</div>
<router-link title="Delete Measure" :to="'/delete/measure/' + measure.slug" class=btn>
<fa-icon icon=trash></fa-icon>
</router-link>
<router-link :to="'/new/measurement/' + measure.slug" class=btn-action>
Add Measurement
</router-link>
<div class=actions>
<router-link
title="Delete Measure"
:to="'/delete/measure/' + measure.slug"
class=btn-icon >
<fa-icon icon=trash></fa-icon>
</router-link>
<router-link
title="Edit Measure"
:to="'/edit/measure/' + measure.slug"
class=btn-icon>
<fa-icon icon=pencil-alt></fa-icon>
</router-link>
<router-link
title="Add Measurement"
:to="'/new/measurement/' + measure.slug"
class=btn-action>
Add Measurement
</router-link>
</div>
</div>
<MeasureDetails :measure=measure :measurements=measurements />
</div>

View File

@ -0,0 +1,43 @@
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { logService } from '@/services/logging';
import { measureStore, userStore } from '@/store';
import { Measure, MeasureConfig, MeasureType } from '@/models';
import MeasureConfigForm from '@/components/measure-config/MeasureConfigForm.vue';
import { slugify } from '@/util';
const logger = logService.getLogger('/views/edit-measure');
@Component({
components: { MeasureConfigForm }
})
export class EditMeasure extends Vue {
private waiting = false;
private get measure(): Measure<MeasureConfig> | null {
return measureStore.measures[this.$route.params.slug] || null;
}
private get slugFromName() {
return slugify(this.measure.name);
}
private async updateMeasure() {
if (this.measure) {
if (!this.measure.slug) {
this.measure.slug = slugify(this.measure.name);
}
this.waiting = true;
try {
await measureStore.updateMeasure(this.measure);
this.$router.push({name: 'measure', params: { slug: this.measure.slug }});
} catch (e) {
logger.error('Unable to update measure. \n\t' + JSON.stringify(this.measure), e.stack);
} finally {
this.waiting = false;
}
}
}
}
export default EditMeasure;

View File

@ -1,10 +1,12 @@
import { Component, Prop, Vue } from 'vue-property-decorator';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faPencilAlt } from '@fortawesome/free-solid-svg-icons';
import { faTrash } from '@fortawesome/free-solid-svg-icons';
import { Measure as MeasureModel, MeasureConfig } from '@/models';
import { measureStore, measurementStore } from '@/store';
import MeasureDetails from '@/components/measure-details/MeasureDetails.vue';
library.add(faPencilAlt);
library.add(faTrash);
@Component({

View File

@ -5,6 +5,7 @@ import { logService } from '@/services/logging';
import { measureStore, userStore } from '@/store';
import { Measure, MeasureConfig, MeasureType } from '@/models';
import MeasureConfigForm from '@/components/measure-config/MeasureConfigForm.vue';
import { slugify } from '@/util';
library.add(faSync);
@ -29,19 +30,12 @@ export class NewMeasure extends Vue {
};
private get slugFromName() {
return this.slugify(this.measure.name);
}
private slugify(s: string): string {
return s
.toLowerCase()
.replace(/[^\w\s\-]/g, '')
.replace(/\s+/g, '-');
return slugify(this.measure.name);
}
private async createMeasure() {
if (!this.measure.slug) {
this.measure.slug = this.slugify(this.measure.name);
this.measure.slug = slugify(this.measure.name);
}
this.waiting = true;