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"
persistent-hint
type="number"
v-model.number="value_.id"
v-model.number="cwo.id"
>
</v-text-field>
<v-text-field
label="IMO"
hint="Project vessel's International Maritime Organisation's identification number"
persistent-hint
v-model.number="value_.imo"
v-model.number="cwo.imo"
>
</v-text-field>
<v-text-field
label="MMSI"
hint="Maritime Mobile Service Identities (MMSI) number"
persistent-hint
v-model.number="value_.mmsi"
v-model.number="cwo.mmsi"
>
</v-text-field>
<v-text-field
@@ -32,13 +32,14 @@
persistent-hint
:type="subscriptionKeyVisible ? 'text' : 'password'"
:append-icon="subscriptionKeyVisible ? 'mdi-eye' : 'mdi-eye-off'"
v-model="value_.subscriptionKey"
v-model="cwo.subscriptionKey"
@click:append="subscriptionKeyVisible = !subscriptionKeyVisible"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -48,6 +49,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -58,54 +60,60 @@
</template>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
export default {
name: "DougalProjectSettingsASAQC",
mixins: [
setIfDifferent({
value: "value_"
})
],
props: [ "value" ],
props: {
value: Object
},
data () {
return {
value_: {
id: null,
imo: null,
mmsi: null,
subscriptionKey: null
},
subscriptionKeyVisible: false
}
},
watch: {
value (newValue) {
this.reset();
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?.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: {
reset () {
this.value_ = deepMerge({
id: null,
imo: null,
mmsi: null,
subscriptionKey: null
}, structuredClone(this.value??{}));
},
save () {
this.$emit("merge", [ [ "cloud", "asaqc" ], this.value_ ]);
this.$nextTick(this.reset);
},
back () {

View File

@@ -10,7 +10,7 @@
persistent-hint
suffix="°"
type="number"
v-model.number="theta_"
v-model.number="cwo.theta"
>
</v-text-field>
<v-text-field
@@ -20,7 +20,7 @@
type="number"
min="0"
step="1"
v-model.number="I_inc_"
v-model.number="cwo.I_inc"
>
</v-text-field>
<v-text-field
@@ -30,7 +30,7 @@
type="number"
min="0"
step="1"
v-model.number="J_inc_"
v-model.number="cwo.J_inc"
>
</v-text-field>
<v-text-field
@@ -38,7 +38,7 @@
hint="Inline bin width (can be negative)"
persistent-hint
type="number"
v-model.number="I_width_"
v-model.number="cwo.I_width"
>
</v-text-field>
<v-text-field
@@ -46,7 +46,7 @@
hint="Crossline bin width (can be negative)"
persistent-hint
type="number"
v-model.number="J_width_"
v-model.number="cwo.J_width"
>
</v-text-field>
<fieldset class="pa-3 mt-3">
@@ -58,7 +58,7 @@
hint="Bin origin easting"
persistent-hint
type="number"
v-model.number="origin_.easting"
v-model.number="cwo.origin.easting"
>
</v-text-field>
</v-col>
@@ -68,7 +68,7 @@
hint="Bin origin northing"
persistent-hint
type="number"
v-model.number="origin_.northing"
v-model.number="cwo.origin.northing"
>
</v-text-field>
</v-col>
@@ -81,7 +81,7 @@
persistent-hint
type="number"
step="1"
v-model.number="origin_.I"
v-model.number="cwo.origin.I"
>
</v-text-field>
</v-col>
@@ -92,7 +92,7 @@
persistent-hint
type="number"
step="1"
v-model.number="origin_.J"
v-model.number="cwo.origin.J"
>
</v-text-field>
</v-col>
@@ -101,6 +101,7 @@
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -110,6 +111,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -120,91 +122,66 @@
</template>
<script>
import { deepSet } from '@/lib/utils';
export default {
name: "DougalProjectSettingsBinning",
props: [ "theta", "I_inc", "J_inc", "I_width", "J_width", "origin" ],
props: {
value: Object
},
data () {
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 () {
if (this.theta != this.theta_) {
this.theta_ = this.theta;
}
},
get () {
if (this.value) {
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 () {
if (this.I_inc != this.I_inc_) {
this.I_inc_ = this.I_inc;
set (v) {
if (this.value) {
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: {
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 () {
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 () {

View File

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

View File

@@ -8,17 +8,18 @@
label="Project folder"
hint="Root file path for this project"
persistent-hint
v-model="rootPath_"
v-model="cwo.rootPath"
>
<dougal-file-browser-dialog
slot="append"
v-model="rootPath_"
v-model="cwo.rootPath"
mimetypes="inode/directory"
></dougal-file-browser-dialog>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -28,6 +29,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -45,32 +47,44 @@ export default {
components: { DougalFileBrowserDialog },
props: [ "rootPath" ],
props: {
value: Object
},
data () {
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 () {
if (this.rootPath != this.rootPath_) {
this.reset();
get () {
if (this.value) {
return this.value;
} else {
return {};
}
},
set (v) {
this.value = v;
}
}
}
},
methods: {
reset () {
this.rootPath_ = this.rootPath;
},
save () {
this.$emit('input', {rootPath: this.rootPath_});
},
back () {

View File

@@ -9,12 +9,13 @@
hint="EPSG code of the project's coordinate reference system"
persistent-hint
type="number"
v-model.number="epsg_"
v-model.number="cwo.epsg"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -24,6 +25,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -38,30 +40,44 @@
export default {
name: "DougalProjectSettingsGeodetics",
props: [ "epsg" ],
props: {
value: Object
},
data () {
return {
epsg_: null
}
},
watch: {
epsg () {
if (this.epsg != this.epsg_) {
this.epsg_ = this.epsg;
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) {
return this.value;
} else {
return {};
}
},
set (v) {
this.value = v;
}
}
},
methods: {
reset () {
this.epsg_ = this.epsg;
},
save () {
this.$emit('input', {epsg: this.epsg_});
},
back () {

View File

@@ -1,11 +1,11 @@
<template>
<v-card>
<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-form>
<v-combobox
v-model="groups_"
v-model="groups"
:items="items"
multiple
:search-input.sync="search"
@@ -59,6 +59,7 @@
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -68,6 +69,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -79,33 +81,19 @@
<script>
import { mapGetters } from 'vuex'
import { deepSet } from '@/lib/utils';
export default {
name: "DougalProjectSettingsGroups",
props: [ "groups" ],
props: [ "value" ],
data () {
return {
groups_: [],
search: null
}
},
watch: {
value (newValue) {
this.reset();
},
groups (cur, prev) {
if (cur?.length == prev?.length) {
return;
}
this.setGroups(cur);
}
},
computed: {
colours () {
@@ -113,7 +101,8 @@ export default {
},
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 () {
@@ -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"])
},
methods: {
setGroups (groups) {
this.groups_ = groups?.map(i => {
return typeof i === "string"
? { text: i, colour: this.nextColour}
: i
});
},
reset () {
this.setGroups(this.groups);
},
save () {
this.$emit('input', {groups: this.groups_?.map(i => i.text)});
},
back () {

View File

@@ -2,7 +2,7 @@
<dougal-project-settings-file-matching-parameters
title="Final P1/11"
subtitle="Final P1/11 files location and parameters."
v-bind="{rootPath}"
v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind"
:is-valid="isValid"
:save="save"
@@ -19,8 +19,7 @@
</style>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex';
@@ -31,55 +30,97 @@ export default {
DougalProjectSettingsFileMatchingParameters
},
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: {
title: String,
subtitle: String,
rootPath: String,
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
value: Object
},
data () {
return {
tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
}
},
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 () {
return {
globs: this.globs_,
paths: this.paths_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
globs: this.cwo?.globs,
paths: this.cwo?.paths,
pattern: this.cwo?.pattern,
lineNameInfo: this.cwo?.lineNameInfo
};
},
isValid () {
return true;
return !!(this.paths.length && this.globs.length && (
this.pattern?.regex &&
["direction", "line", "sequence"].every( i => this.pattern?.captures?.includes(i) )) || (
this.lineNameInfo &&
this.lineNameInfo?.fields &&
return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
this.cwo?.pattern?.regex &&
["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
this.cwo?.lineNameInfo &&
this.cwo?.lineNameInfo?.fields &&
[ "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: {
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 () {
this.$emit("merge", [ ["final", "p111"], {
paths: this.paths_,
globs: this.globs_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {

View File

@@ -8,19 +8,20 @@
label="Pattern"
hint="Regular expression text"
persistent-hint
v-model="regex_"
v-model="cwo.pattern.regex"
>
</v-text-field>
<v-text-field
label="Flags"
hint="Regular expression modifier flags"
persistent-hint
v-model="flags_"
v-model="cwo.pattern.flags"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -30,6 +31,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -40,25 +42,51 @@
</template>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
export default {
name: "DougalProjectSettingsFinalPending",
mixins: [
setIfDifferent({
regex: "regex_",
flags: "flags_"
})
],
props: [ "regex", "flags" ],
props: {
value: Object
},
data () {
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: {
reset () {
this.regex_ = this.regex;
this.flags_ = this.flags;
},
save () {
this.$emit('merge', [ ["final", "pending"], {
regex: this.regex_,
flags: this.flags_
}]);
this.$nextTick(this.reset);
},
back () {

View File

@@ -8,19 +8,20 @@
label="Pattern"
hint="Regular expression text"
persistent-hint
v-model="regex_"
v-model="cwo.pattern.regex"
>
</v-text-field>
<v-text-field
label="Flags"
hint="Regular expression modifier flags"
persistent-hint
v-model="flags_"
v-model="cwo.pattern.flags"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -30,6 +31,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -40,25 +42,51 @@
</template>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
export default {
name: "DougalProjectSettingsRawNTBP",
mixins: [
setIfDifferent({
regex: "regex_",
flags: "flags_"
})
],
props: [ "regex", "flags" ],
props: {
value: Object
},
data () {
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: {
reset () {
this.regex_ = this.regex;
this.flags_ = this.flags;
},
save () {
this.$emit('merge', [ ["raw", "ntbp"], {
regex: this.regex_,
flags: this.flags_
}]);
this.$nextTick(this.reset);
},
back () {

View File

@@ -2,7 +2,7 @@
<dougal-project-settings-file-matching-parameters
title="Raw P1/11"
subtitle="Raw P1/11 files location and parameters."
v-bind="{rootPath}"
v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind"
:is-valid="isValid"
:save="save"
@@ -19,8 +19,7 @@
</style>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex';
@@ -31,54 +30,97 @@ export default {
DougalProjectSettingsFileMatchingParameters
},
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: {
title: String,
subtitle: String,
rootPath: String,
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
value: Object
},
data () {
return {
tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
}
},
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 () {
return {
globs: this.globs_,
paths: this.paths_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
globs: this.cwo?.globs,
paths: this.cwo?.paths,
pattern: this.cwo?.pattern,
lineNameInfo: this.cwo?.lineNameInfo
};
},
isValid () {
return !!(this.paths_.length && this.globs_.length && (
this.pattern_?.regex &&
["direction", "line", "sequence"].every( i => this.pattern_?.captures?.includes(i) )) || (
this.lineNameInfo_ &&
this.lineNameInfo_?.fields &&
return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
this.cwo?.pattern?.regex &&
["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
this.cwo?.lineNameInfo &&
this.cwo?.lineNameInfo?.fields &&
[ "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: {
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 () {
this.$emit("merge", [ ["raw", "p111"], {
paths: this.paths_,
globs: this.globs_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {

View File

@@ -2,6 +2,7 @@
<dougal-project-settings-file-matching-parameters
title="Smartsource header data"
subtitle="Smartsource header data files location and parameters."
v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind"
:is-valid="isValid"
:save="save"
@@ -18,8 +19,7 @@
</style>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex';
@@ -30,57 +30,85 @@ export default {
DougalProjectSettingsFileMatchingParameters
},
props: [ "value", "title", "subtitle" ],
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: {
title: String,
subtitle: String,
rootPath: String,
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
value: Object
},
data () {
return {
tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
}
},
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 () {
return {
globs: this.globs_,
paths: this.paths_,
//pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
globs: this.cwo?.globs,
paths: this.cwo?.paths,
pattern: this.cwo?.pattern,
lineNameInfo: this.cwo?.lineNameInfo
};
},
isValid () {
return true;
return !!(this.paths.length && this.globs.length && (
this.pattern?.regex &&
["direction", "line", "sequence"].every( i => this.pattern?.captures?.includes(i) )) || (
this.lineNameInfo &&
this.lineNameInfo?.fields &&
return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
this.cwo?.pattern?.regex &&
["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
this.cwo?.lineNameInfo &&
this.cwo?.lineNameInfo?.fields &&
[ "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: {
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 () {
this.$emit("merge", [ ["raw", "source", "smsrc", "header"], {
paths: this.paths_,
globs: this.globs_,
pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {

View File

@@ -2,6 +2,7 @@
<dougal-project-settings-file-matching-parameters
title="Smartsource hydrophone data"
subtitle="Smartsource SEG-Y hydrophone data files location and parameters."
v-bind="{rootPath: value.rootPath}"
v-bind.sync="bind"
:is-valid="isValid"
:save="save"
@@ -18,7 +19,7 @@
</style>
<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 { mapActions, mapGetters } from 'vuex';
@@ -30,57 +31,85 @@ export default {
DougalProjectSettingsFileMatchingParameters
},
props: [ "value", "title", "subtitle" ],
mixins: [
setIfDifferent({
globs: "globs_",
paths: "paths_",
pattern: "pattern_",
lineNameInfo: "lineNameInfo_"
})
],
props: {
title: String,
subtitle: String,
rootPath: String,
paths: Array,
globs: Array,
lineNameInfo: Object,
pattern: Object
value: Object
},
data () {
return {
tab: null,
paths_: [],
globs_: [],
pattern_: {},
lineNameInfo_: {}
}
},
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 () {
return {
globs: this.globs_,
paths: this.paths_,
//pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
globs: this.cwo?.globs,
paths: this.cwo?.paths,
pattern: this.cwo?.pattern,
lineNameInfo: this.cwo?.lineNameInfo
};
},
isValid () {
return true;
return !!(this.paths.length && this.globs.length && (
this.pattern?.regex &&
["sequence"].every( i => this.pattern?.captures?.includes(i) )) || (
this.lineNameInfo &&
this.lineNameInfo?.fields &&
[ "sequence" ].every( i =>
["offset", "length"].every( j => j in this.lineNameInfo.fields[i] ))));
return !!(this.cwo?.paths.length && this.cwo?.globs.length && (
this.cwo?.pattern?.regex &&
["direction", "line", "sequence"].every( i => this.cwo?.pattern?.captures?.includes(i) )) || (
this.cwo?.lineNameInfo &&
this.cwo?.lineNameInfo?.fields &&
[ "line", "sequence", "incr" ].every( i =>
["offset", "length"].every( j => j in this.cwo?.lineNameInfo.fields[i] ))));
}
},
@@ -91,40 +120,14 @@ export default {
methods: {
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 () {
this.$emit("merge", [ ["raw", "source", "smsrc", "segy"], {
paths: this.paths_,
globs: this.globs_,
//pattern: this.pattern_,
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {

View File

@@ -8,19 +8,20 @@
label="ID"
hint="Short survey ID"
persistent-hint
v-model="id_"
v-model="cwo.id"
>
</v-text-field>
<v-text-field
label="Name"
hint="Survey name"
persistent-hint
v-model="name_"
v-model="cwo.name"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -30,6 +31,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -45,40 +47,43 @@ export default {
name: "DougalProjectSettingsNameId",
props: {
id: String,
name: String
value: Object
},
data () {
return {
id_: "",
name_: ""
}
},
watch: {
id () {
if (this.id != this.id_) {
this.id_ = this.id;
}
},
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: {
name () {
if (this.name != this.name_) {
this.name_ = this.name;
get () {
if (this.value) {
return this.value;
} else {
return {};
}
},
set (v) {
this.value = v;
}
}
},
methods: {
reset () {
this.id_ = this.id;
this.name_ = this.name;
},
save () {
this.$emit('input', {id: this.id_, name: this.name_});
},
back () {

View File

@@ -1,26 +1,27 @@
<template>
<v-card>
<v-card-title>Files</v-card-title>
<v-card-subtitle>File path configuration for this project.</v-card-subtitle>
<v-card-title>Online line name</v-card-title>
<v-card-subtitle>Line name decoding configuration for real-time data</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="Example file name"
hint="Enter the name of a representative file to make it easier to visualise your configuration"
persistent-hint
v-model="lineNameInfo_.example"
v-model="cwo.lineNameInfo.example"
></v-text-field>
<dougal-fixed-string-decoder
title="Line name format"
subtitle="Format of line names as configured in the navigation system"
:multiline="true"
:text="lineNameInfo_.example"
:fields="lineNameInfo_.fields"
:text="cwo.lineNameInfo.example"
:fields="cwo.lineNameInfo.fields"
></dougal-fixed-string-decoder>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -30,6 +31,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -47,10 +49,8 @@
</style>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
import DougalFixedStringDecoder from '@/components/decoder/fixed-string-decoder';
import { mapActions, mapGetters } from 'vuex';
export default {
name: "DougalProjectSettingsOnlineLineNameFormat",
@@ -59,81 +59,76 @@ export default {
DougalFixedStringDecoder
},
mixins: [
setIfDifferent({
lineNameInfo: "lineNameInfo_"
})
],
props: {
lineNameInfo: Object
value: Object
},
data () {
return {
lineNameInfo_: {
example: "",
fields: {}
}
}
},
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 () {
return !!(this.lineNameInfo_ &&
this.lineNameInfo_?.fields &&
[ "line", "sequence", "incr" ].every( i =>
["offset", "length"].every( j => j in this.lineNameInfo_.fields[i] )));
}
get () {
if (this.value) {
if (!this.value?.online?.line) {
deepSet(this.value, [ "online", "line" ], {
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: {
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 () {
this.$emit("merge", [ ["online", "line"], {
lineNameInfo: this.lineNameInfo_
}]);
this.$nextTick(this.reset);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
}
},

View File

@@ -10,7 +10,7 @@
type="number"
hint="Expected line change time in minutes"
persistent-hint
v-model.number="planner_.defaultLineChangeDuration"
v-model.number="cwo.defaultLineChangeDuration"
>
</v-text-field>
<v-text-field
@@ -19,7 +19,7 @@
type="number"
hint="Expected acquisition speed in knots"
persistent-hint
v-model.number="planner_.defaultAcquisitionSpeed"
v-model.number="cwo.defaultAcquisitionSpeed"
>
</v-text-field>
<v-text-field
@@ -27,7 +27,7 @@
type="number"
hint="Default number of shots to overlap before the FGSP, for reshoots"
persistent-hint
v-model.number="planner_.overlapBefore"
v-model.number="cwo.overlapBefore"
>
</v-text-field>
<v-text-field
@@ -35,12 +35,13 @@
type="number"
hint="Default number of shots to overlap after the LGSP, for reshoots"
persistent-hint
v-model.number="planner_.overlapAfter"
v-model.number="cwo.overlapAfter"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -50,6 +51,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -60,55 +62,60 @@
</template>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
export default {
name: "DougalProjectSettingsPlanner",
mixins: [
setIfDifferent({
planner: "planner_"
})
],
props: {
planner: Object
value: Object
},
data () {
return {
planner_: {
defaultLineChangeDuration: null,
defaultAcquisitionSpeed: null,
overlapBefore: null,
overlapAfter: null
}
}
},
watch: {
planner (newValue) {
this.reset();
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?.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: {
reset () {
this.planner_ = deepMerge({
defaultLineChangeDuration: null,
defaultAcquisitionSpeed: null,
overlapBefore: null,
overlapAfter: null
}, structuredClone(this.planner ?? {}));
},
save () {
this.$emit("merge", [ [ ], this.planner_ ]);
this.$nextTick(this.reset);
},
back () {

View File

@@ -5,14 +5,14 @@
<v-card-text>
<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>
{{ titleFor(preplot) }}
</v-expansion-panel-header>
<v-expansion-panel-content>
<dougal-project-settings-preplots-preplot
v-model="preplots_[idx]"
:root-path="rootPath"
v-model="cwo[idx]"
:root-path="value.rootPath"
></dougal-project-settings-preplots-preplot>
<v-btn
@@ -42,6 +42,7 @@
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
:disabled="!isValid"
@@ -52,6 +53,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -78,45 +80,53 @@ export default {
DougalProjectSettingsPreplotsPreplot,
},
props: [ "rootPath", "preplots" ],
props: {
value: Object
},
data () {
return {
preplots_: [],
panel: null
}
},
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 () {
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 () {
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: {
titleFor (preplot) {
@@ -125,7 +135,7 @@ export default {
if (preplot?.path) {
str += preplot.path;
} else {
const idx = this.preplots_.findIndex(i => i == preplot);
const idx = this.cwo.findIndex(i => i == preplot);
if (idx != -1) {
str += `Preplot ${idx}`;
} else {
@@ -164,9 +174,9 @@ export default {
},
deletePreplot (preplot) {
const idx = this.preplots_.find(i => i == preplot);
const idx = this.cwo.find(i => i == preplot);
if (idx != -1) {
this.preplots_.splice(idx, 1);
this.cwo.splice(idx, 1);
}
},
@@ -178,20 +188,16 @@ export default {
format: "",
fields: {},
};
this.preplots_.push(preplot);
this.panel = this.preplots_.length - 1;
this.cwo.push(preplot);
this.panel = this.cwo.length - 1;
}
},
reset () {
this.preplots_ = this.preplots;
},
save () {
this.$emit('input', {
preplots: this.preplots_
});
},
back () {

View File

@@ -10,12 +10,13 @@
persistent-hint
suffix="min"
type="number"
v-model.number="production_.nominalLineChangeDuration"
v-model.number="cwo.nominalLineChangeDuration"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<!--
<v-btn
color="primary"
@click="save"
@@ -25,6 +26,7 @@
color="warning"
@click="reset"
>Reset</v-btn>
-->
<v-spacer></v-spacer>
<v-btn
color="secondary"
@@ -35,48 +37,56 @@
</template>
<script>
import { deepCompare, deepMerge } from '@/lib/utils';
import setIfDifferent from '@/lib/watcher-mixin';
import { deepSet } from '@/lib/utils';
export default {
name: "DougalProjectSettingsProduction",
mixins: [
setIfDifferent({
production: "production_"
})
],
props: {
production: Object
value: Object
},
data () {
return {
production_: {
nominalLineChangeDuration: null
}
}
},
watch: {
production (newValue) {
this.reset();
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?.production) {
deepSet(this.value, [ "production" ], {
nominalLineChangeDuration: null
});
}
return this.value.production;
} else {
return {};
}
},
set (v) {
if (this.value) {
deepSet(this.value, [ "production" ], v);
}
}
}
},
methods: {
reset () {
this.production_ = deepMerge({
nominalLineChangeDuration: null
}, structuredClone(this.production ?? {}));
},
save () {
this.$emit("merge", [ [], this.production_ ]);
this.$nextTick(this.reset);
},
back () {

View File

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