From 8e331b49890ed906fa06b9977dc8980f32498d67 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sun, 17 Feb 2019 19:30:10 +0100 Subject: [PATCH 01/23] basic html export --- backend/backend/api/entries.py | 12 +++++++++++- backend/backend/export.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/backend/backend/api/entries.py b/backend/backend/api/entries.py index 712cecf..6259f91 100644 --- a/backend/backend/api/entries.py +++ b/backend/backend/api/entries.py @@ -8,7 +8,7 @@ from ..db import Entry, Logbook, EntryLock from ..attachments import handle_img_tags -from ..export import export_entries_as_pdf +from ..export import export_entries_as_pdf, export_entries_as_html from ..actions import new_entry, edit_entry from . import fields, send_signal @@ -196,6 +196,16 @@ def get(self, args, logbook_id=None): as_attachment=True, attachment_filename=("{logbook.name}.pdf" .format(logbook=logbook))) + elif args.get("download") == "html": + # return a PDF version + # TODO: not sure if this belongs in the API + html = export_entries_as_html(logbook, entries) + if html is None: + abort(400, message="Could not create HTML!") + return send_file(html, mimetype="text/html", + as_attachment=True, + attachment_filename=("{logbook.name}.html" + .format(logbook=logbook))) return marshal(dict(logbook=logbook, entries=list(entries)), fields.entries) diff --git a/backend/backend/export.py b/backend/backend/export.py index 2ff416a..35a65bf 100644 --- a/backend/backend/export.py +++ b/backend/backend/export.py @@ -52,3 +52,31 @@ def export_entries_as_pdf(logbook, entries): # https://github.com/wkhtmltopdf/wkhtmltopdf/issues/2051 pass return f.name + +def export_entries_as_html(logbook, entries): + + """ + Super basic "proof-of-concept" html export + No proper formatting, and does not embed images. + """ + + entries_html = [ + """ +

Created at: {created_at}

+

Title: {title}

+

Authors: {authors}

+

{content}

+
+ """.format(title=entry.title or "(No title)", + authors=", ".join(a["name"] for a in entry.authors), + created_at=entry.created_at, + content=entry.content or "---") + for entry in entries + ] + with NamedTemporaryFile(prefix=logbook.name, + suffix=".html", + delete=False) as f: + f.write('

{}


'.format(logbook.name).encode('utf8')) + for entry_html in entries_html: + f.write(entry_html.encode('utf8')) + return f.name \ No newline at end of file From d632eae8b59c1078313396edd58c3c920c80f73e Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sun, 17 Feb 2019 19:50:24 +0100 Subject: [PATCH 02/23] add link to export logbook to html --- frontend/src/logbook.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/frontend/src/logbook.js b/frontend/src/logbook.js index e6cc261..a24df50 100644 --- a/frontend/src/logbook.js +++ b/frontend/src/logbook.js @@ -264,6 +264,17 @@ class Logbook extends React.Component { Configure {" "} |  + + Export HTML + {" "} + |  ) : null} Date: Sun, 17 Feb 2019 21:09:01 +0100 Subject: [PATCH 03/23] use slugify for filenames and improve temp-file handling --- backend/backend/api/entries.py | 9 ++++++--- backend/backend/export.py | 19 +++++++++++-------- backend/requirements.txt | 1 + 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/backend/backend/api/entries.py b/backend/backend/api/entries.py index 6259f91..a0eb46b 100644 --- a/backend/backend/api/entries.py +++ b/backend/backend/api/entries.py @@ -1,4 +1,5 @@ import logging +from slugify import slugify from flask import request, send_file from flask_restful import Resource, marshal, marshal_with, abort @@ -202,10 +203,12 @@ def get(self, args, logbook_id=None): html = export_entries_as_html(logbook, entries) if html is None: abort(400, message="Could not create HTML!") - return send_file(html, mimetype="text/html", + ret = send_file(html.name, mimetype="text/html", as_attachment=True, - attachment_filename=("{logbook.name}.html" - .format(logbook=logbook))) + attachment_filename=(slugify("{logbook.name}.html" + .format(logbook=logbook)))) + html.close() + return ret return marshal(dict(logbook=logbook, entries=list(entries)), fields.entries) diff --git a/backend/backend/export.py b/backend/backend/export.py index 35a65bf..f70d206 100644 --- a/backend/backend/export.py +++ b/backend/backend/export.py @@ -1,4 +1,5 @@ from tempfile import NamedTemporaryFile +from slugify import slugify try: import pdfkit @@ -62,10 +63,10 @@ def export_entries_as_html(logbook, entries): entries_html = [ """ -

