From 9d9f8c4f9b6d5e5a608de6236d1146950b461054 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Thu, 11 Apr 2019 09:24:47 -0500 Subject: [PATCH] web: WIP work on adding create measure functionality in the UI. --- .../measure-config/MeasureConfigForm.vue | 10 ++++- .../measure-config/measure-config-form.ts | 11 +++++- web/src/main.ts | 3 ++ web/src/services/pm-api-client.ts | 2 +- web/src/store-modules/measure.ts | 8 ++++ web/src/styles/ui-common.scss | 38 ++++++++++++++++++- web/src/views/NewMeasure.vue | 27 +++++++++---- web/src/views/UserAccount.vue | 22 +++++++---- web/src/views/measures.scss | 13 +++++++ web/src/views/new-measure.scss | 17 +-------- web/src/views/new-measure.ts | 34 +++++++++++++++-- 11 files changed, 144 insertions(+), 41 deletions(-) diff --git a/web/src/components/measure-config/MeasureConfigForm.vue b/web/src/components/measure-config/MeasureConfigForm.vue index a11a3d7..8bb5e24 100644 --- a/web/src/components/measure-config/MeasureConfigForm.vue +++ b/web/src/components/measure-config/MeasureConfigForm.vue @@ -2,12 +2,18 @@
-
-
Show by default.
+
+ + +
diff --git a/web/src/components/measure-config/measure-config-form.ts b/web/src/components/measure-config/measure-config-form.ts index 1f7ab20..e722693 100644 --- a/web/src/components/measure-config/measure-config-form.ts +++ b/web/src/components/measure-config/measure-config-form.ts @@ -1,10 +1,17 @@ -import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; +import { Component, Emit, Prop, Vue, Watch } from 'vue-property-decorator'; import { logService } from '@/services/logging'; import { Measure, MeasureConfig, MeasureType } from '@/models'; @Component({}) export class MeasureConfigForm extends Vue { - @Prop({}) public config!: MeasureConfig; + @Prop({}) public value!: MeasureConfig; + @Prop({}) public disabled: boolean = false; + + @Watch('value', { immediate: true, deep: true }) + @Emit('input') + private onConfigChanged(newVal: MeasureConfig, oldVal: MeasureConfig) { + return newVal; + } } export default MeasureConfigForm; diff --git a/web/src/main.ts b/web/src/main.ts index 35369f8..0a325ee 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -5,6 +5,7 @@ import App from './App.vue'; import { store } from './store'; import router from './router'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; +import { dom as FA_DOM} from '@fortawesome/fontawesome-svg-core'; import SmartTable from 'vuejs-smart-table'; import ApexChart from 'vue-apexcharts'; @@ -13,6 +14,8 @@ import './registerServiceWorker'; import { logService, LogLevel, ApiLogAppender, ConsoleLogAppender } from '@/services/logging'; Vue.component('fa-icon', FontAwesomeIcon); +FA_DOM.watch(); + Vue.component('apex-chart', ApexChart); Vue.use(SmartTable); diff --git a/web/src/services/pm-api-client.ts b/web/src/services/pm-api-client.ts index f3f603e..816fd87 100644 --- a/web/src/services/pm-api-client.ts +++ b/web/src/services/pm-api-client.ts @@ -114,7 +114,7 @@ export class PmApiClient { } public async createMeasure(measure: Measure): Promise> { - const resp = await this.http.post(`/measures`); + const resp = await this.http.post(`/measures`, measure); return resp.data; } diff --git a/web/src/store-modules/measure.ts b/web/src/store-modules/measure.ts index 7afeaed..d6351e4 100644 --- a/web/src/store-modules/measure.ts +++ b/web/src/store-modules/measure.ts @@ -24,6 +24,14 @@ export class MeasureStoreModule extends VuexModule { public async fetchMeasure(slug: string) { const measure = api.getMeasure(slug); this.context.commit('SET_MEASURE', measure); + return measure; + } + + @Action({ rawError: true }) + public async createMeasure(m: Measure) { + const newMeasure = await api.createMeasure(m); + this.context.commit('SET_MEASURE', newMeasure); + return newMeasure; } @Mutation private SET_MEASURE(measure: Measure) { diff --git a/web/src/styles/ui-common.scss b/web/src/styles/ui-common.scss index ed8e4d0..bc0d4c0 100644 --- a/web/src/styles/ui-common.scss +++ b/web/src/styles/ui-common.scss @@ -6,6 +6,7 @@ border-radius: .25em; cursor: pointer; font-family: $body-font; + font-size: inherit; font-weight: bold; padding: .5em 1em; @@ -15,12 +16,21 @@ .btn-action { background-color: $color2; color: $color3; + cursor: pointer; position: relative; &:hover { background-color: darken($color2, 5%); } +} +.form-waiting .wait-spinner { + border: solid thin $fg-primary; + border-radius: .25em; + cursor: wait; + font-family: $body-font; + font-size: inherit; + padding: .5em 1em; } a.btn, @@ -43,8 +53,34 @@ a.btn-action { text-decoration: none; } .main { flex-grow: 1; } +form { + display: flex; + flex-direction: column; + justify-content: space-between; + + label { + display: inline-block; + margin: .5rem 0; + min-width: 10em; + } + + select { background-color: white; } + + .form-actions, + .form-waiting { + display: flex; + flex-direction: row-reverse; + } +} + input, -select { +select, +textarea { font-size: inherit; padding: .35em .5em; + + &:disabled { cursor: wait; } } + +textarea { font-family: $body-font; } + diff --git a/web/src/views/NewMeasure.vue b/web/src/views/NewMeasure.vue index f522f3c..fdcdacd 100644 --- a/web/src/views/NewMeasure.vue +++ b/web/src/views/NewMeasure.vue @@ -4,34 +4,45 @@

New Measure

What do you want to measure?

-
+
- + v-model="measure.description" >
- + + :placeholder='slugFromName + " (default)"' + :value="measure.slug" + @input="measure.slug = slugify($event.target.value)"/>
- + +
+ + Cancel +
+
+
working
+
diff --git a/web/src/views/UserAccount.vue b/web/src/views/UserAccount.vue index 0ff3a1f..81de96b 100644 --- a/web/src/views/UserAccount.vue +++ b/web/src/views/UserAccount.vue @@ -1,16 +1,19 @@ diff --git a/web/src/views/measures.scss b/web/src/views/measures.scss index 83a154d..453c1b9 100644 --- a/web/src/views/measures.scss +++ b/web/src/views/measures.scss @@ -8,3 +8,16 @@ margin-right: 2rem; } } + +.measure-list { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-evenly; + + .measure-summary { + height: 12rem; + width: 12rem; + } +} + diff --git a/web/src/views/new-measure.scss b/web/src/views/new-measure.scss index 0b8e05c..3a62685 100644 --- a/web/src/views/new-measure.scss +++ b/web/src/views/new-measure.scss @@ -1,7 +1,8 @@ @import '~@/styles/vars'; input, -select { +select, +textarea { // background-color: $bg-primary; /* @@ -13,17 +14,3 @@ select { border: solid thin $color1; border-radius: 4px; } - -select { background-color: white; } - -form { - display: flex; - flex-direction: column; - justify-content: space-between; - - label { - display: inline-block; - margin: .5rem 0; - min-width: 10em; - } -} diff --git a/web/src/views/new-measure.ts b/web/src/views/new-measure.ts index 5d86ea9..5ccef19 100644 --- a/web/src/views/new-measure.ts +++ b/web/src/views/new-measure.ts @@ -1,16 +1,20 @@ import { Component, Prop, Vue, Watch } from 'vue-property-decorator'; +import { library } from '@fortawesome/fontawesome-svg-core'; +import { faSync } from '@fortawesome/free-solid-svg-icons'; import { logService } from '@/services/logging'; -import { userStore } from '@/store'; +import { measureStore, userStore } from '@/store'; import { Measure, MeasureConfig, MeasureType } from '@/models'; import MeasureConfigForm from '@/components/measure-config/MeasureConfigForm.vue'; +library.add(faSync); + const logger = logService.getLogger('/views/new-measure'); @Component({ components: { MeasureConfigForm } }) export class NewMeasure extends Vue { - private test: string = 'test'; + private waiting = false; private measure: Measure = { id: '', config: { @@ -24,11 +28,33 @@ export class NewMeasure extends Vue { }; private get slugFromName() { - return this.measure.name + return this.slugify(this.measure.name); + } + + private slugify(s: string): string { + return s .toLowerCase() - .replace(/[^\w\s]/g, '') + .replace(/[^\w\s\-]/g, '') .replace(/\s+/g, '-'); } + + private async createMeasure() { + if (!this.measure.slug) { + this.measure.slug = this.slugify(this.measure.name); + } + + this.waiting = true; + try { + await measureStore.createMeasure(this.measure); + this.$router.push({ name: 'measures' }); + } catch (e) { + // TODO: show errors + logger.error('Unable to create measure. \n\t ' + JSON.stringify(this.measure), e.stack); + } finally { + this.waiting = false; + } + } + } export default NewMeasure;