Add project configuration components.

The configuration settings are quite complex so we divide the
GUI into modular components.
This commit is contained in:
D. Berge
2023-10-29 15:13:01 +01:00
parent e7c29ba14c
commit 642f5a7585
19 changed files with 2298 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
<template>
<v-card>
<v-card-title>ASAQC</v-card-title>
<v-card-subtitle>Equinor's cloud API configuration.</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="ASAQC ID"
hint="ID number for this survey in ASAQC"
persistent-hint
type="number"
v-model.number="id"
>
</v-text-field>
<v-text-field
label="IMO"
hint="Project vessel's International Maritime Organisation's identification number"
persistent-hint
v-model.number="imo"
>
</v-text-field>
<v-text-field
label="MMSI"
hint="Maritime Mobile Service Identities (MMSI) number"
persistent-hint
v-model.number="mmsi"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsASAQC",
props: [ "value" ],
data () {
return {
id: null,
imo: null,
mmsi: null,
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,172 @@
<template>
<v-card>
<v-card-title>Binning parameters</v-card-title>
<!-- <v-card-subtitle></v-card-subtitle> -->
<v-card-text>
<v-form>
<v-text-field
label="Azimuth"
hint="Direction of I (inline) axis"
persistent-hint
suffix="°"
type="number"
v-model.number="theta"
>
</v-text-field>
<v-text-field
label="I increment"
hint="Bin number increment along the inline axis"
persistent-hint
type="number"
min="0"
step="1"
v-model.number="I_inc"
>
</v-text-field>
<v-text-field
label="J increment"
hint="Bin number increment along the crossline axis"
persistent-hint
type="number"
min="0"
step="1"
v-model.number="J_inc"
>
</v-text-field>
<v-text-field
label="I width"
hint="Inline bin width (can be negative)"
persistent-hint
type="number"
v-model.number="I_width"
>
</v-text-field>
<v-text-field
label="J width"
hint="Crossline bin width (can be negative)"
persistent-hint
type="number"
v-model.number="J_width"
>
</v-text-field>
<fieldset class="pa-3 mt-3">
<legend>Origin</legend>
<v-row>
<v-col>
<v-text-field
label="Easting"
hint="Bin origin easting"
persistent-hint
type="number"
v-model.number="origin.easting"
>
</v-text-field>
</v-col>
<v-col>
<v-text-field
label="Northing"
hint="Bin origin northing"
persistent-hint
type="number"
v-model.number="origin.northing"
>
</v-text-field>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field
label="I"
hint="Bin origin inline"
persistent-hint
type="number"
step="1"
v-model.number="origin.I"
>
</v-text-field>
</v-col>
<v-col>
<v-text-field
label="J"
hint="Bin origin crossline"
persistent-hint
type="number"
step="1"
v-model.number="origin.J"
>
</v-text-field>
</v-col>
</v-row>
</fieldset>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsBinning",
props: [ "value" ],
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: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,249 @@
<template>
<v-card>
<v-card-title v-text="title"></v-card-title>
<v-card-subtitle v-text="subtitle"></v-card-subtitle>
<v-card-text>
<v-tabs v-model="tab">
<v-tab>Paths</v-tab>
<v-tab>Globs</v-tab>
<v-tab>Pattern</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item>
<v-card flat>
<v-card-subtitle>
A list of directories which are searched for matching files.
</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field v-for="(item, index) in paths" :key="index"
v-model="paths[index]"
>
<dougal-file-browser-dialog
slot="append"
v-model="paths[index]"
:root="value.rootPath"
:mimetypes="[ 'inode/directory' ]"
title="Select a directory"
></dougal-file-browser-dialog>
<v-btn slot="append-outer"
fab
x-small text
dark
color="red"
title="Remove"
@click="() => paths.splice(index, 1)"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
</v-text-field>
<v-btn
class="mx-2"
fab dark
x-small text
color="primary"
title="Add path"
@click="() => paths.push('')"
>
<v-icon dark>mdi-plus</v-icon>
</v-btn>
</v-form>
</v-card-text>
</v-card>
</v-tab-item>
<v-tab-item>
<v-card flat>
<v-card-subtitle>
A list of <a href="https://en.wikipedia.org/wiki/Glob_(programming)" target="_blank">glob patterns</a> expanding to match the files of interest. Note that Linux is case-sensitive.
</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field v-for="(item, index) in globs" :key="index"
v-model="globs[index]"
>
<v-btn slot="append-outer"
fab
x-small text
dark
color="red"
title="Remove"
@click="() => globs.splice(index, 1)"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
</v-text-field>
<v-btn
class="mx-2"
fab dark
x-small text
color="primary"
title="Add glob pattern"
@click="() => globs.push('')"
>
<v-icon dark>mdi-plus</v-icon>
</v-btn>
</v-form>
</v-card-text>
</v-card>
</v-tab-item>
<v-tab-item>
<v-card flat>
<v-card-subtitle>
Regular expression that describes the file format definition. Used to capture information such as line and sequence number, etc.
</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
class="mb-5"
label="Regular expression"
v-model="pattern.regex"
persistent-hint
hint="Regular expression"
>
</v-text-field>
<fieldset class="pa-3 mb-5">
<legend>Captures</legend>
<v-text-field v-for="(item, index) in pattern.captures" :key="index"
v-model="pattern.captures[index]"
>
<v-btn slot="append-outer"
fab
x-small text
dark
color="red"
title="Remove"
@click="() => pattern.captures.splice(index, 1)"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
</v-text-field>
<v-btn
class="mx-2"
fab dark
x-small text
color="primary"
title="Add capture"
@click="() => pattern.captures.push('')"
>
<v-icon dark>mdi-plus</v-icon>
</v-btn>
</fieldset>
<v-text-field
class="mb-5"
label="Flags"
v-model="pattern.flags"
persistent-hint
hint="Regular expression modifier flags"
>
</v-text-field>
</v-form>
</v-card-text>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
:disabled="!isValid"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
}
</style>
<script>
import DougalFileBrowserDialog from '@/components/file-browser/file-browser-dialog';
import { mapActions, mapGetters } from 'vuex';
export default {
name: "DougalProjectSettingsFileMatchingParameters",
components: {
DougalFileBrowserDialog
},
props: [ "value", "title", "subtitle" ],
data () {
return {
tab: null,
globs: [],
paths: [],
pattern: {
flags: "i",
regex: null,
captures: []
}
}
},
computed: {
isValid () {
return false;
// return this.preplots && this.preplots.every( item => item.format != null );
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
if (!this.value) {
return;
}
this.globs = this.value.globs;
this.paths = this.value.paths;
this.pattern = this.value.pattern;
},
save () {
this.$emit('input', this.data);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<v-card>
<v-card-title>Files</v-card-title>
<v-card-subtitle>File path configuration for this project.</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="Project folder"
hint="Root file path for this project"
persistent-hint
v-model="path"
>
<dougal-file-browser-dialog
slot="append"
v-model="path"
mimetypes="inode/directory"
></dougal-file-browser-dialog>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import DougalFileBrowserDialog from '@/components/file-browser/file-browser-dialog';
export default {
name: "DougalProjectSettingsFilePath",
components: { DougalFileBrowserDialog },
props: [ "value" ],
data () {
return {
path: ""
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,322 @@
<template>
<v-card flat>
<v-card-text>
<div class="sample" v-html="sampleHtml" ref="sample">
</div>
<v-divider></v-divider>
<v-form>
<v-container>
<v-row no-gutters v-for="(field, key) in {line, point, easting, northing}" :key="key">
<v-col>
<v-chip outlined :color="field.colour">{{field.label}}</v-chip>
</v-col>
<v-col>
<v-text-field
class="ml-3"
dense
label="From"
type="number"
min="0"
:ref="key"
v-model.number="field.offset"
></v-text-field>
</v-col>
<v-col>
<v-text-field
class="ml-3"
dense
label="Width"
type="number"
min="0"
v-model.number="field.width"
></v-text-field>
</v-col>
</v-row>
</v-container>
</v-form>
</v-card-text>
<v-card-actions>
</v-card-actions>
</v-card>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
overflow-x: auto;
overflow-y: hidden;
}
</style>
<script>
function arraysAreEqual(arr0, arr1) {
return (arr0 && arr1 && arr0.length == arr1.length) &&
arr0.reduce( (acc, cur, idx) =>
acc && (arr1[idx] == cur), true );
}
function repeatsLength(arr, comparator=(a, b) => a == b) {
function checkRepeat(arr) {
let idx = 0;
if (arr.length) {
while (comparator(arr[idx], arr[++idx]));
}
return idx;
}
const repeats = [];
let offset = 0;
let count;
while (count = checkRepeat(arr.slice(offset))) {
repeats.push(count);
offset += count;
}
return repeats;
}
export default {
name: "DougalProjectSettingsFixedWidthFormat",
props: [ "value", "sample" ],
data () {
return {
line: {
name: "line_name",
type: "int",
label: "Line",
offset: 0,
width: 4,
colour: "green"
},
point: {
name: "point_number",
type: "int",
label: "Point",
offset: 4,
width: 4,
colour: "blue"
},
easting: {
name: "easting",
type: "float",
label: "Easting",
offset: 8,
width: 12,
colour: "red"
},
northing: {
name: "northing",
type: "float",
label: "Northing",
offset: 20,
width: 12,
colour: "orange"
}
}
},
watch: {
value (newValue) {
this.reset();
},
fields: {
handler () {
if (this.overlappingFields) {
this.$emit("input", null);
} else {
this.$emit("input", {
names: this.names,
types: this.types,
widths: this.widths
});
}
},
deep: true
}
},
computed: {
sampleHtml () {
if (!this.sample) {
return "";
}
const parts = this.fieldsDescending;
const partsForColumn = (col) => {
return parts.filter(part =>
part.offset <= col && part.offset+part.width > col
);
}
const partsForLine = (line) => {
return Array.from({length: line.length}, (_, idx) => partsForColumn(idx));
}
function getDecorators(arr, comparator, specialValue) {
const repeats = repeatsLength(arr, comparator);
let sum = 0;
const res = [];
repeats.slice(0, -1).forEach( count => {
const idx = sum;
sum += count;
const el = arr[idx];
if (el.length) {
if (el.length == 1) {
// Only one field, return it
res.push({
...el[0],
offset: idx,
width: Math.min(Math.min(el[0].offset+el[0].width, sum+idx) - idx, sum-idx)
});
} else {
// More than one element, return special value
res.push({
...specialValue,
offset: idx,
width: sum-idx
});
}
}
});
return res.sort( (a, b) => b.offset-a.offset );
}
const lines = this.sample.split("\n").map( line => {
const decorators = getDecorators(partsForLine(line), arraysAreEqual, {name: "Overlap", colour: "grey"});
let s = line;
for (const part of decorators) {
const s0 = s.slice(0, part.offset);
const s1 = s.slice(part.offset, part.offset+part.width);
const s2 = s.slice(part.offset+part.width);
s = s0+`<span class="${part.colour}--text" title="${part.name}" style="border: 1px solid;">${s1}</span>${s2}`;
}
return s;
});
return lines.join("<br/>");
},
overlappingFields () {
function isOverlapping (a, b) {
return a.offset < b.offset+b.width && b.offset < a.offset+a.width;
}
for (const field of this.fields) {
for (const otherField of this.fields) {
if (field != otherField && isOverlapping(field, otherField)) {
return true;
}
}
}
return false;
},
names () {
return this.fieldsAscending.map(f => f.name);
},
types () {
return this.fieldsAscending.map(f => f.type);
},
widths () {
if (this.overlappingFields) {
return [];
}
const fields = this.fieldsAscending;
const w = [ ];
if (fields[0].offset) {
w.push(-fields[0].offset);
}
w.push(fields[0].width);
for (let idx=1; idx<fields.length; idx++) {
const f0 = fields[idx-1];
const f1 = fields[idx];
const gap = f0.offset+f0.width-f1.offset;
if (gap) {
w.push(gap);
}
w.push(f1.width);
}
return w;
},
fields () {
return [ this.line, this.point, this.easting, this.northing ];
},
fieldsAscending () {
return Object.values(this.fields).sort( (a, b) => a.offset - b.offset );
},
fieldsDescending () {
return Object.values(this.fields).sort( (a, b) => b.offset - a.offset );
}
},
methods: {
reset () {
if (!this.value) {
return;
}
const fieldFor = (index) => {
return this.fields.find(field => field.name == this.value.names[index]);
}
let offset=0;
let index=0;
for (const width of this.value.widths) {
if (width < 0) {
offset -= width;
} else {
fieldFor(index).offset = offset;
fieldFor(index).width = width;
offset += width;
index++;
}
}
},
save () {
this.$emit('input', {...this.$data.values});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
document.addEventListener("selectionchange", this.handleSelection);
},
beforeUnmount () {
document.removeEventListener("selectionchange", this.handleSelection);
}
}
</script>

View File

@@ -0,0 +1,78 @@
<template>
<v-card>
<v-card-title>Geodetics</v-card-title>
<v-card-subtitle>Geodetic parameters.</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="EPSG code"
hint="EPSG code of the project's coordinate reference system"
persistent-hint
type="number"
v-model.number="epsg"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsGeodetics",
props: [ "value" ],
data () {
return {
epsg: null
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,158 @@
<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-text>
<v-form>
<v-combobox
v-model="groups"
:items="items"
multiple
:search-input.sync="search"
:hide-no-data="!search"
hide-selected
chips
hint="Project group(s). Type a value to create a new group (case sensitive)"
persistent-hint
>
<template v-slot:no-data>
<v-list-item>
<small>New group: </small>
<v-chip class="ml-3"
:color="`grey lighten-2`"
label
small
>
{{ search }}
</v-chip>
</v-list-item>
</template>
<template v-slot:selection="{ attrs, item, parent, selected }">
<v-chip
v-if="item === Object(item)"
v-bind="attrs"
:color="`${item.colour} lighten-3`"
:input-value="selected"
label
small
>
<span class="pr-2">
{{ item.text }}
</span>
<v-icon
small
@click="parent.selectItem(item)"
>
$delete
</v-icon>
</v-chip>
</template>
<template v-slot:item="{ index, item }">
<v-chip
:color="`${item.colour} lighten-3`"
label
small
>{{ item.text }}</v-chip>
</template>
</v-combobox>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: "DougalProjectSettingsGroups",
props: [ "value" ],
data () {
return {
groups: [],
search: null
}
},
watch: {
value (newValue) {
this.reset();
},
groups (cur, prev) {
if (cur?.length == prev?.length) {
return;
}
this.groups = cur?.map(i => {
return typeof i === "string"
? { text: i, colour: this.nextColour}
: i
});
}
},
computed: {
colours () {
return [ "green", "purple", "indigo", "cyan", "teal", "orange" ];
},
nextColour () {
return this.colours[(this.items.length + (this.groups?.length ?? 0)) % this.colours.length];
},
items () {
return this.projectGroups.map((item, idx) => {
return {
text: item,
colour: this.colours[idx % this.colours.length]
};
});
},
...mapGetters(["projectGroups"])
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {groups: this.groups?.map(i => i.text)});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<dougal-project-settings-file-matching-parameters
:value="value" title="Final P1/11" subtitle="Final P1/11 files location and parameters."
>
</dougal-project-settings-file-matching-parameters>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
}
</style>
<script>
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex';
export default {
name: "DougalProjectSettingsFinal111",
components: {
DougalProjectSettingsFileMatchingParameters
},
props: [ "value", "title", "subtitle" ],
data () {
return {
tab: null,
globs: [],
paths: [],
pattern: {
flags: "i",
regex: null,
captures: []
}
}
},
computed: {
isValid () {
return false;
// return this.preplots && this.preplots.every( item => item.format != null );
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
if (!this.value) {
return;
}
this.globs = this.value.globs;
this.paths = this.value.paths;
this.pattern = this.value.pattern;
},
save () {
this.$emit('input', this.data);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<v-card>
<v-card-title>Pending sequence detection</v-card-title>
<v-card-subtitle>Sequences which are pending acceptance (e.g., due to marginal quality) can be marked as such by the naming of their <b>final</b> files or parent directory. Dougal uses regular expression matching against the full path, not just the file name. This pattern applies to both P1/90 and P1/11 files.</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="Pattern"
hint="Regular expression text"
persistent-hint
v-model="regex"
>
</v-text-field>
<v-text-field
label="Flags"
hint="Regular expression modifier flags"
persistent-hint
v-model="flags"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsFinalPending",
props: [ "value" ],
data () {
return {
regex: "PENDING",
flags: "i"
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<v-card>
<v-card-title>NTBP detection</v-card-title>
<v-card-subtitle><abbr title="Not to be processed">NTBP</abbr> sequences are denoted by the naming of its files or any of its parent directories. Dougal uses regular expression matching against the full path, not just the file name. This pattern applies to both P1/90 and P1/11 files.</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="Pattern"
hint="Regular expression text"
persistent-hint
v-model="regex"
>
</v-text-field>
<v-text-field
label="Flags"
hint="Regular expression modifier flags"
persistent-hint
v-model="flags"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsRawNTBP",
props: [ "value" ],
data () {
return {
regex: "NTBP",
flags: "i"
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<dougal-project-settings-file-matching-parameters
:value="value" title="Raw P1/11" subtitle="Raw P1/11 files location and parameters."
>
</dougal-project-settings-file-matching-parameters>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
}
</style>
<script>
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex';
export default {
name: "DougalProjectSettingsRaw111",
components: {
DougalProjectSettingsFileMatchingParameters
},
props: [ "value", "title", "subtitle" ],
data () {
return {
tab: null,
globs: [],
paths: [],
pattern: {
flags: "i",
regex: null,
captures: []
}
}
},
computed: {
isValid () {
return false;
// return this.preplots && this.preplots.every( item => item.format != null );
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
if (!this.value) {
return;
}
this.globs = this.value.globs;
this.paths = this.value.paths;
this.pattern = this.value.pattern;
},
save () {
this.$emit('input', this.data);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<dougal-project-settings-file-matching-parameters
:value="value" title="Smartsource" subtitle="Smartsource data files location and parameters."
>
</dougal-project-settings-file-matching-parameters>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
}
</style>
<script>
import DougalProjectSettingsFileMatchingParameters from '@/components/project-settings/file-matching-parameters';
import { mapActions, mapGetters } from 'vuex';
export default {
name: "DougalProjectSettingsSmartsource",
components: {
DougalProjectSettingsFileMatchingParameters
},
props: [ "value", "title", "subtitle" ],
data () {
return {
tab: null,
globs: [],
paths: [],
pattern: {
flags: "i",
regex: null,
captures: []
}
}
},
computed: {
isValid () {
return false;
// return this.preplots && this.preplots.every( item => item.format != null );
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
if (!this.value) {
return;
}
this.globs = this.value.globs;
this.paths = this.value.paths;
this.pattern = this.value.pattern;
},
save () {
this.$emit('input', this.data);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,85 @@
<template>
<v-card>
<v-card-title>Name &amp; ID</v-card-title>
<v-card-subtitle>The survey's name and short ID. The latter must match the value used in ASAQC, if applicable.</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="ID"
hint="Short survey ID"
persistent-hint
v-model="id"
>
</v-text-field>
<v-text-field
label="Name"
hint="Survey name"
persistent-hint
v-model="name"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsNameId",
props: [ "value" ],
data () {
return {
id: "",
name: ""
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,65 @@
<template>
<v-card>
<v-card-title>Not implemented</v-card-title>
<v-card-text>
The code for this configuration section has not yet been implemented.
</v-card-text>
<v-card-actions>
<v-btn
disabled
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
disabled
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsNotImplemented",
props: [ "value" ],
data () {
return {
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
},
save () {
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,80 @@
<template>
<dougal-project-settings-regex-pattern-captures
v-model="pattern" title="Line name format" subtitle="Format of line names as configured in the navigation system"
>
</dougal-project-settings-regex-pattern-captures>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
}
</style>
<script>
import DougalProjectSettingsRegexPatternCaptures from '@/components/project-settings/regex-pattern-captures';
import { mapActions, mapGetters } from 'vuex';
export default {
name: "DougalProjectSettingsOnlineLineNameFormat",
components: {
DougalProjectSettingsRegexPatternCaptures
},
props: [ "value" ],
data () {
return {
pattern: {
flags: "i",
regex: null,
captures: []
}
}
},
computed: {
isValid () {
return false;
// return this.preplots && this.preplots.every( item => item.format != null );
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
if (!this.value) {
return;
}
this.pattern = {...this.value};
},
save () {
this.$emit('input', this.pattern);
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,107 @@
<template>
<v-card>
<v-card-title>Planner settings</v-card-title>
<v-card-subtitle>Default values when creating new sequences in the planner. These values can then be changed for each individual entry.</v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="Default line change duration"
suffix="min"
type="number"
hint="Expected line change time in minutes"
persistent-hint
v-model.number="defaultLineChangeDuration"
>
</v-text-field>
<v-text-field
label="Default acquisition speed"
suffix="kt"
type="number"
hint="Expected acquisition speed in knots"
persistent-hint
v-model.number="defaultAcquisitionSpeed"
>
</v-text-field>
<v-text-field
label="Overlap before"
type="number"
hint="Default number of shots to overlap before the FGSP, for reshoots"
persistent-hint
v-model.number="overlapBefore"
>
</v-text-field>
<v-text-field
label="Overlap after"
type="number"
hint="Default number of shots to overlap after the LGSP, for reshoots"
persistent-hint
v-model.number="overlapAfter"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsPlanner",
props: [ "value" ],
data () {
return {
defaultLineChangeDuration: null,
defaultAcquisitionSpeed: null,
overlapBefore: null,
overlapAfter: null
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,182 @@
<template>
<v-card>
<v-card-title>Preplots</v-card-title>
<v-card-subtitle>Preplot files location and format.</v-card-subtitle>
<v-card-text>
<v-tabs v-model="tab">
<v-tab v-for="item in preplots">{{tabNameFor(item)}}</v-tab>
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item v-for="item in preplots">
<v-card flat>
<v-card-text>
<v-form>
<v-text-field
label="Path"
v-model="item.path"
>
<dougal-file-browser-dialog
slot="append"
v-model="item.path"
:root="value.rootPath"
:mimetypes="[ 'text/plain', '*.sps' ]"
></dougal-file-browser-dialog>
</v-text-field>
<v-text-field v-if="item.class == 'S'"
class="mb-3"
label="Sailline offset"
prefix="±"
type="number"
hint="The value to add/substract to source lines to get to the corresponding sailline"
v-model.number="item.saillineOffset"
>
</v-text-field>
<v-expansion-panels :value="head.length ? 0 : null">
<v-expansion-panel>
<v-expansion-panel-header>Column settings</v-expansion-panel-header>
<v-expansion-panel-content>
<dougal-fixed-width-format v-model="item.format" :sample="head">
</dougal-fixed-width-format>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-form>
</v-card-text>
</v-card>
</v-tab-item>
</v-tabs-items>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
:disabled="!isValid"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
}
</style>
<script>
import DougalFileBrowserDialog from '@/components/file-browser/file-browser-dialog';
import DougalFixedWidthFormat from './fixed-width-format';
import { mapActions, mapGetters } from 'vuex';
export default {
name: "DougalProjectSettingsPreplots",
components: {
DougalFileBrowserDialog,
DougalFixedWidthFormat
},
props: [ "value" ],
data () {
return {
tab: null,
preplots: [],
head: ""
}
},
computed: {
currentItem () {
if (this.tab !== null) {
return this.preplots[this.tab];
}
},
isValid () {
return this.preplots && this.preplots.every( item => item.format != null );
}
},
watch: {
value (newValue) {
this.reset();
},
currentItem: {
handler (newValue) {
if (newValue) {
this.getHead();
}
},
deep: true
}
},
methods: {
tabNameFor (item) {
switch (item.class) {
case "S":
return "Source";
case "V":
return "Vessel";
default:
return item.class || "?";
}
},
async getHead () {
if (this.currentItem) {
const url = `/files/${this.currentItem.path}`;
const init = {
text: true,
headers: {
"Range": "bytes=0-1024"
}
};
this.head = await this.api([url, init]);
this.head = this.head?.substring(0, this.head.lastIndexOf("\n")) || "";
}
},
reset () {
if (!this.value) {
return;
}
this.preplots = JSON.parse(JSON.stringify(this.value.preplots));
},
save () {
this.$emit('input', {preplots: [...this.preplots]});
},
back () {
this.$emit('close');
},
...mapActions(["api"])
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,79 @@
<template>
<v-card>
<v-card-title>Production settings</v-card-title>
<v-card-subtitle></v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
label="Nominal line change duration"
hint="Duration of the nominal elapsed time circling between lines, in minutes. If this time is exceeded between one sequence and the next, an entry will be made in the events log"
persistent-hint
suffix="min"
type="number"
v-model.number="nominalLineChangeDuration"
>
</v-text-field>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn
color="primary"
@click="save"
>Save</v-btn>
<v-spacer></v-spacer>
<v-btn
color="warning"
@click="reset"
>Reset</v-btn>
<v-spacer></v-spacer>
<v-btn
color="secondary"
@click="back"
>Back</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
name: "DougalProjectSettingsProduction",
props: [ "value" ],
data () {
return {
nominalLineChangeDuration: null
}
},
watch: {
value (newValue) {
this.reset();
}
},
methods: {
reset () {
for (const key of Object.keys(this.$data)) {
this[key] = this.value[key];
}
},
save () {
this.$emit('input', {...this.$data});
},
back () {
this.$emit('close');
}
},
mounted () {
this.reset();
}
}
</script>

View File

@@ -0,0 +1,117 @@
<template>
<v-card>
<v-card-title v-text="title"></v-card-title>
<v-card-subtitle v-text="subtitle"></v-card-subtitle>
<v-card-text>
<v-form>
<v-text-field
class="mb-5"
label="Regular expression"
v-model="regex"
persistent-hint
hint="Regular expression"
>
</v-text-field>
<fieldset class="pa-3 mb-5">
<legend>Captures</legend>
<v-text-field v-for="(item, index) in captures" :key="index"
v-model="captures[index]"
>
<v-btn slot="append-outer"
fab
x-small text
dark
color="red"
title="Remove"
@click="() => captures.splice(index, 1)"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
</v-text-field>
<v-btn
class="mx-2"
fab dark
x-small text
color="primary"
title="Add capture"
@click="() => captures.push('')"
>
<v-icon dark>mdi-plus</v-icon>
</v-btn>
</fieldset>
<v-text-field
class="mb-5"
label="Flags"
v-model="flags"
persistent-hint
hint="Regular expression modifier flags"
>
</v-text-field>
</v-form>
</v-card-text>
</v-card>
</template>
<style scoped>
.sample {
font-family: mono;
white-space: pre;
}
</style>
<script>
export default {
name: "DougalProjectSettingsRegexPatternCaptures",
props: [ "value", "title", "subtitle" ],
data () {
return {
regex: "",
flags: "",
captures: []
}
},
watch: {
value (newValue) {
this.reset();
},
regex () {
this.save();
},
flags () {
this.save();
},
captures () {
this.save();
}
},
methods: {
reset () {
this.regex = this.value?.regex;
this.flags = this.value?.flags;
this.captures = this.value?.captures ?? [];
},
save () {
this.$emit('input', {regex: this.regex, flags: this.flags, captures: this.captures});
},
},
mounted () {
this.reset();
}
}
</script>