Created at: {created_at}

-

Title: {title}

-

Authors: {authors}

-

{content}

+
Created at: {created_at}
+
Title: {title}
+
Authors: {authors}
+
{content}

""".format(title=entry.title or "(No title)", authors=", ".join(a["name"] for a in entry.authors), @@ -73,10 +74,12 @@ def export_entries_as_html(logbook, entries): content=entry.content or "---") for entry in entries ] - with NamedTemporaryFile(prefix=logbook.name, + print(entries_html) + with NamedTemporaryFile(prefix=slugify(logbook.name), suffix=".html", - delete=False) as f: - f.write('

{}


'.format(logbook.name).encode('utf8')) + delete=True) as f: + f.write('

{}

'.format(logbook.name).encode('utf8')) + f.write('
{}

'.format(logbook.description).encode('utf8')) for entry_html in entries_html: f.write(entry_html.encode('utf8')) - return f.name \ No newline at end of file + return f \ No newline at end of file diff --git a/backend/requirements.txt b/backend/requirements.txt index f59ed98..07f8d2b 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -14,6 +14,7 @@ peewee==2.10.2 Pillow==5.0.0 pyldap==2.4.45 python-dateutil==2.6.1 +python-slugify==2.0.1 pytz==2017.3 six==1.11.0 uWSGI==2.0.15 From b1cfe06fb19aa9d65ae0ccb8c5d3115560839af3 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Sun, 17 Feb 2019 21:19:05 +0100 Subject: [PATCH 04/23] change file closing --- backend/backend/api/entries.py | 4 +--- backend/backend/export.py | 5 +++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/backend/api/entries.py b/backend/backend/api/entries.py index a0eb46b..abc383a 100644 --- a/backend/backend/api/entries.py +++ b/backend/backend/api/entries.py @@ -203,12 +203,10 @@ def get(self, args, logbook_id=None): html = export_entries_as_html(logbook, entries) if html is None: abort(400, message="Could not create HTML!") - ret = send_file(html.name, mimetype="text/html", + return send_file(html, mimetype="text/html", as_attachment=True, attachment_filename=(slugify("{logbook.name}.html" .format(logbook=logbook)))) - html.close() - return ret return marshal(dict(logbook=logbook, entries=list(entries)), fields.entries) diff --git a/backend/backend/export.py b/backend/backend/export.py index f70d206..4401ee0 100644 --- a/backend/backend/export.py +++ b/backend/backend/export.py @@ -77,9 +77,10 @@ def export_entries_as_html(logbook, entries): print(entries_html) with NamedTemporaryFile(prefix=slugify(logbook.name), suffix=".html", - delete=True) as f: + delete=False) as f: f.write('

{}

'.format(logbook.name).encode('utf8')) f.write('
{}

'.format(logbook.description).encode('utf8')) for entry_html in entries_html: f.write(entry_html.encode('utf8')) - return f \ No newline at end of file + f.close() + return f.name \ No newline at end of file From ccad908657652459563835051c5a729d5e15725e Mon Sep 17 00:00:00 2001 From: Fredrik Bolmsten Date: Tue, 19 Mar 2019 13:45:42 +0100 Subject: [PATCH 05/23] Add buttons for hiding logbookstree and logbook --- frontend/src/app.js | 48 +++++++++++++++++++++++++++++++------ frontend/src/entry.js | 12 ++++++++++ frontend/src/logbook.css | 4 ++++ frontend/src/logbook.js | 11 ++++++++- frontend/src/logbooktree.js | 8 +++++++ 5 files changed, 75 insertions(+), 8 deletions(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index 93c7223..d8c19a2 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -77,14 +77,47 @@ class NoEntry extends React.Component { ); } } +class Elogy extends React.Component { -const Elogy = () => ( + constructor() { + super(); + this.state = { + hideLogbookTree: false, + hideLogbook: false + }; + this._hideLogbookTree = this._hideLogbookTree.bind(this); + this._hideLogbook = this._hideLogbook.bind(this); + } + + componentDidMount() { + eventbus.subscribe("logbooktree.hide", this._hideLogbookTree); + eventbus.subscribe("logbook.hide", this._hideLogbook); + } + + componentWillUnmount() { + eventbus.unsubscribe("logbooktree.hide", this._hideLogbookTree); + eventbus.unsubscribe("logbook.hide", this._hideLogbook); + } + + _hideLogbookTree(hide) { + this.setState({hideLogbookTree: hide}); + } + + _hideLogbook(hide) { + console.log("called"); + this.setState({hideLogbook: hide}); + } + + render() { + const EntryWithEventbus = withProps(Entry, { "eventbus": eventbus, "hideLogbookTree": this.state.hideLogbookTree, "hideLogbook": this.state.hideLogbook }); + + return ( /* Set up a browser router that will render the correct component in the right places, all depending on the current URL. */
-
+ {!this.state.hideLogbookTree ?
( /> -
+
: null} -
+ {!this.state.hideLogbook ?
( /> -
+
: null}
@@ -128,7 +161,7 @@ const Elogy = () => ( (
); - +} +} export default Elogy; diff --git a/frontend/src/entry.js b/frontend/src/entry.js index 4b99858..7d7bdea 100644 --- a/frontend/src/entry.js +++ b/frontend/src/entry.js @@ -253,6 +253,18 @@ class Entry extends React.Component {
{this.state.logbook ? ( + {this.props.hideLogbookTree && + + this.props.eventbus.publish("logbooktree.hide", false)}>Show logbooks +  |  + + } + {this.props.hideLogbook && + + this.props.eventbus.publish("logbook.hide", false)}>Show logbook +  |  + + } {this.state.follows ? ( {logbook.id === 0 ? "[All logbooks]" : logbook.name} - +
{logbook.id ? ( diff --git a/frontend/src/logbooktree.js b/frontend/src/logbooktree.js index ab2d696..6d5eb62 100644 --- a/frontend/src/logbooktree.js +++ b/frontend/src/logbooktree.js @@ -106,6 +106,10 @@ class LogbookTree extends React.Component { this.props.eventbus.unsubscribe("logbook.reload", this._reload); } + hide(){ + this.props.eventbus.publish("logbooktree.hide", true); + } + reload() { console.log("reload logbook tree"); this.fetch(this.props.location.search); @@ -148,6 +152,10 @@ class LogbookTree extends React.Component {
+ + this.hide()}/> + +   {logbookId !== this.state.id ? ( Date: Tue, 19 Mar 2019 13:46:28 +0100 Subject: [PATCH 06/23] remove log --- frontend/src/app.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index d8c19a2..648193b 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -104,7 +104,6 @@ class Elogy extends React.Component { } _hideLogbook(hide) { - console.log("called"); this.setState({hideLogbook: hide}); } From d683ec4ad8b9463a51e5c6e6427db391885ffd7f Mon Sep 17 00:00:00 2001 From: Fredrik Bolmsten Date: Tue, 19 Mar 2019 15:47:19 +0100 Subject: [PATCH 07/23] Added button to noentry for showing logbooktree and logbook --- frontend/src/app.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index 648193b..a90cf49 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -58,8 +58,22 @@ class NoEntry extends React.Component { console.log(this.props.match.location); return (
- Select an entry to read it - {logbookId ? ( +
+ {this.props.hideLogbookTree && + + this.props.eventbus.publish("logbooktree.hide", false)}>Show logbooks + + + } + {this.props.hideLogbookTree && this.props.hideLogbook &&  |  } + {this.props.hideLogbook && + + this.props.eventbus.publish("logbook.hide", false)}>Show logbook + + } +
+ {!this.props.hideLogbook && Select an entry to read it } + {logbookId && !this.props.hideLogbook ? (
{" "} or{" "} @@ -72,6 +86,7 @@ class NoEntry extends React.Component { click here to make a new entry.
+ ) : null}
); @@ -109,6 +124,7 @@ class Elogy extends React.Component { render() { const EntryWithEventbus = withProps(Entry, { "eventbus": eventbus, "hideLogbookTree": this.state.hideLogbookTree, "hideLogbook": this.state.hideLogbook }); + const NoEntryWithEventbus = withProps(NoEntry, { "eventbus": eventbus, "hideLogbookTree": this.state.hideLogbookTree, "hideLogbook": this.state.hideLogbook }); return ( /* Set up a browser router that will render the correct component @@ -172,7 +188,7 @@ class Elogy extends React.Component { component={LogbookEditorWithEventbus} /> - +
From ab6b7b41a986677d06f0f3415b286999d804ba30 Mon Sep 17 00:00:00 2001 From: Fredrik Bolmsten Date: Tue, 19 Mar 2019 15:47:45 +0100 Subject: [PATCH 08/23] fix indent and clean uo --- frontend/src/app.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index a90cf49..d165a01 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -55,25 +55,26 @@ class NoEntry extends React.Component { render() { const logbookId = parseInt(this.props.match.params.logbookId); + const {hideLogbook, hideLogbookTree, eventbus} = this.props; console.log(this.props.match.location); return (
- {this.props.hideLogbookTree && - - this.props.eventbus.publish("logbooktree.hide", false)}>Show logbooks - - - } - {this.props.hideLogbookTree && this.props.hideLogbook &&  |  } - {this.props.hideLogbook && - - this.props.eventbus.publish("logbook.hide", false)}>Show logbook - - } + {hideLogbookTree && + + eventbus.publish("logbooktree.hide", false)}>Show logbooks + + + } + {hideLogbookTree && hideLogbook &&  |  } + {hideLogbook && + + eventbus.publish("logbook.hide", false)}>Show logbook + + }
- {!this.props.hideLogbook && Select an entry to read it } - {logbookId && !this.props.hideLogbook ? ( + {!hideLogbook && Select an entry to read it } + {logbookId && !hideLogbook ? (
{" "} or{" "} From 1ac7018801212862251f963c5286943b30ce4aae Mon Sep 17 00:00:00 2001 From: Fredrik Bolmsten Date: Fri, 22 Mar 2019 09:26:51 +0100 Subject: [PATCH 09/23] remove old design --- frontend/src/app.js | 21 +++++++++++++++++++-- frontend/src/entry.js | 12 ------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index d165a01..9eba390 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -93,6 +93,23 @@ class NoEntry extends React.Component { ); } } + +class HiddenColumn extends React.Component { + + render() { + return ( +
+ + this.props.show()}/> + +

{this.props.text}

+
+ ); + } +} + + + class Elogy extends React.Component { constructor() { @@ -148,7 +165,7 @@ class Elogy extends React.Component { /> -
: null} +
: } {!this.state.hideLogbook ?
@@ -162,7 +179,7 @@ class Elogy extends React.Component { /> -
: null} +
: }
diff --git a/frontend/src/entry.js b/frontend/src/entry.js index 7d7bdea..4b99858 100644 --- a/frontend/src/entry.js +++ b/frontend/src/entry.js @@ -253,18 +253,6 @@ class Entry extends React.Component {
{this.state.logbook ? ( - {this.props.hideLogbookTree && - - this.props.eventbus.publish("logbooktree.hide", false)}>Show logbooks -  |  - - } - {this.props.hideLogbook && - - this.props.eventbus.publish("logbook.hide", false)}>Show logbook -  |  - - } {this.state.follows ? ( Date: Fri, 22 Mar 2019 09:27:06 +0100 Subject: [PATCH 10/23] css for vertical text --- frontend/src/app.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/frontend/src/app.css b/frontend/src/app.css index 5e498f8..7a008d7 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -105,4 +105,17 @@ a { #entry .timestamp { display: block; } +} + +.vertical-text { + writing-mode: tb-rl; + margin: 0px; +} + +.showColumn{ + margin: 5px; +} +.hiddenColumn{ + background: #eee; + border-left: 1px solid #bbb; } \ No newline at end of file From d77649880052ff21ddc7354b9fae506283845f0e Mon Sep 17 00:00:00 2001 From: Fredrik Bolmsten Date: Mon, 25 Mar 2019 15:36:23 +0100 Subject: [PATCH 11/23] remove legacy code from old design --- frontend/src/app.js | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index 9eba390..55e45e4 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -59,22 +59,8 @@ class NoEntry extends React.Component { console.log(this.props.match.location); return (
-
- {hideLogbookTree && - - eventbus.publish("logbooktree.hide", false)}>Show logbooks - - - } - {hideLogbookTree && hideLogbook &&  |  } - {hideLogbook && - - eventbus.publish("logbook.hide", false)}>Show logbook - - } -
- {!hideLogbook && Select an entry to read it } - {logbookId && !hideLogbook ? ( + Select an entry to read it + {logbookId ? (
{" "} or{" "} @@ -142,7 +128,6 @@ class Elogy extends React.Component { render() { const EntryWithEventbus = withProps(Entry, { "eventbus": eventbus, "hideLogbookTree": this.state.hideLogbookTree, "hideLogbook": this.state.hideLogbook }); - const NoEntryWithEventbus = withProps(NoEntry, { "eventbus": eventbus, "hideLogbookTree": this.state.hideLogbookTree, "hideLogbook": this.state.hideLogbook }); return ( /* Set up a browser router that will render the correct component @@ -206,7 +191,7 @@ class Elogy extends React.Component { component={LogbookEditorWithEventbus} /> - +
From 631b3f1e6d6f1b1dcc33bd8eb115668687aea9c6 Mon Sep 17 00:00:00 2001 From: Fredrik Bolmsten Date: Mon, 25 Mar 2019 15:42:57 +0100 Subject: [PATCH 12/23] remove legacy --- frontend/src/app.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index 55e45e4..14f9ccf 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -55,11 +55,10 @@ class NoEntry extends React.Component { render() { const logbookId = parseInt(this.props.match.params.logbookId); - const {hideLogbook, hideLogbookTree, eventbus} = this.props; console.log(this.props.match.location); return (
- Select an entry to read it + Select an entry to read it {logbookId ? (
{" "} @@ -73,7 +72,6 @@ class NoEntry extends React.Component { click here to make a new entry.
- ) : null}
); From cb6c8e1215a40687f8d45be90e3f6bcf520e9b62 Mon Sep 17 00:00:00 2001 From: Fredrik Bolmsten Date: Mon, 25 Mar 2019 15:43:10 +0100 Subject: [PATCH 13/23] legacy code --- frontend/src/app.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/app.js b/frontend/src/app.js index 14f9ccf..597c610 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -125,7 +125,6 @@ class Elogy extends React.Component { } render() { - const EntryWithEventbus = withProps(Entry, { "eventbus": eventbus, "hideLogbookTree": this.state.hideLogbookTree, "hideLogbook": this.state.hideLogbook }); return ( /* Set up a browser router that will render the correct component @@ -177,7 +176,7 @@ class Elogy extends React.Component { Date: Mon, 25 Mar 2019 15:44:54 +0100 Subject: [PATCH 14/23] fix css for border --- frontend/src/app.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app.css b/frontend/src/app.css index 7a008d7..58e4649 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -117,5 +117,5 @@ a { } .hiddenColumn{ background: #eee; - border-left: 1px solid #bbb; + border-right: 1px solid #bbb; } \ No newline at end of file From 4cfaf9db3d28b2753c33188f39b30645414887b4 Mon Sep 17 00:00:00 2001 From: Jonas Rosenqvist Date: Fri, 24 May 2019 14:35:04 +0200 Subject: [PATCH 15/23] filter out all descendants from select options in logbookselector --- frontend/src/logbookeditor.js | 6 +++--- frontend/src/logbookselector.js | 14 ++++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/frontend/src/logbookeditor.js b/frontend/src/logbookeditor.js index 815f4ce..0e91db3 100644 --- a/frontend/src/logbookeditor.js +++ b/frontend/src/logbookeditor.js @@ -483,7 +483,6 @@ class LogbookEditorEdit extends LogbookEditorBase { if (!this.state.id) return
Loading...
; - return (
@@ -491,8 +490,9 @@ class LogbookEditorEdit extends LogbookEditorBase {
Editing logbook "{this.state.logbook.name}" in
diff --git a/frontend/src/logbookselector.js b/frontend/src/logbookselector.js index 7e1d0c6..7e6116a 100644 --- a/frontend/src/logbookselector.js +++ b/frontend/src/logbookselector.js @@ -1,6 +1,5 @@ import React from "react"; - function flattenLogbook (logbook, ancestors) { // return a flat array of all the logbooks, along with their ancestors if (!logbook) @@ -14,7 +13,6 @@ function flattenLogbook (logbook, ancestors) { ); } - // build a nice path string out of the ancestors to the logbook const LogbookOption = ({ logbook, current, ancestors }) => { const logbookPath = (ancestors.join(" / ") @@ -28,7 +26,6 @@ const LogbookOption = ({ logbook, current, ancestors }) => { ); } - export class LogbookSelector extends React.Component { constructor () { @@ -52,19 +49,20 @@ export class LogbookSelector extends React.Component { onChange (event) { this.props.onLogbookChange(event.target.value); } - + render () { const options = flattenLogbook(this.state.logbook) - .filter(([logbook, _]) => logbook.id !== this.props.excludeId) + .filter(([logbook, ancestors]) => !ancestors.includes(this.props.currentName) && logbook.id !== this.props.currentId) .map(([logbook, ancestors]) => ( )); return ( - ); From dcd3829b7fb12feb71dac5403ca2d7685df2fb5b Mon Sep 17 00:00:00 2001 From: Jonas Rosenqvist Date: Tue, 28 May 2019 09:35:58 +0200 Subject: [PATCH 16/23] gitlab ci --- .gitlab-ci.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..e69de29 From a38433a086eef0c9dd880e9ee2fd6a14054018ae Mon Sep 17 00:00:00 2001 From: Jonas Rosenqvist Date: Tue, 28 May 2019 07:39:34 +0000 Subject: [PATCH 17/23] Update .gitlab-ci.yml --- .gitlab-ci.yml | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e69de29..1fc4dae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -0,0 +1,41 @@ +before_script: + - docker info + +build_backend_test_image: + stage: build + script: + - docker build ./backend/ -t docker.maxiv.lu.se/elogy_backend-test + - docker push docker.maxiv.lu.se/elogy_backend-test + only: + - master + +build_frontend_test_image: + stage: build + script: + - docker build ./frontend/ -t docker.maxiv.lu.se/elogy_frontend-test + - docker push docker.maxiv.lu.se/elogy_frontend-test + only: + - master + +build_backend_image: + stage: build + script: + - docker build ./backend/ -t docker.maxiv.lu.se/elogy_backend + - docker push docker.maxiv.lu.se/elogy_backend + only: + - master + +build_frontend_image: + stage: build + script: + - docker build ./frontend/ -t docker.maxiv.lu.se/elogy_frontend + - docker push docker.maxiv.lu.se/elogy_frontend + only: + - master + +deploy_test_image: + stage: deploy + script: + - 'curl -H "Authorization: Bearer $AWX_TOKEN" -XPOST https://ansible.maxiv.lu.se/api/v2/job_templates/22/launch/' + only: + - master From c1a6c6aa321c764118c1d0f528bd1e0a1bf7f62d Mon Sep 17 00:00:00 2001 From: Jonas Rosenqvist Date: Tue, 28 May 2019 11:48:34 +0000 Subject: [PATCH 18/23] Update .gitlab-ci.yml --- .gitlab-ci.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1fc4dae..f958b30 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -17,22 +17,6 @@ build_frontend_test_image: only: - master -build_backend_image: - stage: build - script: - - docker build ./backend/ -t docker.maxiv.lu.se/elogy_backend - - docker push docker.maxiv.lu.se/elogy_backend - only: - - master - -build_frontend_image: - stage: build - script: - - docker build ./frontend/ -t docker.maxiv.lu.se/elogy_frontend - - docker push docker.maxiv.lu.se/elogy_frontend - only: - - master - deploy_test_image: stage: deploy script: From 073453f9e0e1a934eb298283530ea91578381a92 Mon Sep 17 00:00:00 2001 From: Hannes Petri Date: Wed, 12 Jun 2019 14:13:47 +0200 Subject: [PATCH 19/23] Improved logbook editor component; disable editing of names of existing attributes; improved behaviour related to attribute names --- frontend/src/logbookeditor.js | 131 +++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 57 deletions(-) diff --git a/frontend/src/logbookeditor.js b/frontend/src/logbookeditor.js index 0e91db3..cfc05b8 100644 --- a/frontend/src/logbookeditor.js +++ b/frontend/src/logbookeditor.js @@ -10,34 +10,26 @@ import "./logbookeditor.css"; // Editor for a single logbook attribute class LogbookAttributeEditor extends React.PureComponent { - constructor(props) { - super(props); - this.state = { - name: props.name, - type: props.type || "text", - options: props.options, - required: props.required - }; - } - onChangeName(event) { - this.setState({ name: event.target.value }); + this.triggerOnChange({ name: event.target.value }); } onChangeType(event) { - this.setState({ type: event.target.value }); + this.triggerOnChange({ type: event.target.value }); } onChangeOptions(event) { - this.setState({ options: event.target.value.split("\n") }); + this.triggerOnChange({ options: event.target.value.split("\n") }); } onChangeRequired(event) { - this.setState({ required: event.target.checked }); + this.triggerOnChange({ required: event.target.checked }); } - onBlur() { - this.props.onChange(this.props.index, this.state); + triggerOnChange(changes) { + const { name, type, options, required } = this.props; + const state = { name, type, options, required, ...changes }; + this.props.onChange(this.props.index, state); } render() { @@ -47,9 +39,9 @@ class LogbookAttributeEditor extends React.PureComponent {
@@ -123,35 +113,43 @@ class LogbookEditorBase extends React.Component { this.setState({ description: event.target.value }); } - getAttributes(logbook) { - return this.state.attributes.map((attr, i) => ( -
- - {i} - - - - - - -
- )); + getAttributes() { + const { logbook, attributes } = this.state; + + return attributes.map((attr, i) => { + const existingAttribute = + logbook && logbook.attributes.some(({ name }) => name === attr.name); + + return ( +
+ + {i} + + + + + + +
+ ); + }); } findAttribute(name) { @@ -173,13 +171,24 @@ class LogbookEditorBase extends React.Component { } insertAttribute(index, event) { + const existingNames = this.state.attributes.map(({ name }) => name); + const nameBase = "New attribute"; + let attributeName = nameBase; + let counter = 1; + + while (existingNames.includes(attributeName)) { + attributeName = `${nameBase} (${counter})`; + counter++; + } + event.preventDefault(); const newAttribute = { type: "text", - name: "New attribute", + name: attributeName, options: [], required: false }; + this.setState( update(this.state, { attributes: { $splice: [[index, 0, newAttribute]] } @@ -550,13 +559,21 @@ class LogbookEditorEdit extends LogbookEditorBase { Archived -
); } + + canSubmit() { + const attributeNames = this.state.attributes.map(({ name }) => name); + return !attributeNames.some((name, i) => attributeNames.indexOf(name) !== i); + } } class LogbookEditor extends React.Component { From 5528df9fd355418ce3781099befdba8042890244 Mon Sep 17 00:00:00 2001 From: Hannes Petri Date: Wed, 12 Jun 2019 14:18:33 +0200 Subject: [PATCH 20/23] Fixed whitespace issue --- frontend/src/logbookeditor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/logbookeditor.js b/frontend/src/logbookeditor.js index cfc05b8..68a5f1a 100644 --- a/frontend/src/logbookeditor.js +++ b/frontend/src/logbookeditor.js @@ -114,7 +114,7 @@ class LogbookEditorBase extends React.Component { } getAttributes() { - const { logbook, attributes } = this.state; + const { logbook, attributes } = this.state; return attributes.map((attr, i) => { const existingAttribute = From 9a3b212cf4ed83506f1834e5d9ccf73cb47d3ccb Mon Sep 17 00:00:00 2001 From: Hannes Petri Date: Wed, 12 Jun 2019 14:41:50 +0200 Subject: [PATCH 21/23] Added clarifying comment --- frontend/src/logbookeditor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/logbookeditor.js b/frontend/src/logbookeditor.js index 68a5f1a..cc1a40a 100644 --- a/frontend/src/logbookeditor.js +++ b/frontend/src/logbookeditor.js @@ -570,6 +570,7 @@ class LogbookEditorEdit extends LogbookEditorBase { ); } + // Disable the submit button if there are duplicate field names canSubmit() { const attributeNames = this.state.attributes.map(({ name }) => name); return !attributeNames.some((name, i) => attributeNames.indexOf(name) !== i); From a9cca5f1775994f631ce2ee41f7f6dda5b6dc297 Mon Sep 17 00:00:00 2001 From: Hannes Petri Date: Wed, 12 Jun 2019 17:01:08 +0200 Subject: [PATCH 22/23] Made buttons in logbook edit mode not tiny --- frontend/src/logbookeditor.css | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/logbookeditor.css b/frontend/src/logbookeditor.css index e547dea..0f0f0ad 100644 --- a/frontend/src/logbookeditor.css +++ b/frontend/src/logbookeditor.css @@ -17,7 +17,6 @@ #logbookeditor .attributes button { margin: 0; - padding: 0; } #logbookeditor .attribute label { From d1de59f20f3d66dc5d947cb13034bd260677a917 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Wed, 24 Jul 2019 11:12:19 +0200 Subject: [PATCH 23/23] disable html attachment --- backend/backend/api/entries.py | 2 +- backend/backend/export.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/backend/api/entries.py b/backend/backend/api/entries.py index abc383a..37bd582 100644 --- a/backend/backend/api/entries.py +++ b/backend/backend/api/entries.py @@ -204,7 +204,7 @@ def get(self, args, logbook_id=None): if html is None: abort(400, message="Could not create HTML!") return send_file(html, mimetype="text/html", - as_attachment=True, + as_attachment=False, attachment_filename=(slugify("{logbook.name}.html" .format(logbook=logbook)))) diff --git a/backend/backend/export.py b/backend/backend/export.py index 4401ee0..53c5ef0 100644 --- a/backend/backend/export.py +++ b/backend/backend/export.py @@ -61,6 +61,7 @@ def export_entries_as_html(logbook, entries): No proper formatting, and does not embed images. """ +# export = "" entries_html = [ """
Created at: {created_at}
@@ -74,7 +75,7 @@ def export_entries_as_html(logbook, entries): content=entry.content or "---") for entry in entries ] - print(entries_html) + with NamedTemporaryFile(prefix=slugify(logbook.name), suffix=".html", delete=False) as f: