From 622fed8e2ac89849c78470a3223c6d46bcd3c0e8 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Fri, 5 Apr 2019 00:47:19 -0500 Subject: [PATCH] WIP Adding simple measurement view. --- web/package-lock.json | 114 ++++++++++++++++++++++-- web/package.json | 2 + web/src/components/MeasureSummary.vue | 8 ++ web/src/components/measure-summary.scss | 9 ++ web/src/components/measure-summary.ts | 27 ++++++ web/src/main.ts | 2 + web/src/services/pm-api-client.ts | 22 ++--- web/src/store-modules/measure.ts | 6 +- web/src/store-modules/measurement.ts | 21 +++++ web/src/store.ts | 3 + web/src/types/global.d.ts | 1 + web/src/views/Measures.vue | 10 ++- web/src/views/measures.ts | 8 +- 13 files changed, 205 insertions(+), 28 deletions(-) create mode 100644 web/src/components/MeasureSummary.vue create mode 100644 web/src/components/measure-summary.scss create mode 100644 web/src/components/measure-summary.ts create mode 100644 web/src/store-modules/measurement.ts create mode 100644 web/src/types/global.d.ts diff --git a/web/package-lock.json b/web/package-lock.json index 7f5048e..02bc19f 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1744,6 +1744,21 @@ } } }, + "apexcharts": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.6.5.tgz", + "integrity": "sha512-HSDNjTPMEpQaM0MadPj9f6gNvBKSmQXuC100h4Ev2mQFjC1rJId6b1KgF2yKh0In+iXuTXxszI58ozWhKNkbYQ==", + "requires": { + "promise-polyfill": "8.1.0", + "svg.draggable.js": "^2.2.1", + "svg.easing.js": "^2.0.0", + "svg.filter.js": "^2.0.2", + "svg.js": "^2.6.6", + "svg.pathmorphing.js": "^0.1.3", + "svg.resize.js": "^1.4.1", + "svg.select.js": "^2.1.2" + } + }, "append-transform": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", @@ -6865,7 +6880,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -6893,6 +6909,7 @@ "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6907,7 +6924,8 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", @@ -6918,7 +6936,8 @@ "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -7035,7 +7054,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -7047,6 +7067,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7061,6 +7082,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7068,12 +7090,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -7092,6 +7116,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -7172,7 +7197,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -7184,6 +7210,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -7269,7 +7296,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -7305,6 +7333,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7324,6 +7353,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7367,12 +7397,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -11900,6 +11932,11 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "promise-polyfill": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.0.tgz", + "integrity": "sha512-OzSf6gcCUQ01byV4BgwyUCswlaQQ6gzXc23aLQWhicvfX9kfsUiUhgt3CCQej8jDnl8/PhGF31JdHX2/MzF3WA==" + }, "prompts": { "version": "0.1.14", "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", @@ -13687,6 +13724,60 @@ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", "dev": true }, + "svg.draggable.js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz", + "integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==", + "requires": { + "svg.js": "^2.0.1" + } + }, + "svg.easing.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz", + "integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=", + "requires": { + "svg.js": ">=2.3.x" + } + }, + "svg.filter.js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz", + "integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=", + "requires": { + "svg.js": "^2.2.5" + } + }, + "svg.js": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz", + "integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==" + }, + "svg.pathmorphing.js": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz", + "integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==", + "requires": { + "svg.js": "^2.4.0" + } + }, + "svg.resize.js": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz", + "integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==", + "requires": { + "svg.js": "^2.6.5", + "svg.select.js": "^2.1.2" + } + }, + "svg.select.js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz", + "integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==", + "requires": { + "svg.js": "^2.2.5" + } + }, "svgo": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.1.1.tgz", @@ -14594,6 +14685,11 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.7.tgz", "integrity": "sha512-g7ADfQ82QU+j6F/bVDioVQf2ccIMYLuR4E8ev+RsDBlmwRkhGO3HhgF4PF9vpwjdPpxyb1zzLur2nQ2oIMAMEg==" }, + "vue-apexcharts": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/vue-apexcharts/-/vue-apexcharts-1.3.2.tgz", + "integrity": "sha512-3a3v6FKUlpD3BHWiDhuN/7Jcho9pE3+r6PEUccdzfpRFj0jn9W+zAHtaiKrdbBsTqXPKDfbd4dkT25SvBo/cxw==" + }, "vue-class-component": { "version": "6.3.2", "resolved": "https://registry.npmjs.org/vue-class-component/-/vue-class-component-6.3.2.tgz", diff --git a/web/package.json b/web/package.json index e04caf3..46926c8 100644 --- a/web/package.json +++ b/web/package.json @@ -14,12 +14,14 @@ "@fortawesome/vue-fontawesome": "^0.1.5", "@types/js-cookie": "^2.2.1", "@types/lodash.merge": "^4.6.5", + "apexcharts": "^3.6.5", "axios": "^0.18.0", "js-cookie": "^2.2.0", "keen-ui": "^1.1.2", "lodash.merge": "^4.6.1", "register-service-worker": "^1.5.2", "vue": "^2.6.6", + "vue-apexcharts": "^1.3.2", "vue-class-component": "^6.0.0", "vue-property-decorator": "^7.0.0", "vue-router": "^3.0.1", diff --git a/web/src/components/MeasureSummary.vue b/web/src/components/MeasureSummary.vue new file mode 100644 index 0000000..d21d044 --- /dev/null +++ b/web/src/components/MeasureSummary.vue @@ -0,0 +1,8 @@ + + + diff --git a/web/src/components/measure-summary.scss b/web/src/components/measure-summary.scss new file mode 100644 index 0000000..6bb0562 --- /dev/null +++ b/web/src/components/measure-summary.scss @@ -0,0 +1,9 @@ +@import '~@/styles/vars'; + +.measure-summary { + display: inline-block; + + h2 { + border-bottom: solid thin $fg-primary; + } +} diff --git a/web/src/components/measure-summary.ts b/web/src/components/measure-summary.ts new file mode 100644 index 0000000..1b7f5ba --- /dev/null +++ b/web/src/components/measure-summary.ts @@ -0,0 +1,27 @@ +import { Component, Prop, Vue } from 'vue-property-decorator'; +import { Measure, MeasureConfig, Measurement, MeasurementMeta } from '@/models'; +import { measurementStore } from '@/store'; + +@Component +export class MeasureSummary extends Vue { + @Prop() private measure!: Measure; + + private chartOptions = { + chart: { sparkline: { enabled: true } }, + grid: { padding: { top: 20 }}, + stroke: { curve: 'smooth' } + }; + + private chartData = [ + { name: 'Test', data: [1, 10, 4, 6, 2] } + ]; + + private measurements: Array> = []; + + private mounted() { + this.measurements = + } + +} + +export default MeasureSummary; diff --git a/web/src/main.ts b/web/src/main.ts index dbe10c7..b2d1cb6 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -7,10 +7,12 @@ import router from './router'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; import SmartTable from 'vuejs-smart-table'; +import ApexChart from 'vue-apexcharts'; import './registerServiceWorker'; Vue.component('fa-icon', FontAwesomeIcon); +Vue.component('apex-chart', ApexChart); Vue.use(SmartTable); new Vue({ diff --git a/web/src/services/pm-api-client.ts b/web/src/services/pm-api-client.ts index c0bb4de..9f0abec 100644 --- a/web/src/services/pm-api-client.ts +++ b/web/src/services/pm-api-client.ts @@ -1,5 +1,5 @@ import { default as Axios, AxiosInstance } from 'axios'; -import { ApiToken, LoginSubmit, Measure, Measurement, User } from '@/models'; +import { ApiToken, LoginSubmit, Measure, MeasureConfig, Measurement, MeasurementMeta, User } from '@/models'; import { Logger, logService } from '@/services/logging'; import merge from 'lodash.merge'; @@ -108,17 +108,17 @@ export class PmApiClient { return true; } - public async getAllMeasures(): Promise { + public async getAllMeasures(): Promise>> { const resp = await this.http.get(`/measures`); return resp.data; } - public async createMeasure(measure: Measure): Promise { + public async createMeasure(measure: Measure): Promise> { const resp = await this.http.post(`/measures`); return resp.data; } - public async getMeasure(slug: string): Promise { + public async getMeasure(slug: string): Promise> { const resp = await this.http.get(`/measures/${slug}`); return resp.data; } @@ -129,16 +129,16 @@ export class PmApiClient { } public async getMeasurements(measureSlug: string) - : Promise { + : Promise>> { const resp = await this.http.get(`/measure/${measureSlug}`); return resp.data; } - public async createMeasurement( + public async createMeasurement( measureSlug: string, - measurement: Measurement) - : Promise { + measurement: Measurement) + : Promise> { const resp = await this.http.post(`/measure/${measureSlug}`, measurement); return resp.data; @@ -147,7 +147,7 @@ export class PmApiClient { public async getMeasurement( measureSlug: string, measurementId: string) - : Promise { + : Promise> { const resp = await this.http .get(`/measure/${measureSlug}/${measurementId}`); @@ -156,8 +156,8 @@ export class PmApiClient { public async updateMeasurement( measureSlug: string, - measurement: Measurement) - : Promise { + measurement: Measurement) + : Promise> { const resp = await this.http .put(`/measure/${measureSlug}/${measurement.id}`, measurement); diff --git a/web/src/store-modules/measure.ts b/web/src/store-modules/measure.ts index 8391ace..a8a8caa 100644 --- a/web/src/store-modules/measure.ts +++ b/web/src/store-modules/measure.ts @@ -7,13 +7,13 @@ import { VuexModule } from 'vuex-module-decorators'; import { keyBy } from 'lodash'; -import { User, Measure } from '@/models'; +import { User, Measure, MeasureConfig } from '@/models'; import api from '@/services/pm-api-client'; import { logService } from '@/services/logging'; @Module({ namespaced: true, name: 'measure' }) export class MeasureStoreModule extends VuexModule { - public measures: { [key: string]: Measure } = {}; + public measures: { [key: string]: Measure } = {}; private log = logService.getLogger('/store-modules/measure'); @@ -28,7 +28,7 @@ export class MeasureStoreModule extends VuexModule { return await api.getMeasure(slug); } - @Mutation private SET_MEASURE(measure: Measure) { + @Mutation private SET_MEASURE(measure: Measure) { this.measures[measure.slug] = measure; } } diff --git a/web/src/store-modules/measurement.ts b/web/src/store-modules/measurement.ts new file mode 100644 index 0000000..5531e58 --- /dev/null +++ b/web/src/store-modules/measurement.ts @@ -0,0 +1,21 @@ +import { + Action, + getModule, + Module, + Mutation, + VuexModule +} from 'vuex-module-decorators'; +import { Measurement, MeasurementMeta } from '@/models'; +import api from '@/services/pm-api-client'; + +@Module({ namespaced: true, name: 'measurement' }) +export class MeasurementStoreModule extends VuexModule { + public measurements: { [key: string]: Array> } = {}; + + @Action({ commit: 'SET_MEASUREMENTS', rawError: true }) + public async getchMeasurements(measureSlug: string) { + return await api.getMeasurements(measureSlug); + } + + // @Mutation private SET_MEASUREMENTS( +} diff --git a/web/src/store.ts b/web/src/store.ts index 9567e58..27993f6 100644 --- a/web/src/store.ts +++ b/web/src/store.ts @@ -4,6 +4,7 @@ import { getModule } from 'vuex-module-decorators'; import { ApiTokenStoreModule } from './store-modules/api-token'; import { AuthStoreModule } from './store-modules/auth'; import { MeasureStoreModule } from './store-modules/measure'; +import { MeasurementStoreModule } from './store-modules/measurement'; import { UserStoreModule } from './store-modules/user'; Vue.use(Vuex); @@ -16,6 +17,7 @@ export const store = new Vuex.Store({ apiToken: ApiTokenStoreModule, auth: AuthStoreModule, measure: MeasureStoreModule, + measurements: MeasurementStoreModule, user: UserStoreModule } }); @@ -23,4 +25,5 @@ export const store = new Vuex.Store({ export const apiTokenStore = getModule(ApiTokenStoreModule, store); export const authStore = getModule(AuthStoreModule, store); export const measureStore = getModule(MeasureStoreModule, store); +export const measurementStore = getModule(MeasurementStoreModule, store); export const userStore = getModule(UserStoreModule, store); diff --git a/web/src/types/global.d.ts b/web/src/types/global.d.ts new file mode 100644 index 0000000..afa75c4 --- /dev/null +++ b/web/src/types/global.d.ts @@ -0,0 +1 @@ +declare const global: any; diff --git a/web/src/views/Measures.vue b/web/src/views/Measures.vue index 64a9918..6e1248b 100644 --- a/web/src/views/Measures.vue +++ b/web/src/views/Measures.vue @@ -4,9 +4,13 @@

Things You Are Measuring

-
-

{{measure.name}}

-
+ + diff --git a/web/src/views/measures.ts b/web/src/views/measures.ts index d8337cd..747476b 100644 --- a/web/src/views/measures.ts +++ b/web/src/views/measures.ts @@ -1,9 +1,13 @@ import { Component, Vue } from 'vue-property-decorator'; +import MeasureSummary from '@/components/MeasureSummary.vue'; +import Test from '@/components/Test.vue'; import { measureStore } from '@/store'; @Component({ - components: { } + components: { MeasureSummary } }) -export default class Measures extends Vue { +export class Measures extends Vue { private get measures() { return measureStore.measures; } } + +export default Measures;