aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src_js/opcut/common.js35
-rw-r--r--src_js/opcut/fs.js1
-rw-r--r--src_js/opcut/future.js45
-rw-r--r--src_js/opcut/grid.js45
-rw-r--r--src_js/opcut/main.js1
-rw-r--r--src_js/opcut/states.js7
-rw-r--r--src_js/opcut/vt.js69
-rw-r--r--src_py/opcut/server.py4
-rw-r--r--src_web/style/main.scss56
9 files changed, 235 insertions, 28 deletions
diff --git a/src_js/opcut/common.js b/src_js/opcut/common.js
index 89088ac..9c5d16d 100644
--- a/src_js/opcut/common.js
+++ b/src_js/opcut/common.js
@@ -3,6 +3,8 @@ import iziToast from 'izitoast';
import r from 'opcut/renderer';
import * as u from 'opcut/util';
+import * as states from 'opcut/states';
+import * as fs from 'opcut/fs';
const calculateUrl = URI.resolve(window.location.href, './calculate');
@@ -41,6 +43,19 @@ export function calculate() {
}
+export function generateOutput(output_type) {
+ const msg = {
+ output_type: output_type,
+ result: r.get('result')
+ };
+ const req = new XMLHttpRequest();
+ req.onload = () => parseGenerateOutputResponse(JSON.parse(req.responseText), output_type);
+ req.open('POST', generateOutputUrl);
+ req.setRequestHeader('Content-Type', 'application/json');
+ req.send(JSON.stringify(msg));
+}
+
+
function validateCalculateRequest(msg) {
if (!Number.isFinite(msg.params.cut_width) || msg.params.cut_width < 0)
throw 'Invalid cut width';
@@ -68,7 +83,25 @@ function validateCalculateRequest(msg) {
function parseCalculateResponse(msg) {
-
+ r.change(u.pipe(
+ u.set('result', msg.result),
+ u.set('selected', states.main.selected)
+ ));
+ if (msg.result) {
+ showNotification('New calculation available', 'success');
+ } else {
+ showNotification('Could not resolve calculation', 'error');
+ }
+}
+
+
+function parseGenerateOutputResponse(msg, output_type) {
+ if (msg.data) {
+ const fileName = 'output.pdf';
+ fs.saveB64Data(msg.data, fileName);
+ } else {
+ showNotification('Error generating output', 'error');
+ };
}
diff --git a/src_js/opcut/fs.js b/src_js/opcut/fs.js
index b1d464e..f96485b 100644
--- a/src_js/opcut/fs.js
+++ b/src_js/opcut/fs.js
@@ -1,6 +1,7 @@
import h from 'hyperscript';
import FileSaver from 'file-saver';
+import * as u from 'opcut/util';
import * as ev from 'opcut/ev';
diff --git a/src_js/opcut/future.js b/src_js/opcut/future.js
new file mode 100644
index 0000000..a435e89
--- /dev/null
+++ b/src_js/opcut/future.js
@@ -0,0 +1,45 @@
+
+export function create() {
+ let data = {
+ done: false,
+ error: false,
+ result: undefined,
+ resolve: null,
+ reject: null
+ };
+ let future = new Promise((resolve, reject) => {
+ data.resolve = resolve;
+ data.reject = reject;
+ if (data.error) {
+ reject(data.result);
+ } else if (data.done) {
+ resolve(data.resolve);
+ }
+ });
+ future.done = () => data.done;
+ future.result = () => {
+ if (!data.done)
+ throw 'Future is not done';
+ if (data.error)
+ throw data.error;
+ return data.result;
+ };
+ future.setResult = result => {
+ if (data.done)
+ throw 'Result already set';
+ data.result = result;
+ data.done = true;
+ if (data.resolve)
+ data.resolve(data.result);
+ };
+ future.setError = error => {
+ if (data.done)
+ throw 'Result already set';
+ data.error = true;
+ data.result = error;
+ data.done = true;
+ if (data.reject)
+ data.reject(error);
+ };
+ return future;
+}
diff --git a/src_js/opcut/grid.js b/src_js/opcut/grid.js
index 4403195..27f9a23 100644
--- a/src_js/opcut/grid.js
+++ b/src_js/opcut/grid.js
@@ -3,6 +3,7 @@ import Papa from 'papaparse';
import r from 'opcut/renderer';
import * as u from 'opcut/util';
import * as ev from 'opcut/ev';
+import * as fs from 'opcut/fs';
export const state = {
@@ -57,7 +58,7 @@ export function tbody(gridPath, columns, validators) {
}
}
const title = (validator ? validator(u.get(column, row), row) : null);
- return ['td', {
+ return ['td' + (typeof column == 'function' ? '' : '.grid-col-' + column), {
class: {
invalid: title
},
@@ -104,10 +105,9 @@ export function tfoot(gridPath, colspan, newItem, csvColumns) {
['button', {
on: {
click: () => {
- const items = importCsv(csvColumns, newItem);
- if (!items)
- return;
- r.change(itemsPath, state => state.concat(items));
+ importCsv(csvColumns, newItem).then(items => {
+ r.change(itemsPath, state => state.concat(items));
+ });
}
}},
['span.fa.fa-download'],
@@ -253,24 +253,25 @@ export function selectColumn(gridPath, column, values) {
function importCsv(csvColumns, newItem) {
- fs.loadText('csv').then(csvData => {
- const result = Papa.parse(csvData, {
- delimiter: ';',
- skipEmptyLines: true,
- header: true
+ return new Promise(resolve => {
+ fs.loadText('csv').then(csvData => {
+ const result = Papa.parse(csvData, {
+ delimiter: ';',
+ skipEmptyLines: true,
+ header: true
+ });
+ const items = [];
+ for (let i of result.data) {
+ if (!Object.keys(i).every(k => u.contains(k, Object.keys(csvColumns))))
+ continue;
+ const item = u.reduce(
+ (acc, [name, column]) => column.toItem(i[name], acc),
+ newItem,
+ u.toPairs(csvColumns));
+ items.push(item);
+ }
+ resolve(items);
});
-
- const items = [];
- for (let i of result.data) {
- if (!Object.keys(i).every(k => u.contains(k, Object.keys(csvColumns))))
- continue;
- const item = u.reduce(
- (acc, [name, column]) => column.toItem(i[name], acc),
- newItem,
- u.toPairs(csvColumns));
- items.push(item);
- }
- return items;
});
}
diff --git a/src_js/opcut/main.js b/src_js/opcut/main.js
index 8d00c56..7014798 100644
--- a/src_js/opcut/main.js
+++ b/src_js/opcut/main.js
@@ -14,3 +14,4 @@ function main() {
ev.on(window, 'load', main);
+window.r = r;
diff --git a/src_js/opcut/states.js b/src_js/opcut/states.js
index 12c3f8a..1326a70 100644
--- a/src_js/opcut/states.js
+++ b/src_js/opcut/states.js
@@ -7,7 +7,12 @@ export const main = {
cut_width: '1',
panels: grid.state,
items: grid.state
- }
+ },
+ result: null,
+ selected: {
+ panel: null,
+ item: null
+ },
};
diff --git a/src_js/opcut/vt.js b/src_js/opcut/vt.js
index f942e4b..e71d5df 100644
--- a/src_js/opcut/vt.js
+++ b/src_js/opcut/vt.js
@@ -9,8 +9,8 @@ import * as validators from 'opcut/validators';
export function main() {
return ['div.window',
leftPanel(),
- ['div.center-panel'],
- ['div.right-panel']
+ centerPanel(),
+ rightPanel()
];
}
@@ -26,6 +26,7 @@ function leftPanel() {
['div.title', 'OPCUT'],
['a', {
props: {
+ title: 'GitHub',
href: 'https://github.com/bozokopic/opcut'
}},
['span.fa.fa-github']
@@ -134,3 +135,67 @@ function leftPanelItems() {
]
];
}
+
+
+function rightPanel() {
+ const result = r.get('result');
+ return ['div.right-panel', (!result ?
+ [] :
+ [
+ ['div.toolbar',
+ ['button', {
+ on: {
+ click: () => common.generateOutput('PDF')
+ }},
+ ['span.fa.fa-file-pdf-o'],
+ ' PDF'
+ ]
+ ],
+ Object.keys(result.params.panels).map(rightPanelPanel)
+ ])
+ ];
+}
+
+
+function rightPanelPanel(panel) {
+ const isSelected = item => u.equals(r.get('selected'), {panel: panel, item: item});
+ return ['div.panel',
+ ['div.panel-name', {
+ class: {
+ selected: isSelected(null)
+ },
+ on: {
+ click: () => r.set('selected', {panel: panel, item: null})
+ }},
+ panel
+ ],
+ u.filter(used => used.panel == panel)(r.get('result', 'used')).map(used =>
+ ['div.item', {
+ class: {
+ selected: isSelected(used.item)
+ },
+ on: {
+ click: () => r.set('selected', {panel: panel, item: used.item})
+ }},
+ ['div.item-name', used.item],
+ (used.rotate ? ['span.item-rotate.fa.fa-refresh'] : []),
+ ['div.item-x',
+ 'X:',
+ String(used.x)
+ ],
+ ['div.item-y',
+ 'Y:',
+ String(used.y)
+ ]
+ ])
+ ];
+}
+
+
+function centerPanel() {
+ return ['div.center-panel',
+ ['svg',
+
+ ]
+ ];
+}
diff --git a/src_py/opcut/server.py b/src_py/opcut/server.py
index c67279f..02fc161 100644
--- a/src_py/opcut/server.py
+++ b/src_py/opcut/server.py
@@ -57,7 +57,7 @@ async def _calculate_handler(executor, request):
result_json_data = common.result_to_json_data(result)
except asyncio.CancelledError:
raise
- except Exception:
+ except Exception as e:
result_json_data = None
return aiohttp.web.json_response({'result': result_json_data})
@@ -73,7 +73,7 @@ async def _generate_output_handler(executor, request):
output_json_data = base64.b64encode(output).decode('utf-8')
except asyncio.CancelledError:
raise
- except Exception:
+ except Exception as e:
output_json_data = None
return aiohttp.web.json_response({'data': output_json_data})
diff --git a/src_web/style/main.scss b/src_web/style/main.scss
index 612c2a7..896df77 100644
--- a/src_web/style/main.scss
+++ b/src_web/style/main.scss
@@ -83,6 +83,14 @@ html, body {
tbody td:last-child {
text-align: center;
}
+
+ .grid-col-width, .grid-col-height {
+ text-align: right;
+
+ input {
+ text-align: right;
+ }
+ }
}
& > *:not(:last-child) {
@@ -104,9 +112,57 @@ html, body {
.center-panel {
flex-grow: 1;
+ overflow: auto;
}
.right-panel {
+ @include shadow-4dp();
+ width: 200px;
+ display: flex;
+ flex-direction: column;
+ background-color: $color-grey-100;
+ overflow: auto;
+ .toolbar {
+ display: flex;
+ justify-content: center;
+ margin: 10px;
+ }
+
+ .panel {
+ margin: 15px 0px;
+
+ & > *:hover {
+ background-color: $color-grey-400;
+ cursor: pointer;
+ }
+ }
+
+ .panel-name {
+ padding: 3px 10px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-weight: 600;
+ color: $color-grey-800;
+ }
+
+ .item {
+ padding: 3px 10px 3px 20px;
+ display: flex;
+
+ .item-name {
+ flex-grow: 1;
+ }
+
+ .item-rotate, .item-x, .item-y {
+ margin-left: 3px;
+ font-weight: 600;
+ color: $color-grey-800;
+ }
+ }
+
+ .selected {
+ background-color: $color-grey-400;
+ }
}