Refactor configuration GUI.

Another refactoring. What we're doing now is eliminating the
need to save individually on each section. Configuration changes
are done directly on the local configuration and then the local
configuration is saved, downloaded or discarded in one go.
This commit is contained in:
D. Berge
2023-11-15 16:19:09 +01:00
parent c7270febfc
commit 62ab06b4a7
18 changed files with 707 additions and 626 deletions

View File

@@ -9,21 +9,21 @@
hint="ID number for this survey in ASAQC" hint="ID number for this survey in ASAQC"
persistent-hint persistent-hint
type="number" type="number"
v-model.number="value_.id" v-model.number="cwo.id"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
label="IMO" label="IMO"
hint="Project vessel's International Maritime Organisation's identification number" hint="Project vessel's International Maritime Organisation's identification number"
persistent-hint persistent-hint
v-model.number="value_.imo" v-model.number="cwo.imo"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
label="MMSI" label="MMSI"
hint="Maritime Mobile Service Identities (MMSI) number" hint="Maritime Mobile Service Identities (MMSI) number"
persistent-hint persistent-hint
v-model.number="value_.mmsi" v-model.number="cwo.mmsi"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -32,13 +32,14 @@
persistent-hint persistent-hint
:type="subscriptionKeyVisible ? 'text' : 'password'" :type="subscriptionKeyVisible ? 'text' : 'password'"
:append-icon="subscriptionKeyVisible ? 'mdi-eye' : 'mdi-eye-off'" :append-icon="subscriptionKeyVisible ? 'mdi-eye' : 'mdi-eye-off'"
v-model="value_.subscriptionKey" v-model="cwo.subscriptionKey"
@click:append="subscriptionKeyVisible = !subscriptionKeyVisible" @click:append="subscriptionKeyVisible = !subscriptionKeyVisible"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -48,6 +49,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -58,54 +60,60 @@
</template> </template>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
export default { export default {
name: "DougalProjectSettingsASAQC", name: "DougalProjectSettingsASAQC",
mixins: [ props: {
setIfDifferent({ value: Object
value: "value_" },
})
],
props: [ "value" ],
data () { data () {
return { return {
value_: {
id: null,
imo: null,
mmsi: null,
subscriptionKey: null
},
subscriptionKeyVisible: false subscriptionKeyVisible: false
} }
}, },
watch: { computed: {
value (newValue) { // Current working object.
this.reset(); // A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.cloud?.asaqc) {
deepSet(this.value, [ "cloud", "asaqc" ], {
id: null,
imo: null,
mmsi: null,
subscriptionKey: null
});
}
return this.value.cloud.asaqc;
} else {
return {};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "cloud", "asaqc" ], v);
}
}
} }
}, },
methods: { methods: {
reset () { reset () {
this.value_ = deepMerge({
id: null,
imo: null,
mmsi: null,
subscriptionKey: null
}, structuredClone(this.value??{}));
}, },
save () { save () {
this.$emit("merge", [ [ "cloud", "asaqc" ], this.value_ ]);
this.$nextTick(this.reset);
}, },
back () { back () {

View File

@@ -10,7 +10,7 @@
persistent-hint persistent-hint
suffix="°" suffix="°"
type="number" type="number"
v-model.number="theta_" v-model.number="cwo.theta"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -20,7 +20,7 @@
type="number" type="number"
min="0" min="0"
step="1" step="1"
v-model.number="I_inc_" v-model.number="cwo.I_inc"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -30,7 +30,7 @@
type="number" type="number"
min="0" min="0"
step="1" step="1"
v-model.number="J_inc_" v-model.number="cwo.J_inc"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -38,7 +38,7 @@
hint="Inline bin width (can be negative)" hint="Inline bin width (can be negative)"
persistent-hint persistent-hint
type="number" type="number"
v-model.number="I_width_" v-model.number="cwo.I_width"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -46,7 +46,7 @@
hint="Crossline bin width (can be negative)" hint="Crossline bin width (can be negative)"
persistent-hint persistent-hint
type="number" type="number"
v-model.number="J_width_" v-model.number="cwo.J_width"
> >
</v-text-field> </v-text-field>
<fieldset class="pa-3 mt-3"> <fieldset class="pa-3 mt-3">
@@ -58,7 +58,7 @@
hint="Bin origin easting" hint="Bin origin easting"
persistent-hint persistent-hint
type="number" type="number"
v-model.number="origin_.easting" v-model.number="cwo.origin.easting"
> >
</v-text-field> </v-text-field>
</v-col> </v-col>
@@ -68,7 +68,7 @@
hint="Bin origin northing" hint="Bin origin northing"
persistent-hint persistent-hint
type="number" type="number"
v-model.number="origin_.northing" v-model.number="cwo.origin.northing"
> >
</v-text-field> </v-text-field>
</v-col> </v-col>
@@ -81,7 +81,7 @@
persistent-hint persistent-hint
type="number" type="number"
step="1" step="1"
v-model.number="origin_.I" v-model.number="cwo.origin.I"
> >
</v-text-field> </v-text-field>
</v-col> </v-col>
@@ -92,7 +92,7 @@
persistent-hint persistent-hint
type="number" type="number"
step="1" step="1"
v-model.number="origin_.J" v-model.number="cwo.origin.J"
> >
</v-text-field> </v-text-field>
</v-col> </v-col>
@@ -101,6 +101,7 @@
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -110,6 +111,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -120,91 +122,66 @@
</template> </template>
<script> <script>
import { deepSet } from '@/lib/utils';
export default { export default {
name: "DougalProjectSettingsBinning", name: "DougalProjectSettingsBinning",
props: [ "theta", "I_inc", "J_inc", "I_width", "J_width", "origin" ], props: {
value: Object
},
data () { data () {
return { return {
theta_: null,
I_inc_: 1,
J_inc_: 1,
I_width_: -12.50,
J_width_: 12.50,
origin_: {
easting: null,
northing: null,
I: null,
J: null
}
} }
}, },
watch: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
theta () { get () {
if (this.theta != this.theta_) { if (this.value) {
this.theta_ = this.theta; if (!this.value?.binning) {
} deepSet(this.value, [ "binning" ], {
}, theta: null,
Iinc: 1,
Jinc: 1,
Iwidth: null,
Jwidth: null,
origin: {
easting: null,
northing: null,
I: null,
J: null
}
});
}
return this.value.binning;
} else {
return {};
}
},
I_inc () { set (v) {
if (this.I_inc != this.I_inc_) { if (this.value) {
this.I_inc_ = this.I_inc; deepSet(this.value, [ "binning" ], v);
}
} }
},
J_inc () {
if (this.J_inc != this.J_inc_) {
this.J_inc_ = this.J_inc;
}
},
I_width () {
if (this.I_width != this.I_width_) {
this.I_width_ = this.I_width;
}
},
J_width () {
if (this.J_width != this.J_width_) {
this.J_width_ = this.J_width;
}
},
origin () {
if (Object.entries(this.origin).some(i => this.origin_[i[0]] != i[1])) {
this.origin_ = {...this.origin};
}
} }
}, },
methods: { methods: {
reset () { reset () {
this.theta_ = this.theta;
this.I_inc_ = this.I_inc;
this.J_inc_ = this.J_inc;
this.I_width_ = this.I_width;
this.J_width_ = this.J_width;
this.origin_ = {...this.origin};
this.origin_.origin = {...this.origin.origin};
}, },
save () { save () {
this.$emit('input', {
binning: {
theta: this.theta_,
I_inc: this.I_inc_,
J_inc: this.J_inc_,
I_width: this.I_width_,
J_width: this.J_width_,
origin: this.origin_
}
});
}, },
back () { back () {

View File

@@ -178,6 +178,7 @@
</v-tabs-items> </v-tabs-items>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
:disabled="!isValid" :disabled="!isValid"
@@ -188,6 +189,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -295,8 +297,6 @@ export default {
this.$emit('close'); this.$emit('close');
}, },
...mapActions(["api"])
}, },
mounted () { mounted () {

View File

@@ -8,17 +8,18 @@
label="Project folder" label="Project folder"
hint="Root file path for this project" hint="Root file path for this project"
persistent-hint persistent-hint
v-model="rootPath_" v-model="cwo.rootPath"
> >
<dougal-file-browser-dialog <dougal-file-browser-dialog
slot="append" slot="append"
v-model="rootPath_" v-model="cwo.rootPath"
mimetypes="inode/directory" mimetypes="inode/directory"
></dougal-file-browser-dialog> ></dougal-file-browser-dialog>
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -28,6 +29,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -45,32 +47,44 @@ export default {
components: { DougalFileBrowserDialog }, components: { DougalFileBrowserDialog },
props: [ "rootPath" ], props: {
value: Object
},
data () { data () {
return { return {
rootPath_: ""
} }
}, },
watch: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
rootPath () { get () {
if (this.rootPath != this.rootPath_) { if (this.value) {
this.reset(); return this.value;
} else {
return {};
}
},
set (v) {
this.value = v;
} }
}
}
}, },
methods: { methods: {
reset () { reset () {
this.rootPath_ = this.rootPath;
}, },
save () { save () {
this.$emit('input', {rootPath: this.rootPath_});
}, },
back () { back () {

View File

@@ -9,12 +9,13 @@
hint="EPSG code of the project's coordinate reference system" hint="EPSG code of the project's coordinate reference system"
persistent-hint persistent-hint
type="number" type="number"
v-model.number="epsg_" v-model.number="cwo.epsg"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -24,6 +25,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -38,30 +40,44 @@
export default { export default {
name: "DougalProjectSettingsGeodetics", name: "DougalProjectSettingsGeodetics",
props: [ "epsg" ], props: {
value: Object
},
data () { data () {
return { return {
epsg_: null
} }
}, },
watch: { computed: {
epsg () { // Current working object.
if (this.epsg != this.epsg_) { // A shortcut so we don't have to specify the full path
this.epsg_ = this.epsg; // on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
return this.value;
} else {
return {};
}
},
set (v) {
this.value = v;
} }
} }
}, },
methods: { methods: {
reset () { reset () {
this.epsg_ = this.epsg;
}, },
save () { save () {
this.$emit('input', {epsg: this.epsg_});
}, },
back () { back () {

View File

@@ -1,11 +1,11 @@
<template> <template>
<v-card> <v-card>
<v-card-title>Groups</v-card-title> <v-card-title>Groups</v-card-title>
<v-card-subtitle>For <abbr title="Permanent Reservoir Monitoring">PRM</abbr> and 4D operations, each project can be assigned to one or more groups_ sharing the same (or substantially the same) preplots.</v-card-subtitle> <v-card-subtitle>For <abbr title="Permanent Reservoir Monitoring">PRM</abbr> and 4D operations, each project can be assigned to one or more groups sharing the same (or substantially the same) preplots.</v-card-subtitle>
<v-card-text> <v-card-text>
<v-form> <v-form>
<v-combobox <v-combobox
v-model="groups_" v-model="groups"
:items="items" :items="items"
multiple multiple
:search-input.sync="search" :search-input.sync="search"
@@ -59,6 +59,7 @@
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -68,6 +69,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -79,33 +81,19 @@
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { deepSet } from '@/lib/utils';
export default { export default {
name: "DougalProjectSettingsGroups", name: "DougalProjectSettingsGroups",
props: [ "groups" ], props: [ "value" ],
data () { data () {
return { return {
groups_: [],
search: null search: null
} }
}, },
watch: {
value (newValue) {
this.reset();
},
groups (cur, prev) {
if (cur?.length == prev?.length) {
return;
}
this.setGroups(cur);
}
},
computed: { computed: {
colours () { colours () {
@@ -113,7 +101,8 @@ export default {
}, },
nextColour () { nextColour () {
return this.colours[(this.items.length + (this.groups_?.length ?? 0)) % this.colours.length]; // FIXME Fix colour when adding a new group
return this.colours[(this.items.length + (this.value?.groups?.length ?? 0)) % this.colours.length];
}, },
items () { items () {
@@ -125,25 +114,33 @@ export default {
}); });
}, },
groups: {
get () {
return this.value?.groups?.map(i => {
return typeof i === "string"
? { text: i, colour: this.nextColour}
: i
}) ?? [];
},
set (v) {
if (this.value) {
this.value.groups = v?.map( i => i?.text ?? i );
}
}
},
...mapGetters(["projectGroups"]) ...mapGetters(["projectGroups"])
}, },
methods: { methods: {
setGroups (groups) {
this.groups_ = groups?.map(i => {
return typeof i === "string"
? { text: i, colour: this.nextColour}
: i
});
},
reset () { reset () {
this.setGroups(this.groups);
}, },
save () { save () {
this.$emit('input', {groups: this.groups_?.map(i => i.text)});
}, },
back () { back () {

View File

@@ -2,7 +2,7 @@
<dougal-project-settings-file-matching-parameters <dougal-project-settings-file-matching-parameters
title="Final P1/11" title="Final P1/11"
subtitle="Final P1/11 files location and parameters." subtitle="Final P1/11 files location and parameters."
v-bind="{rootPath}" v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind" v-bind.sync="bind"
:is-valid="isValid" :is-valid="isValid"
:save="save" :save="save"
@@ -19,8 +19,7 @@
</style> </style>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters'; import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
@@ -31,55 +30,97 @@ export default {
DougalProjectSettingsFileMatchingParameters DougalProjectSettingsFileMatchingParameters
}, },
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: { props: {
title: String, title: String,
subtitle: String, subtitle: String,
rootPath: String, value: Object
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
}, },
data () { data () {
return { return {
tab: null, tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
} }
}, },
computed: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.final?.p111) {
deepSet(this.value, [ "final", "p111" ], {
globs: [ "**/*.p111", "**/*.P111" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
},
incr: {
length: 1,
type: "bool"
},
attempt: {
length: 1,
type: "int"
},
file_no: {
length: 3,
type: "int"
}
}
}
});
}
return this.value.final.p111;
} else {
return {
globs: [ "**/*.p111", "**/*.P111" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
}
}
};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "final", "p111" ], v);
}
}
},
bind () { bind () {
return { return {
globs: this.globs_, globs: this.cwo?.globs,
paths: this.paths_, paths: this.cwo?.paths,
pattern: this.pattern_, pattern: this.cwo?.pattern,
lineNameInfo: this.lineNameInfo_ lineNameInfo: this.cwo?.lineNameInfo
}; };
}, },
isValid () { isValid () {
return true; return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
return !!(this.paths.length && this.globs.length && ( this.cwo?.pattern?.regex &&
this.pattern?.regex && ["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
["direction", "line", "sequence"].every( i => this.pattern?.captures?.includes(i) )) || ( this.cwo?.lineNameInfo &&
this.lineNameInfo && this.cwo?.lineNameInfo?.fields &&
this.lineNameInfo?.fields &&
[ "line", "sequence", "incr" ].every( i => [ "line", "sequence", "incr" ].every( i =>
["offset", "length"].every( j => j in this.lineNameInfo.fields[i] )))); ["offset", "length"].every( j => j in this.cwo?.lineNameInfo.fields[i] ))));
} }
}, },
@@ -90,56 +131,14 @@ export default {
methods: { methods: {
reset () { reset () {
this.paths_ = [...this.paths];
this.globs_ = [...this.globs];
this.lineNameInfo_ = deepMerge({
example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
},
incr: {
length: 1,
type: "bool"
},
attempt: {
length: 1,
type: "int"
},
file_no: {
length: 3,
type: "int"
}
}
}, structuredClone(this.lineNameInfo ?? {}));
this.pattern_ = structuredClone(this.pattern ?? {});
}, },
save () { save () {
this.$emit("merge", [ ["final", "p111"], {
paths: this.paths_,
globs: this.globs_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
}, },
back () { back () {
this.$emit('close'); this.$emit('close');
}, },
...mapActions(["api"])
}, },
mounted () { mounted () {

View File

@@ -8,19 +8,20 @@
label="Pattern" label="Pattern"
hint="Regular expression text" hint="Regular expression text"
persistent-hint persistent-hint
v-model="regex_" v-model="cwo.pattern.regex"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
label="Flags" label="Flags"
hint="Regular expression modifier flags" hint="Regular expression modifier flags"
persistent-hint persistent-hint
v-model="flags_" v-model="cwo.pattern.flags"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -30,6 +31,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -40,25 +42,51 @@
</template> </template>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
export default { export default {
name: "DougalProjectSettingsFinalPending", name: "DougalProjectSettingsFinalPending",
mixins: [ props: {
setIfDifferent({ value: Object
regex: "regex_", },
flags: "flags_"
})
],
props: [ "regex", "flags" ],
data () { data () {
return { return {
regex_: "NTBP", }
flags_: "i" },
computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.final?.pending.pattern) {
deepSet(this.value, [ "final", "pending", "pattern" ], {
flags: "i",
regex: "PENDING"
});
}
return this.value.final.pending;
} else {
return {
flags: "i",
regex: "PENDING"
};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "final", "pending", "pattern" ], v);
}
}
} }
}, },
@@ -68,16 +96,9 @@ export default {
methods: { methods: {
reset () { reset () {
this.regex_ = this.regex;
this.flags_ = this.flags;
}, },
save () { save () {
this.$emit('merge', [ ["final", "pending"], {
regex: this.regex_,
flags: this.flags_
}]);
this.$nextTick(this.reset);
}, },
back () { back () {

View File

@@ -8,19 +8,20 @@
label="Pattern" label="Pattern"
hint="Regular expression text" hint="Regular expression text"
persistent-hint persistent-hint
v-model="regex_" v-model="cwo.pattern.regex"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
label="Flags" label="Flags"
hint="Regular expression modifier flags" hint="Regular expression modifier flags"
persistent-hint persistent-hint
v-model="flags_" v-model="cwo.pattern.flags"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -30,6 +31,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -40,25 +42,51 @@
</template> </template>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
export default { export default {
name: "DougalProjectSettingsRawNTBP", name: "DougalProjectSettingsRawNTBP",
mixins: [ props: {
setIfDifferent({ value: Object
regex: "regex_", },
flags: "flags_"
})
],
props: [ "regex", "flags" ],
data () { data () {
return { return {
regex_: "NTBP", }
flags_: "i" },
computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.raw?.ntbp.pattern) {
deepSet(this.value, [ "raw", "ntbp", "pattern" ], {
flags: "i",
regex: "NTBP"
});
}
return this.value.raw.ntbp;
} else {
return {
flags: "i",
regex: "NTBP"
};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "raw", "ntbp", "pattern" ], v);
}
}
} }
}, },
@@ -68,16 +96,9 @@ export default {
methods: { methods: {
reset () { reset () {
this.regex_ = this.regex;
this.flags_ = this.flags;
}, },
save () { save () {
this.$emit('merge', [ ["raw", "ntbp"], {
regex: this.regex_,
flags: this.flags_
}]);
this.$nextTick(this.reset);
}, },
back () { back () {

View File

@@ -2,7 +2,7 @@
<dougal-project-settings-file-matching-parameters <dougal-project-settings-file-matching-parameters
title="Raw P1/11" title="Raw P1/11"
subtitle="Raw P1/11 files location and parameters." subtitle="Raw P1/11 files location and parameters."
v-bind="{rootPath}" v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind" v-bind.sync="bind"
:is-valid="isValid" :is-valid="isValid"
:save="save" :save="save"
@@ -19,8 +19,7 @@
</style> </style>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters'; import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
@@ -31,54 +30,97 @@ export default {
DougalProjectSettingsFileMatchingParameters DougalProjectSettingsFileMatchingParameters
}, },
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: { props: {
title: String, title: String,
subtitle: String, subtitle: String,
rootPath: String, value: Object
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
}, },
data () { data () {
return { return {
tab: null, tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
} }
}, },
computed: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.raw?.p111) {
deepSet(this.value, [ "raw", "p111" ], {
globs: [ "**/*.p111", "**/*.P111" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
},
incr: {
length: 1,
type: "bool"
},
attempt: {
length: 1,
type: "int"
},
file_no: {
length: 3,
type: "int"
}
}
}
});
}
return this.value.raw.p111;
} else {
return {
globs: [ "**/*.p111", "**/*.P111" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
}
}
};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "raw", "p111" ], v);
}
}
},
bind () { bind () {
return { return {
globs: this.globs_, globs: this.cwo?.globs,
paths: this.paths_, paths: this.cwo?.paths,
pattern: this.pattern_, pattern: this.cwo?.pattern,
lineNameInfo: this.lineNameInfo_ lineNameInfo: this.cwo?.lineNameInfo
}; };
}, },
isValid () { isValid () {
return !!(this.paths_.length && this.globs_.length && ( return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
this.pattern_?.regex && this.cwo?.pattern?.regex &&
["direction", "line", "sequence"].every( i => this.pattern_?.captures?.includes(i) )) || ( ["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
this.lineNameInfo_ && this.cwo?.lineNameInfo &&
this.lineNameInfo_?.fields && this.cwo?.lineNameInfo?.fields &&
[ "line", "sequence", "incr" ].every( i => [ "line", "sequence", "incr" ].every( i =>
["offset", "length"].every( j => j in this.lineNameInfo_.fields[i] )))); ["offset", "length"].every( j => j in this.cwo?.lineNameInfo.fields[i] ))));
} }
}, },
@@ -89,56 +131,14 @@ export default {
methods: { methods: {
reset () { reset () {
this.paths_ = [...this.paths];
this.globs_ = [...this.globs];
this.lineNameInfo_ = deepMerge({
example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
},
incr: {
length: 1,
type: "bool"
},
attempt: {
length: 1,
type: "int"
},
file_no: {
length: 3,
type: "int"
}
}
}, structuredClone(this.lineNameInfo ?? {}));
this.pattern_ = structuredClone(this.pattern ?? {});
}, },
save () { save () {
this.$emit("merge", [ ["raw", "p111"], {
paths: this.paths_,
globs: this.globs_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
}, },
back () { back () {
this.$emit('close'); this.$emit('close');
}, },
...mapActions(["api"])
}, },
mounted () { mounted () {

View File

@@ -2,6 +2,7 @@
<dougal-project-settings-file-matching-parameters <dougal-project-settings-file-matching-parameters
title="Smartsource header data" title="Smartsource header data"
subtitle="Smartsource header data files location and parameters." subtitle="Smartsource header data files location and parameters."
v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind" v-bind.sync="bind"
:is-valid="isValid" :is-valid="isValid"
:save="save" :save="save"
@@ -18,8 +19,7 @@
</style> </style>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters'; import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
@@ -30,57 +30,85 @@ export default {
DougalProjectSettingsFileMatchingParameters DougalProjectSettingsFileMatchingParameters
}, },
props: [ "value", "title", "subtitle" ],
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: { props: {
title: String, title: String,
subtitle: String, subtitle: String,
rootPath: String, value: Object
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
}, },
data () { data () {
return { return {
tab: null, tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
} }
}, },
computed: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.raw?.source?.smsrc?.header) {
deepSet(this.value, [ "raw", "source", "smsrc", "header" ], {
globs: [ "**/*.hdr", "**/*.HDR" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
}
}
}
});
}
return this.value.raw.source.smsrc.header;
} else {
return {
globs: [ "**/*.hdr", "**/*.HDR" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
}
}
};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "raw", "source", "smsrc", "header" ], v);
}
}
},
bind () { bind () {
return { return {
globs: this.globs_, globs: this.cwo?.globs,
paths: this.paths_, paths: this.cwo?.paths,
//pattern: this.pattern_, pattern: this.cwo?.pattern,
lineNameInfo: this.lineNameInfo_ lineNameInfo: this.cwo?.lineNameInfo
}; };
}, },
isValid () { isValid () {
return true; return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
return !!(this.paths.length && this.globs.length && ( this.cwo?.pattern?.regex &&
this.pattern?.regex && ["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
["direction", "line", "sequence"].every( i => this.pattern?.captures?.includes(i) )) || ( this.cwo?.lineNameInfo &&
this.lineNameInfo && this.cwo?.lineNameInfo?.fields &&
this.lineNameInfo?.fields &&
[ "line", "sequence", "incr" ].every( i => [ "line", "sequence", "incr" ].every( i =>
["offset", "length"].every( j => j in this.lineNameInfo.fields[i] )))); ["offset", "length"].every( j => j in this.cwo?.lineNameInfo.fields[i] ))));
} }
}, },
@@ -91,40 +119,14 @@ export default {
methods: { methods: {
reset () { reset () {
this.paths_ = [...this.paths];
this.globs_ = [...this.globs];
this.lineNameInfo_ = deepMerge({
example: "",
fields: {
sequence: {
length: 3,
type: "int"
},
}
}, structuredClone(this.lineNameInfo ?? {}));
this.pattern_ = structuredClone(this.pattern ?? {});
}, },
save () { save () {
this.$emit("merge", [ ["raw", "source", "smsrc", "header"], {
paths: this.paths_,
globs: this.globs_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
}, },
back () { back () {
this.$emit('close'); this.$emit('close');
}, },
...mapActions(["api"])
}, },
mounted () { mounted () {

View File

@@ -2,6 +2,7 @@
<dougal-project-settings-file-matching-parameters <dougal-project-settings-file-matching-parameters
title="Smartsource hydrophone data" title="Smartsource hydrophone data"
subtitle="Smartsource SEG-Y hydrophone data files location and parameters." subtitle="Smartsource SEG-Y hydrophone data files location and parameters."
v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind" v-bind.sync="bind"
:is-valid="isValid" :is-valid="isValid"
:save="save" :save="save"
@@ -18,7 +19,7 @@
</style> </style>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin'; import setIfDifferent from '@/lib/watcher-mixin';
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters'; import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
@@ -30,57 +31,85 @@ export default {
DougalProjectSettingsFileMatchingParameters DougalProjectSettingsFileMatchingParameters
}, },
props: [ "value", "title", "subtitle" ],
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: { props: {
title: String, title: String,
subtitle: String, subtitle: String,
rootPath: String, value: Object
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
}, },
data () { data () {
return { return {
tab: null, tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
} }
}, },
computed: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.raw?.source?.smsrc?.segy) {
deepSet(this.value, [ "raw", "source", "smsrc", "segy" ], {
globs: [ "**/*.hdr", "**/*.HDR" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
}
}
}
});
}
return this.value.raw.source.smsrc.segy;
} else {
return {
globs: [ "**/*.hdr", "**/*.HDR" ],
paths: [],
lineNameInfo: {
example: "",
fields: {
}
}
};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "raw", "source", "smsrc", "segy" ], v);
}
}
},
bind () { bind () {
return { return {
globs: this.globs_, globs: this.cwo?.globs,
paths: this.paths_, paths: this.cwo?.paths,
//pattern: this.pattern_, pattern: this.cwo?.pattern,
lineNameInfo: this.lineNameInfo_ lineNameInfo: this.cwo?.lineNameInfo
}; };
}, },
isValid () { isValid () {
return true; return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
return !!(this.paths.length && this.globs.length && ( this.cwo?.pattern?.regex &&
this.pattern?.regex && ["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
["sequence"].every( i => this.pattern?.captures?.includes(i) )) || ( this.cwo?.lineNameInfo &&
this.lineNameInfo && this.cwo?.lineNameInfo?.fields &&
this.lineNameInfo?.fields && [ "line", "sequence", "incr" ].every( i =>
[ "sequence" ].every( i => ["offset", "length"].every( j => j in this.cwo?.lineNameInfo.fields[i] ))));
["offset", "length"].every( j => j in this.lineNameInfo.fields[i] ))));
} }
}, },
@@ -91,40 +120,14 @@ export default {
methods: { methods: {
reset () { reset () {
this.paths_ = [...this.paths];
this.globs_ = [...this.globs];
this.lineNameInfo_ = deepMerge({
example: "",
fields: {
sequence: {
length: 3,
type: "int"
},
}
}, structuredClone(this.lineNameInfo ?? {}));
this.pattern_ = structuredClone(this.pattern ?? {});
}, },
save () { save () {
this.$emit("merge", [ ["raw", "source", "smsrc", "segy"], {
paths: this.paths_,
globs: this.globs_,
//pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
}, },
back () { back () {
this.$emit('close'); this.$emit('close');
}, },
...mapActions(["api"])
}, },
mounted () { mounted () {

View File

@@ -8,19 +8,20 @@
label="ID" label="ID"
hint="Short survey ID" hint="Short survey ID"
persistent-hint persistent-hint
v-model="id_" v-model="cwo.id"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
label="Name" label="Name"
hint="Survey name" hint="Survey name"
persistent-hint persistent-hint
v-model="name_" v-model="cwo.name"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -30,6 +31,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -45,40 +47,43 @@ export default {
name: "DougalProjectSettingsNameId", name: "DougalProjectSettingsNameId",
props: { props: {
id: String, value: Object
name: String
}, },
data () { data () {
return { return {
id_: "",
name_: ""
} }
}, },
watch: { computed: {
id () { // Current working object.
if (this.id != this.id_) { // A shortcut so we don't have to specify the full path
this.id_ = this.id; // on every input control. It also makes it easier to
} // change that path if necessary. Finally, it ensures that
}, // the properties being modified are always available.
cwo: {
name () { get () {
if (this.name != this.name_) { if (this.value) {
this.name_ = this.name; return this.value;
} else {
return {};
}
},
set (v) {
this.value = v;
} }
} }
}, },
methods: { methods: {
reset () { reset () {
this.id_ = this.id;
this.name_ = this.name;
}, },
save () { save () {
this.$emit('input', {id: this.id_, name: this.name_});
}, },
back () { back () {

View File

@@ -1,26 +1,27 @@
<template> <template>
<v-card> <v-card>
<v-card-title>Files</v-card-title> <v-card-title>Online line name</v-card-title>
<v-card-subtitle>File path configuration for this project.</v-card-subtitle> <v-card-subtitle>Line name decoding configuration for real-time data</v-card-subtitle>
<v-card-text> <v-card-text>
<v-form> <v-form>
<v-text-field <v-text-field
label="Example file name" label="Example file name"
hint="Enter the name of a representative file to make it easier to visualise your configuration" hint="Enter the name of a representative file to make it easier to visualise your configuration"
persistent-hint persistent-hint
v-model="lineNameInfo_.example" v-model="cwo.lineNameInfo.example"
></v-text-field> ></v-text-field>
<dougal-fixed-string-decoder <dougal-fixed-string-decoder
title="Line name format" title="Line name format"
subtitle="Format of line names as configured in the navigation system" subtitle="Format of line names as configured in the navigation system"
:multiline="true" :multiline="true"
:text="lineNameInfo_.example" :text="cwo.lineNameInfo.example"
:fields="lineNameInfo_.fields" :fields="cwo.lineNameInfo.fields"
></dougal-fixed-string-decoder> ></dougal-fixed-string-decoder>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -30,6 +31,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -47,10 +49,8 @@
</style> </style>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import DougalFixedStringDecoder from '@/components/decoder/fixed-string-decoder'; import DougalFixedStringDecoder from '@/components/decoder/fixed-string-decoder';
import { mapActions, mapGetters } from 'vuex';
export default { export default {
name: "DougalProjectSettingsOnlineLineNameFormat", name: "DougalProjectSettingsOnlineLineNameFormat",
@@ -59,81 +59,76 @@ export default {
DougalFixedStringDecoder DougalFixedStringDecoder
}, },
mixins: [
setIfDifferent({
lineNameInfo: "lineNameInfo_"
})
],
props: { props: {
lineNameInfo: Object value: Object
}, },
data () { data () {
return { return {
lineNameInfo_: {
example: "",
fields: {}
}
} }
}, },
computed: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
isValid () { get () {
return !!(this.lineNameInfo_ && if (this.value) {
this.lineNameInfo_?.fields && if (!this.value?.online?.line) {
[ "line", "sequence", "incr" ].every( i => deepSet(this.value, [ "online", "line" ], {
["offset", "length"].every( j => j in this.lineNameInfo_.fields[i] ))); lineNameInfo: {
} example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
},
incr: {
length: 1,
type: "bool"
},
attempt: {
length: 1,
type: "int"
}
}
}
});
}
return this.value.online.line;
} else {
return {};
}
},
}, set (v) {
if (this.value) {
deepSet(this.value, [ "online", "line" ], v);
}
}
watch: {
value (newValue) {
this.reset();
} }
}, },
methods: { methods: {
reset () { reset () {
this.lineNameInfo_ = deepMerge({
example: "",
fields: {
line: {
length: 4,
type: "int"
},
sequence: {
length: 3,
type: "int"
},
incr: {
length: 1,
type: "bool"
},
attempt: {
length: 1,
type: "int"
},
}
}, structuredClone(this.lineNameInfo ?? {}));
}, },
save () { save () {
this.$emit("merge", [ ["online", "line"], {
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
}, },
back () { back () {
this.$emit('close'); this.$emit('close');
}, }
...mapActions(["api"])
}, },

View File

@@ -10,7 +10,7 @@
type="number" type="number"
hint="Expected line change time in minutes" hint="Expected line change time in minutes"
persistent-hint persistent-hint
v-model.number="planner_.defaultLineChangeDuration" v-model.number="cwo.defaultLineChangeDuration"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -19,7 +19,7 @@
type="number" type="number"
hint="Expected acquisition speed in knots" hint="Expected acquisition speed in knots"
persistent-hint persistent-hint
v-model.number="planner_.defaultAcquisitionSpeed" v-model.number="cwo.defaultAcquisitionSpeed"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -27,7 +27,7 @@
type="number" type="number"
hint="Default number of shots to overlap before the FGSP, for reshoots" hint="Default number of shots to overlap before the FGSP, for reshoots"
persistent-hint persistent-hint
v-model.number="planner_.overlapBefore" v-model.number="cwo.overlapBefore"
> >
</v-text-field> </v-text-field>
<v-text-field <v-text-field
@@ -35,12 +35,13 @@
type="number" type="number"
hint="Default number of shots to overlap after the LGSP, for reshoots" hint="Default number of shots to overlap after the LGSP, for reshoots"
persistent-hint persistent-hint
v-model.number="planner_.overlapAfter" v-model.number="cwo.overlapAfter"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -50,6 +51,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -60,55 +62,60 @@
</template> </template>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
export default { export default {
name: "DougalProjectSettingsPlanner", name: "DougalProjectSettingsPlanner",
mixins: [
setIfDifferent({
planner: "planner_"
})
],
props: { props: {
planner: Object value: Object
}, },
data () { data () {
return { return {
planner_: {
defaultLineChangeDuration: null,
defaultAcquisitionSpeed: null,
overlapBefore: null,
overlapAfter: null
}
} }
}, },
watch: { computed: {
planner (newValue) { // Current working object.
this.reset(); // A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.planner) {
deepSet(this.value, [ "planner" ], {
defaultLineChangeDuration: null,
defaultAcquisitionSpeed: null,
overlapBefore: null,
overlapAfter: null
});
}
return this.value.planner;
} else {
return {};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "planner" ], v);
}
}
} }
}, },
methods: { methods: {
reset () { reset () {
this.planner_ = deepMerge({
defaultLineChangeDuration: null,
defaultAcquisitionSpeed: null,
overlapBefore: null,
overlapAfter: null
}, structuredClone(this.planner ?? {}));
}, },
save () { save () {
this.$emit("merge", [ [ ], this.planner_ ]);
this.$nextTick(this.reset);
}, },
back () { back () {

View File

@@ -5,14 +5,14 @@
<v-card-text> <v-card-text>
<v-expansion-panels v-model="panel"> <v-expansion-panels v-model="panel">
<v-expansion-panel v-for="(preplot, idx) in preplots_" :key="idx"> <v-expansion-panel v-for="(preplot, idx) in cwo" :key="idx">
<v-expansion-panel-header> <v-expansion-panel-header>
{{ titleFor(preplot) }} {{ titleFor(preplot) }}
</v-expansion-panel-header> </v-expansion-panel-header>
<v-expansion-panel-content> <v-expansion-panel-content>
<dougal-project-settings-preplots-preplot <dougal-project-settings-preplots-preplot
v-model="preplots_[idx]" v-model="cwo[idx]"
:root-path="rootPath" :root-path="value.rootPath"
></dougal-project-settings-preplots-preplot> ></dougal-project-settings-preplots-preplot>
<v-btn <v-btn
@@ -42,6 +42,7 @@
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
:disabled="!isValid" :disabled="!isValid"
@@ -52,6 +53,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -78,45 +80,53 @@ export default {
DougalProjectSettingsPreplotsPreplot, DougalProjectSettingsPreplotsPreplot,
}, },
props: [ "rootPath", "preplots" ], props: {
value: Object
},
data () { data () {
return { return {
preplots_: [],
panel: null panel: null
} }
}, },
computed: { computed: {
// Current working object.
// A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.preplots) {
deepSet(this.value, [ "preplots" ], []);
}
return this.value.preplots;
} else {
return [];
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "preplots" ], v);
}
}
},
lastPreplotIsValid () { lastPreplotIsValid () {
return this.preplots_.length == 0 || this.validPreplot(this.preplots_[this.preplots_.length-1]); return this.cwo.length == 0 || this.validPreplot(this.cwo[this.cwo.length-1]);
}, },
isValid () { isValid () {
return this.preplots_.every(preplot => this.validPreplot(preplot)); return this.cwo.every(preplot => this.validPreplot(preplot));
} }
}, },
watch: {
preplots () {
if (this.preplots.some( (i, idx) => i != this.preplots_[idx] )) {
this.preplots_ = structuredClone(this.preplots);
}
},
currentItem: {
handler (newValue) {
if (newValue) {
this.getHead();
}
},
deep: true
}
},
methods: { methods: {
titleFor (preplot) { titleFor (preplot) {
@@ -125,7 +135,7 @@ export default {
if (preplot?.path) { if (preplot?.path) {
str += preplot.path; str += preplot.path;
} else { } else {
const idx = this.preplots_.findIndex(i => i == preplot); const idx = this.cwo.findIndex(i => i == preplot);
if (idx != -1) { if (idx != -1) {
str += `Preplot ${idx}`; str += `Preplot ${idx}`;
} else { } else {
@@ -164,9 +174,9 @@ export default {
}, },
deletePreplot (preplot) { deletePreplot (preplot) {
const idx = this.preplots_.find(i => i == preplot); const idx = this.cwo.find(i => i == preplot);
if (idx != -1) { if (idx != -1) {
this.preplots_.splice(idx, 1); this.cwo.splice(idx, 1);
} }
}, },
@@ -178,20 +188,16 @@ export default {
format: "", format: "",
fields: {}, fields: {},
}; };
this.preplots_.push(preplot); this.cwo.push(preplot);
this.panel = this.preplots_.length - 1; this.panel = this.cwo.length - 1;
} }
}, },
reset () { reset () {
this.preplots_ = this.preplots;
}, },
save () { save () {
this.$emit('input', {
preplots: this.preplots_
});
}, },
back () { back () {

View File

@@ -10,12 +10,13 @@
persistent-hint persistent-hint
suffix="min" suffix="min"
type="number" type="number"
v-model.number="production_.nominalLineChangeDuration" v-model.number="cwo.nominalLineChangeDuration"
> >
</v-text-field> </v-text-field>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<!--
<v-btn <v-btn
color="primary" color="primary"
@click="save" @click="save"
@@ -25,6 +26,7 @@
color="warning" color="warning"
@click="reset" @click="reset"
>Reset</v-btn> >Reset</v-btn>
-->
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
color="secondary" color="secondary"
@@ -35,48 +37,56 @@
</template> </template>
<script> <script>
import { deepCompare, deepMerge } from '@/lib/utils'; import { deepSet } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
export default { export default {
name: "DougalProjectSettingsProduction", name: "DougalProjectSettingsProduction",
mixins: [
setIfDifferent({
production: "production_"
})
],
props: { props: {
production: Object value: Object
}, },
data () { data () {
return { return {
production_: {
nominalLineChangeDuration: null
}
} }
}, },
watch: { computed: {
production (newValue) { // Current working object.
this.reset(); // A shortcut so we don't have to specify the full path
// on every input control. It also makes it easier to
// change that path if necessary. Finally, it ensures that
// the properties being modified are always available.
cwo: {
get () {
if (this.value) {
if (!this.value?.production) {
deepSet(this.value, [ "production" ], {
nominalLineChangeDuration: null
});
}
return this.value.production;
} else {
return {};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "production" ], v);
}
}
} }
}, },
methods: { methods: {
reset () { reset () {
this.production_ = deepMerge({
nominalLineChangeDuration: null
}, structuredClone(this.production ?? {}));
}, },
save () { save () {
this.$emit("merge", [ [], this.production_ ]);
this.$nextTick(this.reset);
}, },
back () { back () {

View File

@@ -61,7 +61,7 @@
<component <component
:is="activeComponent" :is="activeComponent"
v-bind="activeValues" v-bind="activeValues"
@merge="merge" v-model.sync="configuration"
@close="deselect" @close="deselect"
></component> ></component>
</v-col> </v-col>