mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 09:07:09 +00:00
This introduces a number of changes, most notably an easier way to specify fixed width formats and support for configuring multiple import options (actual SPSv1, SPSv2.1, P1/90, CSV, …) Note that only the configuration GUI is done, support for actually importing those formats has not been implemented as of this commit.
302 lines
8.1 KiB
Vue
302 lines
8.1 KiB
Vue
<template>
|
||
<v-card flat elevation="0">
|
||
<v-card-title v-if="title">{{ title }}</v-card-title>
|
||
<v-card-subtitle v-if="subtitle">{{ subtitle }}</v-card-subtitle>
|
||
<v-card-text>
|
||
|
||
<v-tabs v-model="viewTab">
|
||
<v-tab>Text</v-tab>
|
||
<v-tab>Parsed</v-tab>
|
||
</v-tabs>
|
||
|
||
<v-tabs-items v-model="viewTab">
|
||
<v-tab-item>
|
||
<v-simple-table dense class="text">
|
||
<template v-slot:default>
|
||
<colgroup v-if="showLineNumbers">
|
||
<col class="line_no"/>
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th class="line_no">
|
||
<v-simple-checkbox
|
||
v-ripple
|
||
off-icon="mdi-format-list-numbered"
|
||
title="Show line numbers"
|
||
v-model="showLineNumbers"
|
||
>
|
||
</v-simple-checkbox>
|
||
</th>
|
||
<th v-for="(header, idx) in headers" :key="idx"
|
||
:style="`color:${header.colour};`"
|
||
>
|
||
{{ header.text }}
|
||
</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="(row, ridx) in rows" :key="ridx">
|
||
<td class="line_no"">
|
||
<small v-if="showLineNumbers">
|
||
{{ ridx + (typeof numberedLines == "number" ? numberedLines : 0)+1 }}
|
||
</small>
|
||
</td>
|
||
<td v-for="(cell, cidx) in row" :key="cidx"
|
||
:style="`background-color:${cell.colour};`"
|
||
>
|
||
{{ cell.text }}
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</template>
|
||
</v-simple-table>
|
||
</v-tab-item>
|
||
|
||
<v-tab-item>
|
||
<!-- Parsed view -->
|
||
<v-simple-table dense class="parsed">
|
||
<template v-slot:default>
|
||
<thead>
|
||
<tr>
|
||
<th
|
||
title="The line along which the vessel will nominally sail"
|
||
>Sail line</th>
|
||
<th
|
||
title="Whether the line will be acquired in the incrementing or decrementing shot points direction"
|
||
>Direction</th>
|
||
<th
|
||
title="Whether the line is planned to be acquired. Some lines may be in the preplot but not intended to be shot in a particular campaign"
|
||
>Acquire?</th>
|
||
<th
|
||
title="The source lines that will be shot from this vessel line. Typically there is one source line per source array."
|
||
>Source lines</th>
|
||
<th
|
||
title="Any general remarks concerning this sail line (supports Markdown)"
|
||
>Remarks</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="(line, line_no) in saillines" :key="line_no">
|
||
<td>{{ line_no }}</td>
|
||
<td v-if="line.incr" title="Incrementing">▲</td>
|
||
<td v-else title="Decrementing">▼</td>
|
||
<td v-if="line.ntba" title="Not to be acquired" class="ko">✘</td>
|
||
<td v-else title="Line acquisition planned" class="ok">✔</td>
|
||
<td v-html="line.source_line.join('<br/>')"></td>
|
||
<td v-if="line['meta.colour']"
|
||
:style="`background-color:${line['meta.colour']};`"
|
||
v-html="$options.filters.markdown(line.remarks)"></td>
|
||
<td v-else
|
||
v-html="$options.filters.markdown(line.remarks)"></td>
|
||
</tr>
|
||
</tbody>
|
||
</template>
|
||
</v-simple-table>
|
||
</v-tab-item>
|
||
</v-tabs-items>
|
||
|
||
</v-card-text>
|
||
<v-card-actions>
|
||
</v-card-actions>
|
||
</v-card>
|
||
</template>
|
||
|
||
<style scoped>
|
||
/*.v-data-table table tbody tr td*/
|
||
.text th {
|
||
border: 1px solid hsl(0, 0%, 33.3%);
|
||
}
|
||
|
||
.text td {
|
||
border-inline: 1px solid hsl(0, 0%, 33.3%);
|
||
}
|
||
|
||
.parsed td {
|
||
vertical-align: top;
|
||
}
|
||
|
||
.line_no {
|
||
text-align: right;
|
||
width: 4ex;
|
||
border: none !important;
|
||
}
|
||
|
||
.ok {
|
||
color: green;
|
||
}
|
||
|
||
.ko {
|
||
color: red;
|
||
}
|
||
</style>
|
||
|
||
<script>
|
||
import { parse } from 'csv-parse/sync'
|
||
import { getHSLColourFor } from '@/lib/hsl'
|
||
import truncateText from '@/lib/truncate-text'
|
||
|
||
export default {
|
||
name: "DougalSaillinesStringDecoder",
|
||
|
||
components: {
|
||
},
|
||
|
||
props: {
|
||
text: String,
|
||
//fields: Object,
|
||
//delimiter: String,
|
||
headerRow: { type: [ Boolean, Number ], default: false},
|
||
numberedLines: [ Boolean, Number ],
|
||
maxHeight: String,
|
||
editableFieldList: { type: Boolean, default: true },
|
||
readonly: Boolean,
|
||
title: String,
|
||
subtitle: String
|
||
},
|
||
|
||
data () {
|
||
return {
|
||
delimiter: ",",
|
||
showLineNumbers: null,
|
||
text_: "",
|
||
viewTab: null
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
|
||
cells () {
|
||
return parse(this.text_, {delimiter: this.delimiter, trim: true});
|
||
},
|
||
|
||
headers () {
|
||
return this.cells[0]?.map(cell => ({
|
||
text: cell,
|
||
colour: this.getHSLColourFor(cell),
|
||
backgroundColour: this.getHSLColourFor(cell, 0.2),
|
||
})) ?? [];
|
||
},
|
||
|
||
rows () {
|
||
return [...this.cells].slice(1).map(r =>
|
||
r.map( (c, ι) => ({
|
||
text: truncateText(c),
|
||
colour: this.headers[ι]?.backgroundColour
|
||
})));
|
||
},
|
||
|
||
/*
|
||
* A saillines object looks like:
|
||
*
|
||
* {
|
||
* [sail_line]: {
|
||
* incr: true, // or false
|
||
* ntba: true, // or false
|
||
* remarks: "",
|
||
* source_line: [ 1000, 1001, …],
|
||
* "meta.colour": ""
|
||
* },
|
||
* …
|
||
* }
|
||
*/
|
||
saillines () {
|
||
// Return an array of the column numbers
|
||
// corresponding to `key`.
|
||
// This file accepts duplicate column numbers,
|
||
// notably for `source_line`.
|
||
const key_indices = (key) =>
|
||
this.headers.reduce( (acc, cur, ι) => {
|
||
if (cur.text == key) {
|
||
acc.push(ι)
|
||
}
|
||
return acc;
|
||
}, []);
|
||
|
||
// Properties of the sailline object
|
||
const keys = [ "incr", "ntba", "remarks", "source_line", "meta.colour" ];
|
||
|
||
function to_bool (v, missing=false) {
|
||
return (v === undefined || v === null)
|
||
? missing // Missing value meaning
|
||
: /^t(rue)|^[1-9-]+$/i.test(String(v).trim())
|
||
}
|
||
|
||
// To transform the input text into the required format for each field
|
||
const transformer = (key) => {
|
||
const transformers = {
|
||
incr: (v) => to_bool(v, true),
|
||
ntba: (v) => to_bool(v, false),
|
||
remarks: (v) => (v === undefined || v === null) ? "" : String,
|
||
source_line: Number,
|
||
};
|
||
return transformers[key] ?? String;
|
||
};
|
||
|
||
// This is the saillines object
|
||
const lines = {};
|
||
|
||
// The column numbers for each property
|
||
const columns = keys.map( k => [ k, key_indices(k) ] );
|
||
|
||
// The column number for the sail_line property, which
|
||
// we use as a key.
|
||
const sail_line_idx = key_indices("sail_line")[0];
|
||
|
||
// Transform each line in the input file into a
|
||
// sailline object (just for display purposes,
|
||
// this is not exactly how the server will do it).
|
||
for (const row of this.rows) {
|
||
const sail_line = row[sail_line_idx]?.text;
|
||
const values = columns.map(i => [
|
||
i[0],
|
||
i[0] == "source_line"
|
||
? i[1].map(idx => transformer(i[0])(row[idx]?.text))
|
||
: transformer(i[0])(row[i[1][0]]?.text)
|
||
]);
|
||
|
||
lines[sail_line] = Object.fromEntries(values);
|
||
}
|
||
|
||
return lines;
|
||
}
|
||
|
||
},
|
||
|
||
watch: {
|
||
|
||
text () {
|
||
if (this.text != this.text_) {
|
||
this.reset();
|
||
}
|
||
},
|
||
|
||
numberedLines (cur, prev) {
|
||
if (cur != prev) {
|
||
this.showLineNumbers = typeof cur == "number" || cur;
|
||
}
|
||
}
|
||
|
||
},
|
||
|
||
methods: {
|
||
|
||
|
||
getHSLColourFor: getHSLColourFor.bind(this),
|
||
|
||
numberLine (number, line) {
|
||
return `<span class="line-number">${number}</span>${line}`;
|
||
},
|
||
|
||
reset () {
|
||
this.text_ = this.text.replaceAll("\r", "");
|
||
}
|
||
|
||
},
|
||
|
||
mounted () {
|
||
this.reset();
|
||
}
|
||
|
||
}
|
||
</script>
|