Skip to content

Commit

Permalink
first work towards an edit-flows page and api interface
Browse files Browse the repository at this point in the history
  • Loading branch information
ngottlieb committed Oct 2, 2023
1 parent 51b98e4 commit 23a5ec9
Show file tree
Hide file tree
Showing 11 changed files with 335 additions and 8 deletions.
6 changes: 5 additions & 1 deletion src/app/global/mixins/gauge-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,9 @@ export const gaugeHelpers = {
}
return output;
},
}

metricLabel(metricId) {
return this.metrics.find(m => m.id.toString() === metricId.toString())?.unit
}
},
};
9 changes: 9 additions & 0 deletions src/app/router/river-detail.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ export default [
},
component: () => import('@/app/views/river-detail/components/main-tab/main-tab.vue')
},
{
path: 'edit-flows',
name: 'edit-flows',
meta: {
crumbLabel: 'Edit Flows',
transitionName: 'slide'
},
component: () => import('@/app/views/river-detail/components/edit-flows/edit-flows.vue')
},
{
path: 'flow',
name: 'flow-tab',
Expand Down
39 changes: 39 additions & 0 deletions src/app/services/getGaugeCorrelations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import http from "@/app/http"

// this is passed a "target id" that represents the reach's gauge record
export async function getGaugeCorrelations(id) {
return http.post('graphql', {
query: `
query ($targetid: Int) {
gaugeCorrelations(targetid: $targetid) {
source {
id
name
source
source_id
}
time_adjustment
metric {
id
unit
name
}
estimated
id
excluded
delay_update
ranges {
id
max
min
permissions{result,domain,permission}
}
permissions{result,permission}
}
}
`,
variables: {
targetid: id
}
}).then(res => res.data.data);
}
20 changes: 20 additions & 0 deletions src/app/services/getReachCorrelationGauge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import http from "@/app/http"

export async function getReachCorrelationGauge(id) {
return http.post('graphql', {
query: `
query ($source_id: AWID!, $source: String!) {
gauge(source: $source, source_id: $source_id) {
id
name
source
source_id
}
}
`,
variables: {
source_id: id,
source: "river"
}
}).then(res => res.data.data);
}
2 changes: 1 addition & 1 deletion src/app/services/getReachGages.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export async function getReachGages(id) {
.post("/graphql", {
query: `{
getGaugeInformationForReachID(id: ${id}) {
metrics {
name
unit
Expand All @@ -31,6 +30,7 @@ export async function getReachGages(id) {
rc
epoch
time_adjustment,
targetid,
gauge_reading
gauge_metric
gauge_comment
Expand Down
2 changes: 2 additions & 0 deletions src/app/services/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ export * from "./getDocument";
export * from "./getDocuments";
export * from "./getEvents";
export * from "./getGage";
export * from "./getGaugeCorrelations";
export * from "./getGageReadings";
export * from "./getProject";
export * from "./getProjects";
export * from "./getRapids";
export * from "./getReach";
export * from "./getReachAccidents";
export * from "./getReachAlerts";
export * from "./getReachCorrelationGauge";
export * from "./getReachCredits";
export * from "./getReachEvents";
export * from "./getReachDocuments";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<template>
<cv-modal
ref="modalWrapper"
size="large"
@primary-click="_confirm()"
@modal-hidden="_cancel()"
@modal-shown="setModalOffset"
>
<template slot="title">
<h2>
Select a new gauge
</h2>
</template>
<template slot="content">
<cv-search
label="start typing to search for a gauge"
@input="debouncedFetchGaugeOptions" />

<div v-if="searchResults.length" class="gauge-list bx--tile mb-spacing-md">
<cv-radio-group vertical="vertical">
<cv-radio-button
v-for="(g, index) in searchResults"
:key="index"
v-model="selectedGauge"
:value="g.value.toString()"
:label="g.name"
/>
</cv-radio-group>
</div>

<div v-if="selectedGauge" class="gauge-details">
<cv-select v-model="gaugeMetric" label="Gauge metric to use">
<cv-select-option
v-for="(m, index) in metricOptions"
:key="index"
:value="m.id"
>{{ m.label }}
</cv-select-option>
</cv-select>
</div>
</template>
<template slot="secondary-button"> Cancel </template>
<template slot="primary-button"> OK </template>
</cv-modal>
</template>
<script>
import { shadowDomFixedHeightOffset, gaugeHelpers } from "@/app/global/mixins";
import http from '@/app/http'
import debounce from 'lodash.debounce'
export default {
name: "add-gauge-modal",
mixins: [gaugeHelpers, shadowDomFixedHeightOffset],
data: () => ({
searchResults: [],
selectedGauge: null,
gaugeMetric: "2"
}),
methods: {
show(opts = {}) {
if (opts.gauge) {
this.selectedGauge = opts.gauge.id
}
this.$refs.modalWrapper.show();
return new Promise((resolve, reject) => {
this.resolvePromise = resolve;
this.rejectPromise = reject;
});
},
_confirm() {
this.resolvePromise(true);
this.$refs.modalWrapper.hide()
},
_cancel() {
this.resolvePromise(false);
},
async fetchGaugeOptions(query) {
if (query.length === 0) {
this.searchResults = []
} else if (query.length > 4) {
http.get(`/ui/lookup/LookupGaugeInfo/?name=${query}`)
.then(r => {
this.searchResults = r.data?.items;
});
}
}
},
created() {
this.debouncedFetchGaugeOptions = debounce(this.fetchGaugeOptions, 200, {
leading: false,
trailing: true
});
}
}
</script>
<style lang="scss" scoped>
.gauge-list {
max-height: 120px;
overflow-y: scroll;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as AddGaugeModal } from './add-gauge-modal.vue'
148 changes: 148 additions & 0 deletions src/app/views/river-detail/components/edit-flows/edit-flows.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<template>
<div class="edit-flows">
<layout name="layout-full-width" class="mb-lg">
<template #main>
<hr>
<div class="header-row mb-spacing-lg">
<h2>Edit Flows</h2>
<cv-button
size="small"
@click.exact="openGaugeModal()"
>
+ Add Gauge Correlation
</cv-button>
</div>

<div v-for="(gauge, index) in gauges"
:key="index"
class="bx--tile"
>
<h3>{{ gauge.gauge.name }} ({{ gauge.gauge.source }}) ({{ gauge.gauge.id }})</h3>
<table class="bx--data-table">
<thead>
<tr>
<th>Metric</th>
<th>Time Adjustment</th>
<th>Estimated</th>
<th>Excluded</th>
<th>Comment</th>
</tr>
</thead>
<tbody class="align-center">
<tr>
<td>{{ metricLabel(gauge.gauge_metric) }}</td>
<td>{{ gauge.time_adjustment }}m</td>
<td>test</td>
<td>test</td>
<td>test</td>
</tr>
</tbody>
</table>
<h4>Ranges</h4>

<table class="bx--data-table">
<thead>
<tr>
<th>Min</th>
<th>Max</th>
<th>Range</th>
<th>Rated</th>
<th>Comment</th>
<th/>
</tr>
</thead>
<tbody>
Ranges will go here
</tbody>
</table>
</div>
</template>
</layout>
<add-gauge-modal ref="addGaugeModal" :reachTargetId="reachTargetId" />
</div>
</template>

<script>
import { appLocalStorage } from '@/app/global/services'
import { getGaugeCorrelations, getReachCorrelationGauge } from '@/app/services'
import { Layout } from '@/app/global/layout'
import { gaugeHelpers } from '@/app/global/mixins'
import { mapState } from 'vuex'
import { AddGaugeModal } from './components'
export default {
name: 'edit-flows',
components: {
Layout,
AddGaugeModal
},
mixins: [gaugeHelpers],
data: () => ({
reachCorrelationGauge: null, // this "gauge" record represents the reach itself in relationships with other gauges
gaugeCorrelations: [],
loading: true
}),
computed: {
...mapState({
gauges: state => state.RiverGages.data?.gauges ?? [],
user: state => state.User.data
}),
reachId() {
return this.$route.params.id;
},
reachTargetId() {
return this.reachCorrelationGauge?.id;
}
},
watch: {
// gauge correlations require a "gauge id" to represent the reach
// we need to query to retrieve it
reachId: {
immediate: true,
async handler() {
// get the reach "target ID"
const targetGauge = await getReachCorrelationGauge(this.reachId);
if (!targetGauge.errors) {
this.reachCorrelationGauge = targetGauge.gauge;
// use the "target ID" to retrieve existing gauge correlations
const corrs = await getGaugeCorrelations(this.reachTargetId);
if (!corrs.errors) {
this.gaugeCorrelations = corrs.gauges;
} else {
// eslint-disable-next-line no-console
console.log(corrs.errors);
}
} else {
// eslint-disable-next-line no-console
console.log(targetGauge.errors);
}
}
}
},
methods: {
async openGaugeModal(gauge = null) {
await this.$refs.addGaugeModal.show({
gauge: gauge
});
}
},
beforeMount () {
// as of now, this is the only place in the app that we're actually checking
// auth before showing a route. So I'm just doing it in this ad hoc way
// but if the SPA expands and has more login-protected routes,
// we'll need to address this more systematically
if (!(this.user || appLocalStorage.getItem('wh2o-auth'))) {
this.$router.replace(`/river-detail/${this.$route.params.id}`);
}
}
}
</script>
<style lang="scss" scoped>
.header-row {
align-items: center;
display: flex;
justify-content: space-between;
}
</style>
1 change: 1 addition & 0 deletions src/app/views/river-detail/components/edit-flows/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as EditFlows } from './edit-flows'
Loading

0 comments on commit 23a5ec9

Please sign in to comment.