From 03062000ddd702475501036b02bae0aae41de1ec Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Fri, 29 Jan 2021 20:41:45 -0600 Subject: [PATCH 001/325] replace logo svg with outline export --- src/images/logo_dark_bg.svg | 129 ++++++++++++++++++++---------------- src/images/logo_default.svg | 129 ++++++++++++++++++++---------------- 2 files changed, 146 insertions(+), 112 deletions(-) diff --git a/src/images/logo_dark_bg.svg b/src/images/logo_dark_bg.svg index 3655535..0eca10c 100644 --- a/src/images/logo_dark_bg.svg +++ b/src/images/logo_dark_bg.svg @@ -1,4 +1,4 @@ - + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + - DataJoint GUI diff --git a/src/images/logo_default.svg b/src/images/logo_default.svg index 47b9c97..c2c46ef 100644 --- a/src/images/logo_default.svg +++ b/src/images/logo_default.svg @@ -1,4 +1,4 @@ - + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + - DataJoint GUI From c2df27653fefd0c63cf663163a3d5eb2b76d4955 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Sat, 30 Jan 2021 16:32:21 -0600 Subject: [PATCH 002/325] add disabled button style --- src/Components/MainTableView/TableView.css | 8 ++++++++ src/Components/MainTableView/TableView.tsx | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Components/MainTableView/TableView.css b/src/Components/MainTableView/TableView.css index ebd06c5..0a542c5 100644 --- a/src/Components/MainTableView/TableView.css +++ b/src/Components/MainTableView/TableView.css @@ -19,6 +19,7 @@ border-radius: 2px 2px 0 0; cursor: pointer; box-shadow: -1px -1px 2px rgb(160, 160, 160); + border: none; } .table-view .nav-tabs .tab:hover { @@ -26,6 +27,13 @@ background-color: #82D088; /* light alternative green */ } +.table-view .nav-tabs .tab:disabled { + color:rgb(160, 160, 160); + background-color: #609b74; + cursor: not-allowed; +} + + .table-view .nav-tabs .tab.inView { color: #262A22; background-color: #F1f1f1; diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index 817aa2e..09c9288 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -272,7 +272,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri getCurrentView() { if (this.props.selectedTableName === '') { - return
Select a Table to see contents
+ return
Select a Table to see contents
} else if (this.state.errorMessage) { return
{this.state.errorMessage}
From 24b3a6186ae7709f44b4f88f6f0d42d6d585e658 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Sun, 31 Jan 2021 01:00:21 -0600 Subject: [PATCH 003/325] make checkbox disabled for delete and update menu after single selection --- src/Components/MainTableView/TableContent.css | 8 ++++++ src/Components/MainTableView/TableContent.tsx | 25 ++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Components/MainTableView/TableContent.css b/src/Components/MainTableView/TableContent.css index 50ce1a1..3b4b744 100644 --- a/src/Components/MainTableView/TableContent.css +++ b/src/Components/MainTableView/TableContent.css @@ -157,4 +157,12 @@ table.table { .headerRow th.buffer input { visibility: hidden; +} + +input[type="checkbox"] { + cursor: pointer; +} + +input[type="checkbox"][disabled] { + cursor: not-allowed; } \ No newline at end of file diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 2fa3bee..5bee104 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -27,7 +27,8 @@ type TableContentStatus = { pageIncrement: number, paginatorState: Array, selectedTableEntries: any, - showWarning: boolean + showWarning: boolean, + isDisabledCheckbox: boolean } /** @@ -50,7 +51,8 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s pageIncrement: 25, paginatorState: [0, 25], selectedTableEntries: {}, - showWarning: false + showWarning: false, + isDisabledCheckbox: false, } this.getCurrentTableActionMenuComponent = this.getCurrentTableActionMenuComponent.bind(this); @@ -296,6 +298,23 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s ) } + + checkSelection(tableEntry: any) { + // splitting the selected table entry into primary and secondary attributes + let primaryTableEntries = tableEntry.slice(0, this.props.tableAttributesInfo?.primaryAttributes.length); + + // pairing the table entry with it's corresponding key + let primaryEntries: any = {}; + this.props.tableAttributesInfo?.primaryAttributes.forEach((PK, index) => { + primaryEntries[PK.attributeName] = primaryTableEntries[index] + }) + + // store the labeled entries under unique keyname using its primary keys if not already there + let uniqueEntryName = primaryTableEntries.join(".") + + // returns true if entry is already selected + return this.state.selectedTableEntries[uniqueEntryName] + } render() { return( @@ -328,7 +347,7 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s {this.props.contentData.slice(this.state.paginatorState[0], this.state.paginatorState[1]).map((entry: any) => { return ( - this.handleCheckedEntry(event, entry)} /> + 0 && (this.state.currentSelectedTableActionMenu === TableActionType.DELETE || this.state.currentSelectedTableActionMenu === TableActionType.UPDATE) && !this.checkSelection(entry)} onChange={(event) => this.handleCheckedEntry(event, entry)} /> {entry.map((column: any) => { return ({column}) }) From 43bf0e610c9b0171cff3288a94771762783db1c8 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Mon, 1 Feb 2021 10:39:47 -0600 Subject: [PATCH 004/325] add styling to table content, column resizer still in works --- src/Components/MainTableView/TableContent.css | 31 +++- src/Components/MainTableView/TableContent.tsx | 140 ++++++++++++++++-- 2 files changed, 150 insertions(+), 21 deletions(-) diff --git a/src/Components/MainTableView/TableContent.css b/src/Components/MainTableView/TableContent.css index 3b4b744..76a2130 100644 --- a/src/Components/MainTableView/TableContent.css +++ b/src/Components/MainTableView/TableContent.css @@ -129,7 +129,6 @@ table.table { border-bottom: 1px solid rgb(0, 0, 0); display: flex; font-weight: 600; - } .content-view-area .table .tableRow { @@ -139,18 +138,29 @@ table.table { .content-view-area .table .tableRow td.tableCell, .content-view-area .table .headerRow th.headings { - width: 100%; + position: relative; padding: 0 4px; text-align: left; + border-right: 1px solid rgb(221, 221, 221); + padding-top: 3px; white-space: nowrap; overflow: hidden; - border-right: 1px solid rgb(221, 221, 221); + text-overflow: ellipsis; } -.content-view-area .table .tableRow td.tableCell:hover { - overflow: auto; +div.cellDivider { + position: absolute; + width: 2px; + height: 100%; + cursor: col-resize; + right: 0; + top: 0; + bottom: 0; } +.content-view-area .table .tableRow td.tableCell:hover { + /* overflow: auto; */ +} .headerRow th.buffer { /* width: 82px; */ } @@ -165,4 +175,15 @@ input[type="checkbox"] { input[type="checkbox"][disabled] { cursor: not-allowed; +} + +.paginator p{ + margin: 8px 0 0 0; +} + +.paginator .icon { + color: gray; + font-size: 0.8rem; + margin: 0 4px; + cursor: pointer; } \ No newline at end of file diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 5bee104..0aaf45b 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { createRef } from 'react'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faChevronRight, faChevronLeft, faStepBackward, faStepForward} from '@fortawesome/free-solid-svg-icons' import './TableContent.css' @@ -6,6 +6,7 @@ import TableType from '../TableTypeEnum/TableType' import InsertTuple from './InsertTuple' import DeleteTuple from './DeleteTuple' import TableAttributesInfo from './DataStorageClasses/TableAttributesInfo'; +import { isThisTypeNode } from 'typescript'; enum PaginationCommand { forward, @@ -28,9 +29,14 @@ type TableContentStatus = { paginatorState: Array, selectedTableEntries: any, showWarning: boolean, - isDisabledCheckbox: boolean + isDisabledCheckbox: boolean, + headerWidth: number, + dragStart: number, + dragDistance: number, + resizeIndex: any, } + /** * Class component to handle rendering of the tuples as well as Filter, Insert, Update, and Delete subcomponetns * @@ -53,10 +59,30 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s selectedTableEntries: {}, showWarning: false, isDisabledCheckbox: false, + headerWidth: 0, + dragStart: 0, + dragDistance: 0, + resizeIndex: undefined } this.getCurrentTableActionMenuComponent = this.getCurrentTableActionMenuComponent.bind(this); this.getShowWarningComponent = this.getShowWarningComponent.bind(this); + + // TODO: use effect to add reference for table column styling + // cellRef: React.RefObject; + // this.cellRef = createRef() + // const [colRefs, setColRefs] = React.useState([]); + // React.useEffect(() => { + // }) + + + } + + + componentDidMount() { + + + } /** @@ -72,6 +98,14 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s // Reset TableActionview this.setState({currentSelectedTableActionMenu: TableActionType.FILTER, hideTableActionMenu: true}); + + // TODO: part of reference for table column width update + // console.log('cellRef: ', this.cellRef) + // let cellStyle + // if (this.cellRef.current) { + // cellStyle = getComputedStyle(this.cellRef.current) + // console.log('width: ', cellStyle.width) + // } } /** @@ -299,6 +333,10 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s ) } + /** + * Function to check if the table entry has been selected or not (used to prevent multiple selection for delete/update mode) + * @param tableEntry + */ checkSelection(tableEntry: any) { // splitting the selected table entry into primary and secondary attributes let primaryTableEntries = tableEntry.slice(0, this.props.tableAttributesInfo?.primaryAttributes.length); @@ -315,7 +353,72 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s // returns true if entry is already selected return this.state.selectedTableEntries[uniqueEntryName] } + + /** + * Function to set the new adjusted width (TODO: fix to make sure the fix is for each column using reference) + * @param difference // the distance the user dragged the column divider handle + */ + setHeaderWidth(difference: number) { + if (this.state.headerWidth + difference > 0) { + this.setState({headerWidth: this.state.headerWidth + difference}); + } + else { + this.setState({headerWidth: 1}) + } + } + + /** + * Listens for when cell border is selected and stores the index of the column and mouse start position + * @param event + * @param colIndex + */ + cellResizeMouseDown(event: any, colIndex: any) { + this.setState({dragStart: event.clientX, resizeIndex: colIndex}) + // console.log('event.target.offsetParent.nextSibling: ', event.target.offsetParent.nextSibling) + } + + /** + * Updates the distance the user drags the table column divider + * @param event + */ + cellResizeMouseMove(event: any) { + if (this.state.dragStart) { + this.setState({dragDistance: event.pageX - this.state.dragStart}) + this.setHeaderWidth(this.state.dragDistance); + } + } + + /** + * Listens for when user is done resizing the column, resets drag position stats + * @param event + */ + cellResizeMouseUp(event: any) { + // reset column drag stats + this.setState({dragStart: 0, dragDistance: 0, resizeIndex: undefined}) + } + /** + * Tells the element how to style width of the given table column index + * @param colIndex + */ + getCellWidth(colIndex: number) { + if (this.state.resizeIndex === colIndex && this.state.headerWidth) { + return { + width: this.state.headerWidth + 'px' + } + } + else if (this.state.resizeIndex !== colIndex && this.state.headerWidth) { + return { + width: '180px' // needs to refer to each col state + } + } + else { + return { + width: '180px' // default + } + } + } + render() { return(
@@ -330,26 +433,31 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s
- + {this.cellResizeMouseMove(event)}} onMouseUp={(event) => {this.cellResizeMouseUp(event)}}> - {this.getPrimaryKeys().map((attributeName) => { - return () })} - {this.getSecondaryKeys().map((attributeName) => { - return () })} {this.props.contentData.slice(this.state.paginatorState[0], this.state.paginatorState[1]).map((entry: any) => { - return ( + return ( {this.cellResizeMouseMove(event)}} onMouseUp={(event) => {this.cellResizeMouseUp(event)}}> - {entry.map((column: any) => { - return () + {entry.map((column: any, index: number) => { + return ( + ) }) }) })} @@ -358,11 +466,11 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s

Total Rows: {this.props.contentData.length}

- this.handlePagination(PaginationCommand.start)} /> - this.handlePagination(PaginationCommand.backward)} /> + this.handlePagination(PaginationCommand.start)} /> + this.handlePagination(PaginationCommand.backward)} /> Currently viewing: {this.state.paginatorState[0] + 1} - {this.state.paginatorState[1]} - this.handlePagination(PaginationCommand.forward)} /> - this.handlePagination(PaginationCommand.end)} /> + this.handlePagination(PaginationCommand.forward)} /> + this.handlePagination(PaginationCommand.end)} />
From 7c9648877a637a4ac217524e75f02356a1f7b35f Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Mon, 1 Feb 2021 12:03:38 -0600 Subject: [PATCH 005/325] match height for action menu area --- src/Components/MainTableView/TableContent.css | 1 - src/Components/MainTableView/TableContent.tsx | 28 ++++++++++++------- src/Components/MainTableView/TableView.css | 11 +++++++- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Components/MainTableView/TableContent.css b/src/Components/MainTableView/TableContent.css index 76a2130..1d4fd97 100644 --- a/src/Components/MainTableView/TableContent.css +++ b/src/Components/MainTableView/TableContent.css @@ -117,7 +117,6 @@ table.table { width: 100%; } - .table tbody { display: inline-block; /* height: 60%; */ diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 0aaf45b..2d967de 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -159,22 +159,30 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s getCurrentTableActionMenuComponent() { if (this.state.currentSelectedTableActionMenu === TableActionType.FILTER) { - return

Filter

Replace with Filter Component

; + return (
+

Filter

+

Replace with Filter Component

+
) } else if (this.state.currentSelectedTableActionMenu === TableActionType.INSERT) { - return + return (
+ +
) } else if (this.state.currentSelectedTableActionMenu === TableActionType.UPDATE) { - return

Update

Replace with Update Component

; + return (
+

Update

+

Replace with Update Component

+
) } else if (this.state.currentSelectedTableActionMenu === TableActionType.DELETE) { - return (
-

Delete

+ return (
+

Delete

Date: Mon, 1 Feb 2021 16:32:56 -0600 Subject: [PATCH 006/325] add disable styling, adjust more styling in the delete menu --- src/Components/MainTableView/DeleteTuple.css | 70 +++++++++++++++++++ src/Components/MainTableView/DeleteTuple.tsx | 13 ++-- src/Components/MainTableView/InsertTuple.css | 0 src/Components/MainTableView/TableContent.css | 7 ++ 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 src/Components/MainTableView/InsertTuple.css diff --git a/src/Components/MainTableView/DeleteTuple.css b/src/Components/MainTableView/DeleteTuple.css index e69de29..4ddadae 100644 --- a/src/Components/MainTableView/DeleteTuple.css +++ b/src/Components/MainTableView/DeleteTuple.css @@ -0,0 +1,70 @@ +div.tupleToDeleteCheck, +div.dependencies, +div.deleting { + width: 100%; + position: relative; + box-sizing: border-box; + padding: 0px 16px; +} + +table.tupleToDelete { + text-align: left; + border-collapse: collapse; +} + +table.tupleToDelete thead tr th, +table.tupleToDelete tbody tr td { + border: 1px solid gray; + padding: 4px; + white-space: nowrap; + width: auto; +} + +table.tupleToDelete thead tr, +table.tupleToDelete tbody tr { + width: 100%; + overflow-x: auto; +} + +table.tupleToDelete thead { + background-color: rgb(212, 212, 212); +} + +button.checkDependencies, +button.confirmDeletion { + position: relative; + display: inline-flex; + justify-self: flex-end; + margin-top: 16px; + border: 2px solid rgb(151, 0, 0); + padding: 8px 20px; + border-radius: 4px; + color: rgb(151, 0, 0); + cursor: pointer; +} + +button.checkDependencies:hover { + background-color: rgb(151, 0, 0); + color: white; +} + +div.dependencies { +} + +div.deleting { + +} + +.deleting .errorMessage { + padding: 0; +} + +.deleting button.dismiss { + margin-left: 8px; + border: 1px solid gray; + border-radius: 4px; +} + +.deleting button.dismiss:hover { + background-color: rgb(212, 212, 212); +} \ No newline at end of file diff --git a/src/Components/MainTableView/DeleteTuple.tsx b/src/Components/MainTableView/DeleteTuple.tsx index fe42422..a423026 100644 --- a/src/Components/MainTableView/DeleteTuple.tsx +++ b/src/Components/MainTableView/DeleteTuple.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import "./DeleteTuple.css"; /** * list of allowed states on this delete tuple component @@ -114,10 +115,10 @@ class DeleteTuple extends React.Component<{token: string, selectedSchemaName: st return(
-

Delete this entry?

{Object.values(this.props.tupleToDelete).map((entry: any) => { return (
+

Delete this entry?

-
{attributeName}
+ {this.getPrimaryKeys().map((attributeName, index) => { + return (
+
{attributeName}
+
{this.cellResizeMouseDown(event, index)}}>
-
{attributeName}
+ {this.getSecondaryKeys().map((attributeName, index) => { + return (
+
{attributeName}
+
{this.cellResizeMouseDown(event, index + this.getPrimaryKeys().length)}}>
0 && (this.state.currentSelectedTableActionMenu === TableActionType.DELETE || this.state.currentSelectedTableActionMenu === TableActionType.UPDATE) && !this.checkSelection(entry)} onChange={(event) => this.handleCheckedEntry(event, entry)} />{column}{column} +
{this.cellResizeMouseDown(event, index)}}>
+
@@ -141,9 +142,11 @@ class DeleteTuple extends React.Component<{token: string, selectedSchemaName: st
+ + ) })} - {this.state.dependencies ? '' : + {Object.entries(this.props.tupleToDelete).length === 0 && !this.state.dependencies ?

Select a table entry to delete.

: } {/* TODO: replace with proper animation */} @@ -159,13 +162,15 @@ class DeleteTuple extends React.Component<{token: string, selectedSchemaName: st })}

Are you sure you want to delete this entry?

- +
) : ''} +
{this.state.isDeletingEntry ?

Deleting entry might take a while...(replace with wheel)

: '' } {/* TODO: replace with proper animation */} {this.state.deleteStatusMessage ? ( -
{this.state.deleteStatusMessage}
+
{this.state.deleteStatusMessage}
) : ''} +
) } diff --git a/src/Components/MainTableView/InsertTuple.css b/src/Components/MainTableView/InsertTuple.css new file mode 100644 index 0000000..e69de29 diff --git a/src/Components/MainTableView/TableContent.css b/src/Components/MainTableView/TableContent.css index 1d4fd97..640555c 100644 --- a/src/Components/MainTableView/TableContent.css +++ b/src/Components/MainTableView/TableContent.css @@ -58,6 +58,13 @@ color: #399E5A } +.content-controllers button:disabled { + border: 2px solid #969b91; + background-color: #F1f1f1; + color: #969b91; + cursor: not-allowed; +} + .content-controllers button.selectedButton { background-color: #399E5A; border-color: #399E5A; From a50374ea59d939d330908322849ac091c0050f72 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Mon, 1 Feb 2021 16:36:16 -0600 Subject: [PATCH 007/325] fix spacing between paragraph and button --- src/Components/MainTableView/DeleteTuple.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Components/MainTableView/DeleteTuple.css b/src/Components/MainTableView/DeleteTuple.css index 4ddadae..8f34f8f 100644 --- a/src/Components/MainTableView/DeleteTuple.css +++ b/src/Components/MainTableView/DeleteTuple.css @@ -48,7 +48,12 @@ button.checkDependencies:hover { color: white; } -div.dependencies { +button.confirmDeletion { + margin-bottom: 24px; +} + +div.dependencies p { + margin: 0; } div.deleting { From ccc62f8d06eefe6a0a4989fb0433369d59a26022 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Tue, 2 Feb 2021 16:07:59 -0600 Subject: [PATCH 008/325] fix pagination behavior, not styled for disabled icons yet --- src/Components/MainTableView/TableContent.tsx | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 2d967de..5b4f167 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -6,7 +6,6 @@ import TableType from '../TableTypeEnum/TableType' import InsertTuple from './InsertTuple' import DeleteTuple from './DeleteTuple' import TableAttributesInfo from './DataStorageClasses/TableAttributesInfo'; -import { isThisTypeNode } from 'typescript'; enum PaginationCommand { forward, @@ -76,13 +75,6 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s // }) - } - - - componentDidMount() { - - - } /** @@ -91,6 +83,16 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s * @param prevState */ componentDidUpdate(prevProps: any, prevState: any) { + // check to see if contentData updated, if so, check length to update page info + if (this.props.contentData !== prevProps.contentData) { + // Update paginator state if contentData is less than 25 + if (this.props.contentData.length < 25 ) { + this.setState({paginatorState: [0, this.props.contentData.length]}) + } else { + this.setState({paginatorState: [0, this.state.pageIncrement]}) // set to default increment of 25 + } + } + // Break if the the selectedTable did not change if (prevProps.selectedTableName === this.props.selectedTableName) { return; @@ -98,7 +100,7 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s // Reset TableActionview this.setState({currentSelectedTableActionMenu: TableActionType.FILTER, hideTableActionMenu: true}); - + // TODO: part of reference for table column width update // console.log('cellRef: ', this.cellRef) // let cellStyle @@ -129,18 +131,32 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s * @param cmd */ handlePagination(cmd: PaginationCommand) { + // check to see if paginator needs to even run for pages with small entries, if not, break + if (this.state.paginatorState[1] < this.state.pageIncrement) { + return; + } + + // jump to beginning if (cmd === PaginationCommand.start) { this.setState({paginatorState: [0, this.state.pageIncrement]}) } else if (cmd === PaginationCommand.end) { - this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length]}) + if (this.props.contentData.length%this.state.pageIncrement > 0) { + this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length]}) + } + else { + this.setState({paginatorState: [this.props.contentData.length - this.state.pageIncrement, this.props.contentData.length]}) + } } else if (cmd === PaginationCommand.forward) { if (this.state.paginatorState[1] + this.state.pageIncrement < this.props.contentData.length) { this.setState({paginatorState: [this.state.paginatorState[0] + this.state.pageIncrement, this.state.paginatorState[1] + this.state.pageIncrement]}) } - else { + else if (this.props.contentData.length%this.state.pageIncrement > 0) { this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length]}) + } + else { + this.setState({paginatorState: [this.props.contentData.length - this.state.pageIncrement, this.props.contentData.length]}) } } else if (cmd === PaginationCommand.backward) { @@ -157,7 +173,6 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s * Switching return code based this.state.currentSelectedTableActionMenu. Mainly used in the render() function below */ getCurrentTableActionMenuComponent() { - if (this.state.currentSelectedTableActionMenu === TableActionType.FILTER) { return (

Filter

@@ -427,7 +442,7 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s } } - render() { + render() { return(
@@ -463,7 +478,7 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s 0 && (this.state.currentSelectedTableActionMenu === TableActionType.DELETE || this.state.currentSelectedTableActionMenu === TableActionType.UPDATE) && !this.checkSelection(entry)} onChange={(event) => this.handleCheckedEntry(event, entry)} /> {entry.map((column: any, index: number) => { return ( - {column} + {column}
{this.cellResizeMouseDown(event, index)}}>
) }) From 03c20e2bd5d68a60aa8d6bf7b66a9f674c63cbef Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Tue, 2 Feb 2021 17:06:54 -0600 Subject: [PATCH 009/325] add styling to disabled pagination icons --- src/Components/MainTableView/TableContent.css | 5 +++ src/Components/MainTableView/TableContent.tsx | 44 ++++++++++++------- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/Components/MainTableView/TableContent.css b/src/Components/MainTableView/TableContent.css index 640555c..6e485e7 100644 --- a/src/Components/MainTableView/TableContent.css +++ b/src/Components/MainTableView/TableContent.css @@ -192,4 +192,9 @@ input[type="checkbox"][disabled] { font-size: 0.8rem; margin: 0 4px; cursor: pointer; +} + +.paginator .icon.disabled { + color: rgb(196, 196, 196); + cursor: not-allowed; } \ No newline at end of file diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 5b4f167..30af717 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -33,6 +33,8 @@ type TableContentStatus = { dragStart: number, dragDistance: number, resizeIndex: any, + atEndPage: boolean, + atStartPage: boolean } @@ -61,7 +63,9 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s headerWidth: 0, dragStart: 0, dragDistance: 0, - resizeIndex: undefined + resizeIndex: undefined, + atEndPage: false, + atStartPage: true } this.getCurrentTableActionMenuComponent = this.getCurrentTableActionMenuComponent.bind(this); @@ -133,13 +137,14 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s handlePagination(cmd: PaginationCommand) { // check to see if paginator needs to even run for pages with small entries, if not, break if (this.state.paginatorState[1] < this.state.pageIncrement) { + this.setState({atStartPage: true, atEndPage: true}) return; } - // jump to beginning + // jump to beginning/end/next/previous page and update the page position and style status accordingly if (cmd === PaginationCommand.start) { - this.setState({paginatorState: [0, this.state.pageIncrement]}) - } + this.setState({paginatorState: [0, this.state.pageIncrement], atStartPage: true, atEndPage: false}) + } else if (cmd === PaginationCommand.end) { if (this.props.contentData.length%this.state.pageIncrement > 0) { this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length]}) @@ -147,24 +152,33 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s else { this.setState({paginatorState: [this.props.contentData.length - this.state.pageIncrement, this.props.contentData.length]}) } + this.setState({atStartPage: false, atEndPage: true}) } else if (cmd === PaginationCommand.forward) { if (this.state.paginatorState[1] + this.state.pageIncrement < this.props.contentData.length) { - this.setState({paginatorState: [this.state.paginatorState[0] + this.state.pageIncrement, this.state.paginatorState[1] + this.state.pageIncrement]}) + this.setState({paginatorState: [this.state.paginatorState[0] + this.state.pageIncrement, this.state.paginatorState[1] + this.state.pageIncrement], + atStartPage: false}) } else if (this.props.contentData.length%this.state.pageIncrement > 0) { - this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length]}) + this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length], + atStartPage: false, atEndPage: true}) } else { - this.setState({paginatorState: [this.props.contentData.length - this.state.pageIncrement, this.props.contentData.length]}) + this.setState({paginatorState: [this.props.contentData.length - this.state.pageIncrement, this.props.contentData.length], + atStartPage: false, atEndPage: true}) } } else if (cmd === PaginationCommand.backward) { - if (this.state.paginatorState[0] - this.state.pageIncrement > 0 || this.state.paginatorState[0] - this.state.pageIncrement === 0) { - this.setState({paginatorState: [this.state.paginatorState[0] - this.state.pageIncrement, this.state.paginatorState[0]]}) - } + if (this.state.paginatorState[0] - this.state.pageIncrement > 0) { + this.setState({paginatorState: [this.state.paginatorState[0] - this.state.pageIncrement, this.state.paginatorState[0]], + atEndPage: false}) + } else if (this.state.paginatorState[0] - this.state.pageIncrement === 0) { + this.setState({paginatorState: [this.state.paginatorState[0] - this.state.pageIncrement, this.state.paginatorState[0]], + atStartPage: true, atEndPage: false}) + } else { - this.setState({paginatorState: [0, this.state.pageIncrement]}) + this.setState({paginatorState: [0, this.state.pageIncrement], + atStartPage: true, atEndPage: false}) } } } @@ -489,11 +503,11 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s

Total Rows: {this.props.contentData.length}

- this.handlePagination(PaginationCommand.start)} /> - this.handlePagination(PaginationCommand.backward)} /> + this.handlePagination(PaginationCommand.start)} /> + this.handlePagination(PaginationCommand.backward)} /> Currently viewing: {this.state.paginatorState[0] + 1} - {this.state.paginatorState[1]} - this.handlePagination(PaginationCommand.forward)} /> - this.handlePagination(PaginationCommand.end)} /> + this.handlePagination(PaginationCommand.forward)} /> + this.handlePagination(PaginationCommand.end)} />
From ace8a49d62df3319ba1f89bb5eb9ebaaa7775d7b Mon Sep 17 00:00:00 2001 From: guzman-raphael Date: Wed, 3 Feb 2021 12:46:13 -0600 Subject: [PATCH 010/325] Add some packagining optimization and clean up. --- .gitignore | 4 +++- Dockerfile | 9 ++++++++ README.md | 23 ++++++++++++------- debug.log | 1 - docker-compose.yaml | 18 --------------- local-docker-compose.yaml | 22 ++++++++++++++++++ .../enums/TableAttributeType.tsx | 2 +- 7 files changed, 50 insertions(+), 29 deletions(-) create mode 100644 Dockerfile delete mode 100644 debug.log delete mode 100644 docker-compose.yaml create mode 100644 local-docker-compose.yaml diff --git a/.gitignore b/.gitignore index e137dcd..e2c7558 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -.eslintcache \ No newline at end of file +.eslintcache +.env +docker-compose.y*ml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..40158d5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM node:lts-buster-slim +USER node +WORKDIR /home/node +COPY --chown=node:node ./package.json ./package-lock.json /home/node/ +RUN npm install +COPY --chown=node:node ./tsconfig.json ./yarn.lock /home/node/ +COPY --chown=node:node ./public /home/node/public +COPY --chown=node:node ./src /home/node/src +CMD ["npm", "start"] diff --git a/README.md b/README.md index d3f7b65..85822d9 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,22 @@ # DJ GUI React Front End -Make sure you run ```npm install``` to download all the require modules first +Single source of truth for development efforts on DJGUI Frontend. -To launch development simply run these commands -1) ```docker-compose pull``` (Need to pull the base image used for launching the node) [Should be a one time thing] -2) ```docker-compose up``` +## Branches -NOTE: The docker-compose file looks for the docker network dj-gui-api, which from the name implies is the backend for this application. If that network is not created first it might complain, but you can create it manaully to bypass that. +For now, developing under the following policy for branches: +- `dev`: Feature-complete, DEMO-ready progress. Might be a bit rough around the edges or lacking in docs, tests but functional. Demonstrates latest features that have been completed. +- `master`: Polished, release-ready source with relevant docs, tests. More stable and less likely to undergo any refactoring/restructuring. -To use this application, please clone ```git@github.com:vathes/DJ-GUI-API.git``` create an empty .env file in the root directory of the repo then run these two commands ```docker-compose build``` then ```docker-compose up``` +## Run Locally +1) Copy `local-docker-compose.yaml` to `docker-compose.yaml`. This file is untracked so feel free to modify as necessary. Idea is to commit anything generic but system/setup dependent should go on 'your' version i.e. local UID/GID, etc. +2) `docker-compose pull` to ensure images are cached before taking an outage. +3) Check the first comment which will provide best instruction on how to start the service. -Feature Request and Bugs: -Please file it under issues under repo. +NOTE: The docker-compose file looks for the `dj-gui-api` docker network which from the name implies is the backend for this application. If that network is not created first it might complain, but you can create it manually to bypass that. + + +## Feature Request and Bugs + +Please file it under issues within the repo. diff --git a/debug.log b/debug.log deleted file mode 100644 index 2753666..0000000 --- a/debug.log +++ /dev/null @@ -1 +0,0 @@ -[1202/160517.224:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3) diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 83fa7db..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,18 +0,0 @@ -version: "3.8" -services: - web: - build: . - ports: - - "3000:3000" - volumes: - - ./:/src - image: node:lts-buster-slim - networks: - - dj-gui-react - working_dir: /src/ - command: "npm start" - -networks: - dj-gui-react: - external: - name: dj-gui-api \ No newline at end of file diff --git a/local-docker-compose.yaml b/local-docker-compose.yaml new file mode 100644 index 0000000..f56f4ad --- /dev/null +++ b/local-docker-compose.yaml @@ -0,0 +1,22 @@ +# docker-compose -f local-docker-compose.yaml up +version: "2.4" +services: + web: + build: . + image: dj-gui-react + volumes: + - ./package.json:/home/node/package.json + - ./package-lock.json:/home/node/package-lock.json + - ./tsconfig.json:/home/node/tsconfig.json + - ./yarn.lock:/home/node/yarn.lock + - ./public:/home/node/public + - ./src:/home/node/src + networks: + - dj-gui-react + ports: + - "3000:3000" + command: npm start +networks: + dj-gui-react: + external: + name: dj-gui-api diff --git a/src/Components/MainTableView/enums/TableAttributeType.tsx b/src/Components/MainTableView/enums/TableAttributeType.tsx index cd8d614..079bfc4 100644 --- a/src/Components/MainTableView/enums/TableAttributeType.tsx +++ b/src/Components/MainTableView/enums/TableAttributeType.tsx @@ -1,4 +1,4 @@ -// Struct and enums to handle table attirbutes +// Struct and enums to handle table attributes enum TableAttributeType { TINY = 0, TINY_UNSIGNED = 1, From cd17aae09dcddd5d3623cc19a9d05ebd978ccacb Mon Sep 17 00:00:00 2001 From: guzman-raphael Date: Wed, 3 Feb 2021 12:56:19 -0600 Subject: [PATCH 011/325] Remove .vscode from being tracked. --- .gitignore | 1 + .vscode/settings.json | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index e2c7558..db7646a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ yarn-error.log* .eslintcache .env docker-compose.y*ml +.vscode diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 615aafb..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.pythonPath": "/usr/bin/python3" -} \ No newline at end of file From f611936a8c73bbb64308f5d0bd6bf65baf40185b Mon Sep 17 00:00:00 2001 From: Synicix Date: Wed, 3 Feb 2021 18:49:48 -0600 Subject: [PATCH 012/325] Add support for date --- src/Components/MainTableView/InsertTuple.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index 30d5375..faf9257 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -240,6 +240,14 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str
); } + else if (tableAttribute.attributeType === TableAttributeType.DATE) { + return ( +
+ {this.getAttributeLabelBlock(tableAttribute, 'date')} + +
+ ) + } else if (tableAttribute.attributeType === TableAttributeType.DATETIME) { return (
From 87d70b4baf1583900b51ed189846cc71973d4ed9 Mon Sep 17 00:00:00 2001 From: Synicix Date: Wed, 3 Feb 2021 20:03:30 -0600 Subject: [PATCH 013/325] Added basic Time handling, backend needs to be fixed to covert time to epoch --- src/Components/MainTableView/InsertTuple.tsx | 8 ++++++++ src/Components/MainTableView/TableView.tsx | 9 ++++++--- .../MainTableView/enums/TableAttributeType.tsx | 5 +++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index faf9257..296ae79 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -256,6 +256,14 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str
); } + else if (tableAttribute.attributeType === TableAttributeType.TIME) { + return ( +
+ {this.getAttributeLabelBlock(tableAttribute, 'time')} + +
+ ); + } else if (tableAttribute.attributeType === TableAttributeType.TIMESTAMP) { return (
diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index 817aa2e..62267f5 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -57,7 +57,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri this.setState({tableAttributesInfo: this.parseTableAttributes(result), errorMessage: ''}) }) .catch(error => { - this.setState({tableAttributesInfo: undefined, errorMessage: 'Problem fetching table attributes'}) + this.setState({tableAttributesInfo: undefined, errorMessage: 'Problem fetching table attributes: ' + error}) }) // retrieve table content this.fetchTableContent(); @@ -77,7 +77,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri this.setState({tableInfoData: result, errorMessage: ''}) }) .catch(error => { - this.setState({tableInfoData: '', errorMessage: 'Problem fetching table information'}) + this.setState({tableInfoData: '', errorMessage: 'Problem fetching table information: ' + error}) }) } } @@ -99,7 +99,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri this.setState({tableContentData: result.tuples, errorMessage: ''}) }) .catch(error => { - this.setState({tableContentData: [], errorMessage: 'Problem fetching table content'}) + this.setState({tableContentData: [], errorMessage: 'Problem fetching table content: ' + error}) }) } @@ -260,6 +260,9 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri else if (tableTypeString === 'datetime') { return TableAttributeType.DATETIME; } + else if (tableTypeString === 'time') { + return TableAttributeType.TIME; + } else if (tableTypeString === 'timestamp') { return TableAttributeType.TIMESTAMP; } diff --git a/src/Components/MainTableView/enums/TableAttributeType.tsx b/src/Components/MainTableView/enums/TableAttributeType.tsx index cd8d614..65b611c 100644 --- a/src/Components/MainTableView/enums/TableAttributeType.tsx +++ b/src/Components/MainTableView/enums/TableAttributeType.tsx @@ -20,8 +20,9 @@ enum TableAttributeType { UUID = 17, DATE = 18, DATETIME = 19, - TIMESTAMP = 20, - ENUM = 21 + TIME = 20, + TIMESTAMP = 21, + ENUM = 22 } export default TableAttributeType; \ No newline at end of file From 4be76aa68dc8d20c2b6a24aa70e0bf182f5d52c2 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Wed, 3 Feb 2021 23:05:25 -0600 Subject: [PATCH 014/325] clean up syntax add some more documentation --- src/Components/MainTableView/DeleteTuple.tsx | 5 +- src/Components/MainTableView/TableContent.tsx | 72 +++++++++---------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/Components/MainTableView/DeleteTuple.tsx b/src/Components/MainTableView/DeleteTuple.tsx index a423026..1a50d81 100644 --- a/src/Components/MainTableView/DeleteTuple.tsx +++ b/src/Components/MainTableView/DeleteTuple.tsx @@ -142,16 +142,13 @@ class DeleteTuple extends React.Component<{token: string, selectedSchemaName: st
- - ) })} {Object.entries(this.props.tupleToDelete).length === 0 && !this.state.dependencies ?

Select a table entry to delete.

: - + } {/* TODO: replace with proper animation */} {this.state.isGettingDependencies ?

Checking dependency...(imagine a wheel turning)...

: '' } - {this.state.dependencies ? (
diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 30af717..92a9751 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -1,4 +1,4 @@ -import React, { createRef } from 'react'; +import React, {createRef} from 'react'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import {faChevronRight, faChevronLeft, faStepBackward, faStepForward} from '@fortawesome/free-solid-svg-icons' import './TableContent.css' @@ -8,10 +8,10 @@ import DeleteTuple from './DeleteTuple' import TableAttributesInfo from './DataStorageClasses/TableAttributesInfo'; enum PaginationCommand { - forward, - backward, - start, - end + FORWARD, + BACKWARD, + START, + END } enum TableActionType { @@ -26,18 +26,17 @@ type TableContentStatus = { hideTableActionMenu: boolean, pageIncrement: number, paginatorState: Array, - selectedTableEntries: any, - showWarning: boolean, - isDisabledCheckbox: boolean, - headerWidth: number, - dragStart: number, - dragDistance: number, - resizeIndex: any, - atEndPage: boolean, - atStartPage: boolean + selectedTableEntries: any, // lookup dictionary to store the selected table entry - for menu UI + showWarning: boolean, // text warning when duplicate selection is made for delete/update, most likely to be take out once disable checkbox feature is finished + isDisabledCheckbox: boolean, // tells the UI to disable any other checkboxes once there is already a selection in delete/update mode + headerWidth: number, // part of table column resizer feature + dragStart: number, // part of table column resizer feature + dragDistance: number, // part of table column resizer feature + resizeIndex: any, // part of table column resizer feature + atEndPage: boolean, // tells the UI to disable certain pagination icons if user is on the last page + atStartPage: boolean // tells the UI to disable certain pagination icons if user is on the first page } - /** * Class component to handle rendering of the tuples as well as Filter, Insert, Update, and Delete subcomponetns * @@ -77,8 +76,6 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s // const [colRefs, setColRefs] = React.useState([]); // React.useEffect(() => { // }) - - } /** @@ -142,25 +139,25 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s } // jump to beginning/end/next/previous page and update the page position and style status accordingly - if (cmd === PaginationCommand.start) { + if (cmd === PaginationCommand.START) { this.setState({paginatorState: [0, this.state.pageIncrement], atStartPage: true, atEndPage: false}) } - else if (cmd === PaginationCommand.end) { - if (this.props.contentData.length%this.state.pageIncrement > 0) { - this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length]}) + else if (cmd === PaginationCommand.END) { + if (this.props.contentData.length % this.state.pageIncrement > 0) { + this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length % this.state.pageIncrement, this.props.contentData.length]}) } else { this.setState({paginatorState: [this.props.contentData.length - this.state.pageIncrement, this.props.contentData.length]}) } this.setState({atStartPage: false, atEndPage: true}) } - else if (cmd === PaginationCommand.forward) { + else if (cmd === PaginationCommand.FORWARD) { if (this.state.paginatorState[1] + this.state.pageIncrement < this.props.contentData.length) { this.setState({paginatorState: [this.state.paginatorState[0] + this.state.pageIncrement, this.state.paginatorState[1] + this.state.pageIncrement], atStartPage: false}) } - else if (this.props.contentData.length%this.state.pageIncrement > 0) { - this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length%this.state.pageIncrement, this.props.contentData.length], + else if (this.props.contentData.length % this.state.pageIncrement > 0) { + this.setState({paginatorState: [this.props.contentData.length - this.props.contentData.length % this.state.pageIncrement, this.props.contentData.length], atStartPage: false, atEndPage: true}) } else { @@ -168,11 +165,12 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s atStartPage: false, atEndPage: true}) } } - else if (cmd === PaginationCommand.backward) { + else if (cmd === PaginationCommand.BACKWARD) { if (this.state.paginatorState[0] - this.state.pageIncrement > 0) { this.setState({paginatorState: [this.state.paginatorState[0] - this.state.pageIncrement, this.state.paginatorState[0]], atEndPage: false}) - } else if (this.state.paginatorState[0] - this.state.pageIncrement === 0) { + } + else if (this.state.paginatorState[0] - this.state.pageIncrement === 0) { this.setState({paginatorState: [this.state.paginatorState[0] - this.state.pageIncrement, this.state.paginatorState[0]], atStartPage: true, atEndPage: false}) } @@ -195,11 +193,12 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s } else if (this.state.currentSelectedTableActionMenu === TableActionType.INSERT) { return (
-
) } @@ -212,7 +211,8 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s else if (this.state.currentSelectedTableActionMenu === TableActionType.DELETE) { return (

Delete

-

Total Rows: {this.props.contentData.length}

- this.handlePagination(PaginationCommand.start)} /> - this.handlePagination(PaginationCommand.backward)} /> + this.handlePagination(PaginationCommand.START)} /> + this.handlePagination(PaginationCommand.BACKWARD)} /> Currently viewing: {this.state.paginatorState[0] + 1} - {this.state.paginatorState[1]} - this.handlePagination(PaginationCommand.forward)} /> - this.handlePagination(PaginationCommand.end)} /> + this.handlePagination(PaginationCommand.FORWARD)} /> + this.handlePagination(PaginationCommand.END)} />
From 4469cf2d0ff4cac3f4f8d71ae963dee411412002 Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 00:17:42 -0600 Subject: [PATCH 015/325] Fixed fetching problems for Date, DateTime, Time and Blob --- src/Components/MainTableView/TableView.tsx | 57 ++++++++++++++++++- .../enums/TableAttributeType.tsx | 3 +- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index 62267f5..fd111c4 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -9,6 +9,8 @@ import TableAttributeType from './enums/TableAttributeType'; import TableAttributesInfo from './DataStorageClasses/TableAttributesInfo'; import PrimaryTableAttribute from './DataStorageClasses/PrimaryTableAttribute'; import SecondaryTableAttribute from './DataStorageClasses/SecondaryTableAttribute'; +import { table } from 'console'; +import TableAttribute from './DataStorageClasses/TableAttribute'; type TableViewState = { tableAttributesInfo?: TableAttributesInfo, @@ -56,11 +58,13 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri .then(result => { this.setState({tableAttributesInfo: this.parseTableAttributes(result), errorMessage: ''}) }) + .then(() => { + // Fetch table content after getting the table attribute info + this.fetchTableContent(); + }) .catch(error => { this.setState({tableAttributesInfo: undefined, errorMessage: 'Problem fetching table attributes: ' + error}) }) - // retrieve table content - this.fetchTableContent(); } if (this.state.currentView === 'tableInfo') { fetch('/api/get_table_definition', { @@ -93,9 +97,33 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri if (!result.ok) { throw Error(`${result.status} - ${result.statusText}`) } - return result.json() + return result.json(); }) .then(result => { + // Deal with coverting time back to datajoint format + let tableAttributes: Array = this.state.tableAttributesInfo?.primaryAttributes as Array; + tableAttributes = tableAttributes.concat(this.state.tableAttributesInfo?.secondaryAttributes as Array); + + // Iterate though each tableAttribute and deal with TEMPORAL types + for (let i = 0; i < tableAttributes.length; i++) { + console.log(tableAttributes[i].attributeName) + if (tableAttributes[i].attributeType === TableAttributeType.TIME) { + for (let tuple of result.tuples) { + tuple[i] = this.parseTimeString(tuple[i]); + } + } + else if (tableAttributes[i].attributeType === TableAttributeType.TIMESTAMP || tableAttributes[i].attributeType === TableAttributeType.DATETIME) { + for (let tuple of result.tuples) { + tuple[i] = this.parseDateTime(tuple[i]); + } + } + else if (tableAttributes[i].attributeType === TableAttributeType.DATE) { + for (let tuple of result.tuples) { + tuple[i] = this.parseDate(tuple[i]); + } + } + } + this.setState({tableContentData: result.tuples, errorMessage: ''}) }) .catch(error => { @@ -103,6 +131,25 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri }) } + /** + * Function to covert epoch time string back to datajoint time format + * @param timeString + */ + parseTimeString(timeString: string) { + let date = new Date(parseInt(timeString) * 1000); + return date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds(); + } + + parseDateTime(dateTimeString: string) { + let date = new Date(parseInt(dateTimeString) * 1000); + return date.toString(); + } + + parseDate(dateTimeString: string) { + let date = new Date(parseInt(dateTimeString) * 1000); + return date.toDateString(); + } + /** * Function to convert the api return json to produce a TableAttributeInfo * @param jsonResult @@ -173,6 +220,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri )); } else if (tableAttributeType === TableAttributeType.ENUM) { + // Get each enum option and save it under enumOptions tableAttributesInfo.secondaryAttributes.push(new SecondaryTableAttribute( secondaryAttributesInfoArray[0], this.parseTableTypeString(secondaryAttributesInfoArray[1]), @@ -269,6 +317,9 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri else if (tableTypeString.substring(0, 4) === 'enum') { return TableAttributeType.ENUM; } + else if (tableTypeString === 'blob') { + return TableAttributeType.BLOB; + } throw Error('Unsupported TableAttributeType: ' + tableTypeString); } diff --git a/src/Components/MainTableView/enums/TableAttributeType.tsx b/src/Components/MainTableView/enums/TableAttributeType.tsx index 65b611c..7358fe1 100644 --- a/src/Components/MainTableView/enums/TableAttributeType.tsx +++ b/src/Components/MainTableView/enums/TableAttributeType.tsx @@ -22,7 +22,8 @@ enum TableAttributeType { DATETIME = 19, TIME = 20, TIMESTAMP = 21, - ENUM = 22 + ENUM = 22, + BLOB = 23 } export default TableAttributeType; \ No newline at end of file From 2cd46f1e0082aabbb37cafc1fb9f6cce7d7e203f Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 00:33:51 -0600 Subject: [PATCH 016/325] Remove random auto import --- src/Components/MainTableView/TableView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index fd111c4..db440c6 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -9,7 +9,6 @@ import TableAttributeType from './enums/TableAttributeType'; import TableAttributesInfo from './DataStorageClasses/TableAttributesInfo'; import PrimaryTableAttribute from './DataStorageClasses/PrimaryTableAttribute'; import SecondaryTableAttribute from './DataStorageClasses/SecondaryTableAttribute'; -import { table } from 'console'; import TableAttribute from './DataStorageClasses/TableAttribute'; type TableViewState = { From 7794e12a5b40f8e3566ef6d6ca618f1d0859ddfb Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 00:41:01 -0600 Subject: [PATCH 017/325] Add missing docs for helper functions --- src/Components/MainTableView/TableView.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index db440c6..2331a96 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -139,11 +139,19 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri return date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds(); } + /** + * Helper function for converting dateTime string back to string format for table view + * @param dateTimeString + */ parseDateTime(dateTimeString: string) { let date = new Date(parseInt(dateTimeString) * 1000); return date.toString(); } + /** + * Helper function for converting date to Date String + * @param dateTimeString + */ parseDate(dateTimeString: string) { let date = new Date(parseInt(dateTimeString) * 1000); return date.toDateString(); From 9e169682b7df7695a3f936b8b91e8db56b25f110 Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 02:00:17 -0600 Subject: [PATCH 018/325] Add framework for preventing insert on blobs tables --- src/Components/MainTableView/TableContent.tsx | 4 ++++ src/Components/MainTableView/TableView.tsx | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 92a9751..65eeb9f 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -341,6 +341,10 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s return secondaryKeyList; } + checkIfTableHasBlobs(): boolean { + return false; + } + /** * Handle button rednering with disable feature for Insert Update or Delete based on the table type and return the buttons accordingly */ diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index 0ddb8e0..3e5987f 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -87,6 +87,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri } fetchTableContent() { + console.log(this.props.selectedTableName) fetch('/api/fetch_tuples', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token}, @@ -105,7 +106,6 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri // Iterate though each tableAttribute and deal with TEMPORAL types for (let i = 0; i < tableAttributes.length; i++) { - console.log(tableAttributes[i].attributeName) if (tableAttributes[i].attributeType === TableAttributeType.TIME) { for (let tuple of result.tuples) { tuple[i] = this.parseTimeString(tuple[i]); From 622206e48c2eb5ddc57d8e6ee81792e96621ca6a Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 02:03:20 -0600 Subject: [PATCH 019/325] Added longblob parsing on the front end --- src/Components/MainTableView/TableView.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index d1aa86f..cdef342 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -324,10 +324,10 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri else if (tableTypeString.substring(0, 4) === 'enum') { return TableAttributeType.ENUM; } - else if (tableTypeString === 'blob') { + else if (tableTypeString === 'blob' || tableTypeString === 'longblob') { return TableAttributeType.BLOB; } - + console.log(tableTypeString) throw Error('Unsupported TableAttributeType: ' + tableTypeString); } From 02d12c84e669b40cc998edfcb02ff8e5cd61e861 Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 02:17:36 -0600 Subject: [PATCH 020/325] Add disable insert and update for tables that has blobs --- src/Components/MainTableView/TableContent.tsx | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 65eeb9f..3122e9a 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -6,6 +6,8 @@ import TableType from '../TableTypeEnum/TableType' import InsertTuple from './InsertTuple' import DeleteTuple from './DeleteTuple' import TableAttributesInfo from './DataStorageClasses/TableAttributesInfo'; +import TableAttribute from './DataStorageClasses/TableAttribute' +import TableAttributeType from './enums/TableAttributeType' enum PaginationCommand { FORWARD, @@ -341,7 +343,23 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s return secondaryKeyList; } + /** + * Check if the current table has blob attributes + */ checkIfTableHasBlobs(): boolean { + if (this.props.tableAttributesInfo === undefined) { + return false; + } + + let tableAttributes: Array = this.props.tableAttributesInfo?.primaryAttributes as Array; + tableAttributes = tableAttributes.concat(this.props.tableAttributesInfo?.secondaryAttributes as Array); + + for (let tableAttribute of tableAttributes) { + if (tableAttribute.attributeType === TableAttributeType.BLOB) { + return true; + } + } + return false; } @@ -353,8 +371,7 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s let disableUpdate: boolean = false; let disableDelete: boolean = false; - - if (this.props.selectedTableType === TableType.COMPUTED || this.props.selectedTableType === TableType.IMPORTED) { + if (this.props.selectedTableType === TableType.COMPUTED || this.props.selectedTableType === TableType.IMPORTED || this.checkIfTableHasBlobs()) { disableInsert = true; disableUpdate = true; } From 95ab318038a9c24ce9fda8815931154cb5cc81e0 Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 03:37:18 -0600 Subject: [PATCH 021/325] Completed code to handle insert of date, datetime, time, and timestamp --- src/Components/MainTableView/InsertTuple.tsx | 76 +++++++++++++++++--- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index 296ae79..64a7dba 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -29,6 +29,27 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str this.onSubmit = this.onSubmit.bind(this); } +/** + * Handle cases with enums on load by setting the deafult value to the first enum option + */ + componentDidMount() { + // Figure out if any of the attribute is enum type, if so set the state ahead of time + let tableAttributes: Array = this.props.tableAttributesInfo?.primaryAttributes as Array; + tableAttributes = tableAttributes.concat(this.props.tableAttributesInfo?.secondaryAttributes as Array); + for (let tableAttribute of tableAttributes) { + if (tableAttribute.attributeType === TableAttributeType.ENUM) { + if (tableAttribute.enumOptions === undefined) { + throw Error('tableAttribute.enumOptions is undefined'); + } + + // Set enum to first value + let tupleBuffer = Object.assign({}, this.state.tupleBuffer); + tupleBuffer[tableAttribute.attributeName] = tableAttribute.enumOptions[0]; + this.setState({tupleBuffer}) + } + } + } + /** * Helper function to handle attribute changes by updating tupleBuffer accordingly * @param attributeName Attribute name of the change, this is used to access the tupleBuffer object members to set the value @@ -36,7 +57,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str */ handleChange(attributeName: string, event: any) { // Create a copy, update the object, then set state - let tupleBuffer = this.state.tupleBuffer; + let tupleBuffer = Object.assign({}, this.state.tupleBuffer); tupleBuffer[attributeName] = event.target.value; this.setState({tupleBuffer: tupleBuffer}); } @@ -52,9 +73,42 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str if (this.props.tableAttributesInfo === undefined) { return; } - + // Copy the current state of tupleBuffer for processing for submission - let tupleBuffer = this.state.tupleBuffer; + let tupleBuffer = Object.assign({}, this.state.tupleBuffer); + + // Loop through and deal with date, datetime, and timestamp formats + let tableAttributes: Array = this.props.tableAttributesInfo?.primaryAttributes as Array; + tableAttributes = tableAttributes.concat(this.props.tableAttributesInfo?.secondaryAttributes as Array); + for (let tableAttribute of tableAttributes) { + if (tableAttribute.attributeType === TableAttributeType.DATE) { + // Check if attribute exists, if not break + if (!tupleBuffer.hasOwnProperty(tableAttribute.attributeName)) { + break; + } + + // Covert date to UTC + let date = new Date(tupleBuffer[tableAttribute.attributeName]) + tupleBuffer[tableAttribute.attributeName] = date.getUTCFullYear() + ':' + date.getUTCMonth() + ':' + date.getUTCDay() + } + else if (tableAttribute.attributeType === TableAttributeType.DATETIME || tableAttribute.attributeType === TableAttributeType.TIMESTAMP) { + // Check if attribute exists, if not break + if (!tupleBuffer.hasOwnProperty(tableAttribute.attributeName + '__date') && !tupleBuffer.hasOwnProperty(tableAttribute.attributeName + 'time')) { + break; + } + + // Covert date time to UTC + let date = new Date(tupleBuffer[tableAttribute.attributeName + '__date'] + 'T' + tupleBuffer[tableAttribute.attributeName + '__time']); + + // Delete extra fields from tuple + delete tupleBuffer[tableAttribute.attributeName + '__date']; + delete tupleBuffer[tableAttribute.attributeName + '__time']; + + // Construct the insert string + tupleBuffer[tableAttribute.attributeName] = date.getUTCFullYear() + ':' + date.getUTCMonth() + ':' + date.getUTCDay() + ' ' + date.getUTCHours() + ':' + date.getUTCMinutes() + ':' + date.getUTCMinutes(); + } + } + // Check primary attributes first that everything is filled out correctly in tupleBuffer for (let primaryAttribute of this.props.tableAttributesInfo.primaryAttributes) { // Check if attribute exist, if not then complain @@ -103,6 +157,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str .catch((error) => { this.setState({errorMessage: error}); }) + } /** @@ -252,32 +307,33 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str return (
{this.getAttributeLabelBlock(tableAttribute, 'date time')} - + +
); } else if (tableAttribute.attributeType === TableAttributeType.TIME) { return (
- {this.getAttributeLabelBlock(tableAttribute, 'time')} - + {this.getAttributeLabelBlock(tableAttribute, 'HH:MM:SS')} +
); } else if (tableAttribute.attributeType === TableAttributeType.TIMESTAMP) { return (
- {this.getAttributeLabelBlock(tableAttribute, 'time')} - + {this.getAttributeLabelBlock(tableAttribute, 'time stamp')} + +
); } else if (tableAttribute.attributeType === TableAttributeType.ENUM) { - // Does not handle default value for enum return (
{this.getAttributeLabelBlock(tableAttribute, 'enum')} - { tableAttribute.enumOptions?.map((enumOptionString: string) => { return(); })} From 09ba6c471a9a04e66f8ea873244100e25057f5c8 Mon Sep 17 00:00:00 2001 From: Synicix Date: Thu, 4 Feb 2021 03:48:38 -0600 Subject: [PATCH 022/325] Enable UUID input block --- src/Components/MainTableView/InsertTuple.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index 64a7dba..1c1c7b4 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -287,11 +287,11 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str
); } - else if (tableAttribute.attributeType === TableAttributeType.UUID) { // TODO NEED TO DEAL WITH UUID GENRATION HERE + else if (tableAttribute.attributeType === TableAttributeType.UUID) { return (
{this.getAttributeLabelBlock(tableAttribute, 'UUID')} - +
); } From e541069775967575bc20a9d535cc1ae199d88a53 Mon Sep 17 00:00:00 2001 From: Synicix Date: Fri, 5 Feb 2021 01:22:34 -0600 Subject: [PATCH 023/325] Added decimal insert support --- .../PrimaryTableAttribute.tsx | 12 +++++- .../SecondaryTableAttribute.tsx | 12 +++++- .../DataStorageClasses/TableAttribute.tsx | 13 ++++++- src/Components/MainTableView/InsertTuple.tsx | 39 +++++++++++++++++-- src/Components/MainTableView/TableView.tsx | 35 +++++++++++++++-- 5 files changed, 98 insertions(+), 13 deletions(-) diff --git a/src/Components/MainTableView/DataStorageClasses/PrimaryTableAttribute.tsx b/src/Components/MainTableView/DataStorageClasses/PrimaryTableAttribute.tsx index 5538d37..d05414f 100644 --- a/src/Components/MainTableView/DataStorageClasses/PrimaryTableAttribute.tsx +++ b/src/Components/MainTableView/DataStorageClasses/PrimaryTableAttribute.tsx @@ -7,8 +7,16 @@ import TableAttributeType from '../enums/TableAttributeType' class PrimaryTableAttribute extends TableAttribute { autoIncrement: boolean; // Note this is only valid if the attributeType is int type - constructor(attributeName: string, attributeType: TableAttributeType, autoIncrement: boolean, stringTypeAttributeLengthInfo?: number, enumOptions?: Array) { - super(attributeName, attributeType, stringTypeAttributeLengthInfo, enumOptions); + constructor( + attributeName: string, + attributeType: TableAttributeType, + autoIncrement: boolean, + stringTypeAttributeLengthInfo?: number, + enumOptions?: Array, + decimalNumDigits?: number, + decimalNumDecimalDigits?: number + ) { + super(attributeName, attributeType, stringTypeAttributeLengthInfo, enumOptions, decimalNumDigits, decimalNumDecimalDigits); this.autoIncrement = autoIncrement; } } diff --git a/src/Components/MainTableView/DataStorageClasses/SecondaryTableAttribute.tsx b/src/Components/MainTableView/DataStorageClasses/SecondaryTableAttribute.tsx index d89fac3..f9ced09 100644 --- a/src/Components/MainTableView/DataStorageClasses/SecondaryTableAttribute.tsx +++ b/src/Components/MainTableView/DataStorageClasses/SecondaryTableAttribute.tsx @@ -8,8 +8,16 @@ class SecondaryTableAttribute extends TableAttribute { nullable: boolean; defaultValue: string; - constructor(attributeName: string, attributeType: TableAttributeType, nullable: boolean, defaultValue: string, stringTypeAttributeLengthInfo?: number, enumOptions?: Array) { - super(attributeName, attributeType, stringTypeAttributeLengthInfo, enumOptions); + constructor(attributeName: string, + attributeType: TableAttributeType, + nullable: boolean, + defaultValue: string, + stringTypeAttributeLengthInfo?: number, + enumOptions?: Array, + decimalNumDigits?: number, + decimalNumDecimalDigits?: number + ) { + super(attributeName, attributeType, stringTypeAttributeLengthInfo, enumOptions, decimalNumDigits, decimalNumDecimalDigits); this.nullable = nullable; this.defaultValue = defaultValue; } diff --git a/src/Components/MainTableView/DataStorageClasses/TableAttribute.tsx b/src/Components/MainTableView/DataStorageClasses/TableAttribute.tsx index e989330..672b4b7 100644 --- a/src/Components/MainTableView/DataStorageClasses/TableAttribute.tsx +++ b/src/Components/MainTableView/DataStorageClasses/TableAttribute.tsx @@ -8,12 +8,23 @@ class TableAttribute { attributeType: TableAttributeType; stringTypeAttributeLengthInfo?: number; enumOptions?: Array; + decimalNumDigits?: number; + decimalNumDecimalDigits?: number; - constructor(attributeName: string, attributeType: TableAttributeType, stringTypeAttributeLengthInfo?: number, enumOptions?: Array) { + constructor( + attributeName: string, + attributeType: TableAttributeType, + stringTypeAttributeLengthInfo?: number, + enumOptions?: Array, + decimalNumDigits?: number, + decimalNumDecimalDigits?: number + ) { this.attributeName = attributeName; this.attributeType = attributeType; this.stringTypeAttributeLengthInfo = stringTypeAttributeLengthInfo; this.enumOptions = enumOptions; + this.decimalNumDigits = decimalNumDigits; + this.decimalNumDecimalDigits = decimalNumDecimalDigits } } diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index 1c1c7b4..287462c 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -241,22 +241,53 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str min = '0'; max = '4294967295'; } - else if (tableAttribute.attributeType === TableAttributeType.FLOAT || tableAttribute.attributeType === TableAttributeType.DECIMAL) { + else if (tableAttribute.attributeType === TableAttributeType.FLOAT) { return(
- {this.getAttributeLabelBlock(tableAttribute, 'decimal')} + {this.getAttributeLabelBlock(tableAttribute, 'float')}
); } - else if (tableAttribute.attributeType === TableAttributeType.FLOAT_UNSIGNED || tableAttribute.attributeType === TableAttributeType.DECIMAL_UNSIGNED) { // This is depricated in MYSQL 8.0 + else if (tableAttribute.attributeType === TableAttributeType.FLOAT_UNSIGNED ) { return(
- {this.getAttributeLabelBlock(tableAttribute, 'decimal unsigned')} + {this.getAttributeLabelBlock(tableAttribute, 'float unsigned')}
); } + else if (tableAttribute.attributeType === TableAttributeType.DECIMAL) { + // Check that decimalNumdigits, and decimalNumDecimalDigits are not undefined + if (tableAttribute.decimalNumDigits === undefined || tableAttribute.decimalNumDecimalDigits === undefined) { + throw Error('Decimal attributes of decimalNumDigits or decimalNumDecimalDigits are undefined'); + } + + // Generate max number input for the given params + let maxValueString: string = ''; + let stepValueString : string = '0.'; + // Deal with the leading numbers before the decimal point + for (let i = 0; i < tableAttribute.decimalNumDigits - tableAttribute.decimalNumDecimalDigits; i++) { + maxValueString += '9' + } + maxValueString += '.' + + for (let i = 0; i < tableAttribute.decimalNumDecimalDigits; i++) { + maxValueString += '9' + } + + for (let i = 0; i < tableAttribute.decimalNumDecimalDigits - 1; i++) { + stepValueString += '0' + } + stepValueString += '1' + + return( +
+ {this.getAttributeLabelBlock(tableAttribute, 'decimal(' + tableAttribute.decimalNumDigits + ', ' + tableAttribute.decimalNumDecimalDigits)} + +
+ ); + } else if (tableAttribute.attributeType === TableAttributeType.BOOL) { if (defaultValue === '') { defaultValue = 'false' diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index 5dac6c8..21422e7 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -87,7 +87,6 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri } fetchTableContent() { - console.log(this.props.selectedTableName) fetch('/api/fetch_tuples', { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token}, @@ -195,6 +194,19 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri primaryAttributeInfoArray[1].substring(5, primaryAttributeInfoArray[1].length - 1).replace(/'/g, '').split(',') )); } + else if (tableAttributeType === TableAttributeType.DECIMAL) { + let decimalAttributes = primaryAttributeInfoArray[1].substring(7).replace(/[{()}]/g, '').split(','); + + tableAttributesInfo.primaryAttributes.push(new PrimaryTableAttribute( + primaryAttributeInfoArray[0], + tableAttributeType, + primaryAttributeInfoArray[4], + undefined, + undefined, + parseInt(decimalAttributes[0]), + parseInt(decimalAttributes[1]) + )); + } else { tableAttributesInfo.primaryAttributes.push(new PrimaryTableAttribute( primaryAttributeInfoArray[0], @@ -237,6 +249,20 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri secondaryAttributesInfoArray[1].substring(5, secondaryAttributesInfoArray[1].length - 1).replace(/'/g, '').split(',') )); } + else if (tableAttributeType === TableAttributeType.DECIMAL) { + let decimalAttributes = secondaryAttributesInfoArray[1].substring(7).replace(/[{()}]/g, '').split(','); + // Get each enum option and save it under enumOptions + tableAttributesInfo.secondaryAttributes.push(new SecondaryTableAttribute( + secondaryAttributesInfoArray[0], + this.parseTableTypeString(secondaryAttributesInfoArray[1]), + secondaryAttributesInfoArray[2], + secondaryAttributesInfoArray[3], + undefined, + undefined, + parseInt(decimalAttributes[0]), + parseInt(decimalAttributes[1]) + )); + } else { tableAttributesInfo.secondaryAttributes.push(new SecondaryTableAttribute( secondaryAttributesInfoArray[0], @@ -285,10 +311,11 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri else if (tableTypeString === 'int unsigned') { return TableAttributeType.INT_UNSIGNED; } - else if (tableTypeString === 'decimal') { + else if (tableTypeString.substr(0, 7) === 'decimal') { return TableAttributeType.DECIMAL; } - else if (tableTypeString === 'decimal unsigned') { + else if (tableTypeString === 'decimal unsigned') { + // Depricated in SQL 8.0 return TableAttributeType.DECIMAL_UNSIGNED; } else if (tableTypeString === 'float') { @@ -327,7 +354,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri else if (tableTypeString === 'blob' || tableTypeString === 'longblob') { return TableAttributeType.BLOB; } - console.log(tableTypeString) + throw Error('Unsupported TableAttributeType: ' + tableTypeString); } From 73a430f222faa0e62044f245b225a5367af98ea6 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Fri, 5 Feb 2021 10:04:54 -0600 Subject: [PATCH 024/325] style insert action menu. multiple copy over and nullable icons not working yet --- src/Components/MainTableView/InsertTuple.css | 112 +++++++++++++++++++ src/Components/MainTableView/InsertTuple.tsx | 96 ++++++++++------ 2 files changed, 172 insertions(+), 36 deletions(-) diff --git a/src/Components/MainTableView/InsertTuple.css b/src/Components/MainTableView/InsertTuple.css index e69de29..e26f8ed 100644 --- a/src/Components/MainTableView/InsertTuple.css +++ b/src/Components/MainTableView/InsertTuple.css @@ -0,0 +1,112 @@ +form { + width: 100%; + position: relative; +} + +.inputRow { + display: flex; + position: relative; + width: 100%; + overflow-x: hidden; + margin-right: 0; + flex-direction: flex-end; + padding-bottom: 12px; +} + +.inputRow:hover { + overflow-x: auto; +} + +.rowControlls { + align-self: flex-end; + display: flex; +} + +.rowControlls .icon { + margin-right: 8px; + color: rgb(80, 80, 80); + cursor: pointer; +} + +.rowControlls .icon.deleteRow:hover { + color: rgb(151, 0, 0); +} + +.rowControlls .icon.addRow:hover { + color: rgb(5, 114, 5); +} + +.fieldUnit { + display: flex; + flex-direction: column; + width: fit-content; + border: 0.5px solid gray; +} + +.attributeHead { + padding: 4px; + background-color: rgb(228, 228, 228); + font-size: 0.8rem; + display: flex; + align-items: center; + white-space: nowrap; +} + +.attributeHead label { + font-weight: 800; +} + +.attributeHead .nullableControls { + display: flex; + align-items: center; +} + +.attributeHead .nullableTag { + margin-left: 24px; + border-radius: 2px; + font-size: 0.7rem; + background-color: rgb(80, 80, 80); + padding: 0px 4px; + color: white; +} + +.attributeHead .resetIcon { + color: rgb(80, 80, 80); + margin: 0 4px; + cursor: pointer; +} + +.fieldUnit input, +.fieldUnit input:focus, +.fieldUnit input:active { + box-sizing: border-box; + border-radius: 0; + border: none; + border-top: 1px solid gray; + outline: none; + height: 100%; + padding: 0 4px; +} + +.fieldUnit .dateTimeFields { + display: flex; +} + +.fieldUnit .dateTimeFields input:first-of-type { + border-right: 1px solid gray; +} + +.submitButton { + margin-top: 16px; + border: 2px solid rgb(5, 114, 5); + padding: 8px 20px; + border-radius: 4px; + color: rgb(5, 114, 5); + cursor: pointer; +} + + +.submitButton:hover { + background-color: rgb(5, 114, 5); + color: white; +} diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index 1c1c7b4..99c0551 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -1,8 +1,12 @@ import React from 'react'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faRedoAlt, faTrashAlt, faPlusCircle} from '@fortawesome/free-solid-svg-icons' import TableAttribute from './DataStorageClasses/TableAttribute'; import TableAttributesInfo from './DataStorageClasses/TableAttributesInfo'; import PrimaryTableAttribute from './DataStorageClasses/PrimaryTableAttribute'; import TableAttributeType from './enums/TableAttributeType'; +import './InsertTuple.css' +import SecondaryTableAttribute from './DataStorageClasses/SecondaryTableAttribute'; type insertTupleState = { tupleBuffer: any // Object to stored the values typed in by the user @@ -165,8 +169,18 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str * @param tableAttribute Table attribute object so the function can extract the attributeName (Could add special label/look CSS for differnet types later on) * @param typeString The string to put in () for the user to see of what type the attribute is */ - getAttributeLabelBlock(tableAttribute: TableAttribute, typeString: string) { - return ; + getAttributeLabelBlock(tableAttribute: any, typeString: string) { + return ( +
+ + {tableAttribute.constructor === SecondaryTableAttribute && tableAttribute.nullable ? +
+
nullable
+ +
: '' + } +
+ ); } /** @@ -243,7 +257,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } else if (tableAttribute.attributeType === TableAttributeType.FLOAT || tableAttribute.attributeType === TableAttributeType.DECIMAL) { return( -
+
{this.getAttributeLabelBlock(tableAttribute, 'decimal')}
@@ -251,7 +265,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } else if (tableAttribute.attributeType === TableAttributeType.FLOAT_UNSIGNED || tableAttribute.attributeType === TableAttributeType.DECIMAL_UNSIGNED) { // This is depricated in MYSQL 8.0 return( -
+
{this.getAttributeLabelBlock(tableAttribute, 'decimal unsigned')}
@@ -262,7 +276,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str defaultValue = 'false' } return( -
+
{this.getAttributeLabelBlock(tableAttribute, 'bool')}
@@ -281,7 +295,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } else if (tableAttribute.attributeType === TableAttributeType.VAR_CHAR) { return ( -
+
{this.getAttributeLabelBlock(tableAttribute, 'varchar(' + tableAttribute.stringTypeAttributeLengthInfo + ')')}
@@ -289,7 +303,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } else if (tableAttribute.attributeType === TableAttributeType.UUID) { return ( -
+
{this.getAttributeLabelBlock(tableAttribute, 'UUID')}
@@ -297,7 +311,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } else if (tableAttribute.attributeType === TableAttributeType.DATE) { return ( -
+
{this.getAttributeLabelBlock(tableAttribute, 'date')}
@@ -305,16 +319,18 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } else if (tableAttribute.attributeType === TableAttributeType.DATETIME) { return ( -
+
{this.getAttributeLabelBlock(tableAttribute, 'date time')} - - +
+ + +
); } else if (tableAttribute.attributeType === TableAttributeType.TIME) { return ( -
+
{this.getAttributeLabelBlock(tableAttribute, 'HH:MM:SS')}
@@ -322,16 +338,18 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } else if (tableAttribute.attributeType === TableAttributeType.TIMESTAMP) { return ( -
+
{this.getAttributeLabelBlock(tableAttribute, 'time stamp')} - - +
+ + +
); } else if (tableAttribute.attributeType === TableAttributeType.ENUM) { return ( -
+
{this.getAttributeLabelBlock(tableAttribute, 'enum')}
@@ -362,7 +380,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str getPrimaryAttributeInputBlock(primaryTableAttribute: PrimaryTableAttribute) { if (primaryTableAttribute.autoIncrement === true) { return( -
+
{this.getAttributeLabelBlock(primaryTableAttribute, 'Auto Increment')}
@@ -378,23 +396,29 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str

Insert

- { - // Deal with primary attirbutes - this.props.tableAttributesInfo?.primaryAttributes.map((primaryTableAttribute) => { - return( - this.getPrimaryAttributeInputBlock(primaryTableAttribute) - ) - }) - } - { - // Deal with secondary attributes - this.props.tableAttributesInfo?.secondaryAttributes.map((secondaryAttribute) => { - return( - this.getAttributeInputBlock(secondaryAttribute) - ) - }) - } - +
+
+ + +
+ { + // Deal with primary attirbutes + this.props.tableAttributesInfo?.primaryAttributes.map((primaryTableAttribute) => { + return( + this.getPrimaryAttributeInputBlock(primaryTableAttribute) + ) + }) + } + { + // Deal with secondary attributes + this.props.tableAttributesInfo?.secondaryAttributes.map((secondaryAttribute) => { + return( + this.getAttributeInputBlock(secondaryAttribute) + ) + }) + } +
+
{this.state.errorMessage}
From 016d4294bd78b52e01cda6e002727ce9ad7786a9 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Fri, 5 Feb 2021 10:20:38 -0600 Subject: [PATCH 025/325] disable action menu button and multiple checkbox for delete/update/insert mode. clear selection when moving to a different table --- src/Components/MainTableView/TableContent.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Components/MainTableView/TableContent.tsx b/src/Components/MainTableView/TableContent.tsx index 3122e9a..06138f4 100644 --- a/src/Components/MainTableView/TableContent.tsx +++ b/src/Components/MainTableView/TableContent.tsx @@ -102,7 +102,7 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s } // Reset TableActionview - this.setState({currentSelectedTableActionMenu: TableActionType.FILTER, hideTableActionMenu: true}); + this.setState({currentSelectedTableActionMenu: TableActionType.FILTER, hideTableActionMenu: true, selectedTableEntries: {}}); // TODO: part of reference for table column width update // console.log('cellRef: ', this.cellRef) @@ -375,7 +375,7 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s disableInsert = true; disableUpdate = true; } - else if (this.props.selectedTableType === TableType.LOOKUP || this.props.selectedTableType === TableType.PART) { + else if (this.props.selectedTableType === TableType.LOOKUP || this.props.selectedTableType === TableType.PART || Object.entries(this.state.selectedTableEntries).length > 1) { disableInsert = true; disableUpdate = true; disableDelete = true; @@ -510,7 +510,12 @@ class TableContent extends React.Component<{token: string, selectedSchemaName: s {this.props.contentData.slice(this.state.paginatorState[0], this.state.paginatorState[1]).map((entry: any) => { return ( {this.cellResizeMouseMove(event)}} onMouseUp={(event) => {this.cellResizeMouseUp(event)}}> - 0 && (this.state.currentSelectedTableActionMenu === TableActionType.DELETE || this.state.currentSelectedTableActionMenu === TableActionType.UPDATE) && !this.checkSelection(entry)} onChange={(event) => this.handleCheckedEntry(event, entry)} /> + + 0 && (this.state.currentSelectedTableActionMenu === TableActionType.DELETE || this.state.currentSelectedTableActionMenu === TableActionType.UPDATE || this.state.currentSelectedTableActionMenu === TableActionType.INSERT) && !this.checkSelection(entry)} + onChange={(event) => this.handleCheckedEntry(event, entry)} /> + {entry.map((column: any, index: number) => { return ( {column} From f0205b4ccb723b5e1cc59bca02a3340e260bd725 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Fri, 5 Feb 2021 10:42:51 -0600 Subject: [PATCH 026/325] add custom title and favicon --- public/favicon.ico | Bin 3870 -> 15086 bytes public/index.html | 6 +-- public/logo192.png | Bin 5347 -> 0 bytes public/logo512.png | Bin 9664 -> 0 bytes public/logo_icon.svg | 95 +++++++++++++++++++++++++++++++++++++++++++ public/manifest.json | 8 ++-- 6 files changed, 102 insertions(+), 7 deletions(-) delete mode 100644 public/logo192.png delete mode 100644 public/logo512.png create mode 100644 public/logo_icon.svg diff --git a/public/favicon.ico b/public/favicon.ico index a11777cc471a4344702741ab1c8a588998b1311a..6003686a61bc28477f150f68e50f57e22549bde1 100644 GIT binary patch literal 15086 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 GzW)PzzW8PU literal 3870 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 baj7?x%VD!5Cxk2YbYLNVeiXvvpMCWYo=by@ diff --git a/public/index.html b/public/index.html index aa069f2..cffbace 100644 --- a/public/index.html +++ b/public/index.html @@ -7,9 +7,9 @@ - + - React App + DataJoint GUI diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a3796c0e0a64c3d858ca038bd4570465d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5347 zcmZWtbyO6NvR-oO24RV%BvuJ&=?+<7=`LvyB&A_#M7mSDYw1v6DJkiYl9XjT!%$dLEBTQ8R9|wd3008in6lFF3GV-6mLi?MoP_y~}QUnaDCHI#t z7w^m$@6DI)|C8_jrT?q=f8D?0AM?L)Z}xAo^e^W>t$*Y0KlT5=@bBjT9kxb%-KNdk zeOS1tKO#ChhG7%{ApNBzE2ZVNcxbrin#E1TiAw#BlUhXllzhN$qWez5l;h+t^q#Eav8PhR2|T}y5kkflaK`ba-eoE+Z2q@o6P$)=&` z+(8}+-McnNO>e#$Rr{32ngsZIAX>GH??tqgwUuUz6kjns|LjsB37zUEWd|(&O!)DY zQLrq%Y>)Y8G`yYbYCx&aVHi@-vZ3|ebG!f$sTQqMgi0hWRJ^Wc+Ibv!udh_r%2|U) zPi|E^PK?UE!>_4`f`1k4hqqj_$+d!EB_#IYt;f9)fBOumGNyglU(ofY`yHq4Y?B%- zp&G!MRY<~ajTgIHErMe(Z8JG*;D-PJhd@RX@QatggM7+G(Lz8eZ;73)72Hfx5KDOE zkT(m}i2;@X2AT5fW?qVp?@WgN$aT+f_6eo?IsLh;jscNRp|8H}Z9p_UBO^SJXpZew zEK8fz|0Th%(Wr|KZBGTM4yxkA5CFdAj8=QSrT$fKW#tweUFqr0TZ9D~a5lF{)%-tTGMK^2tz(y2v$i%V8XAxIywrZCp=)83p(zIk6@S5AWl|Oa2hF`~~^W zI;KeOSkw1O#TiQ8;U7OPXjZM|KrnN}9arP)m0v$c|L)lF`j_rpG(zW1Qjv$=^|p*f z>)Na{D&>n`jOWMwB^TM}slgTEcjxTlUby89j1)|6ydRfWERn3|7Zd2&e7?!K&5G$x z`5U3uFtn4~SZq|LjFVrz$3iln-+ucY4q$BC{CSm7Xe5c1J<=%Oagztj{ifpaZk_bQ z9Sb-LaQMKp-qJA*bP6DzgE3`}*i1o3GKmo2pn@dj0;He}F=BgINo};6gQF8!n0ULZ zL>kC0nPSFzlcB7p41doao2F7%6IUTi_+!L`MM4o*#Y#0v~WiO8uSeAUNp=vA2KaR&=jNR2iVwG>7t%sG2x_~yXzY)7K& zk3p+O0AFZ1eu^T3s};B%6TpJ6h-Y%B^*zT&SN7C=N;g|#dGIVMSOru3iv^SvO>h4M=t-N1GSLLDqVTcgurco6)3&XpU!FP6Hlrmj}f$ zp95;b)>M~`kxuZF3r~a!rMf4|&1=uMG$;h^g=Kl;H&Np-(pFT9FF@++MMEx3RBsK?AU0fPk-#mdR)Wdkj)`>ZMl#^<80kM87VvsI3r_c@_vX=fdQ`_9-d(xiI z4K;1y1TiPj_RPh*SpDI7U~^QQ?%0&!$Sh#?x_@;ag)P}ZkAik{_WPB4rHyW#%>|Gs zdbhyt=qQPA7`?h2_8T;-E6HI#im9K>au*(j4;kzwMSLgo6u*}-K`$_Gzgu&XE)udQ zmQ72^eZd|vzI)~!20JV-v-T|<4@7ruqrj|o4=JJPlybwMg;M$Ud7>h6g()CT@wXm` zbq=A(t;RJ^{Xxi*Ff~!|3!-l_PS{AyNAU~t{h;(N(PXMEf^R(B+ZVX3 z8y0;0A8hJYp@g+c*`>eTA|3Tgv9U8#BDTO9@a@gVMDxr(fVaEqL1tl?md{v^j8aUv zm&%PX4^|rX|?E4^CkplWWNv*OKM>DxPa z!RJ)U^0-WJMi)Ksc!^ixOtw^egoAZZ2Cg;X7(5xZG7yL_;UJ#yp*ZD-;I^Z9qkP`} zwCTs0*%rIVF1sgLervtnUo&brwz?6?PXRuOCS*JI-WL6GKy7-~yi0giTEMmDs_-UX zo=+nFrW_EfTg>oY72_4Z0*uG>MnXP=c0VpT&*|rvv1iStW;*^={rP1y?Hv+6R6bxFMkxpWkJ>m7Ba{>zc_q zEefC3jsXdyS5??Mz7IET$Kft|EMNJIv7Ny8ZOcKnzf`K5Cd)&`-fTY#W&jnV0l2vt z?Gqhic}l}mCv1yUEy$%DP}4AN;36$=7aNI^*AzV(eYGeJ(Px-j<^gSDp5dBAv2#?; zcMXv#aj>%;MiG^q^$0MSg-(uTl!xm49dH!{X0){Ew7ThWV~Gtj7h%ZD zVN-R-^7Cf0VH!8O)uUHPL2mO2tmE*cecwQv_5CzWeh)ykX8r5Hi`ehYo)d{Jnh&3p z9ndXT$OW51#H5cFKa76c<%nNkP~FU93b5h-|Cb}ScHs@4Q#|}byWg;KDMJ#|l zE=MKD*F@HDBcX@~QJH%56eh~jfPO-uKm}~t7VkHxHT;)4sd+?Wc4* z>CyR*{w@4(gnYRdFq=^(#-ytb^5ESD?x<0Skhb%Pt?npNW1m+Nv`tr9+qN<3H1f<% zZvNEqyK5FgPsQ`QIu9P0x_}wJR~^CotL|n zk?dn;tLRw9jJTur4uWoX6iMm914f0AJfB@C74a;_qRrAP4E7l890P&{v<}>_&GLrW z)klculcg`?zJO~4;BBAa=POU%aN|pmZJn2{hA!d!*lwO%YSIzv8bTJ}=nhC^n}g(ld^rn#kq9Z3)z`k9lvV>y#!F4e{5c$tnr9M{V)0m(Z< z#88vX6-AW7T2UUwW`g<;8I$Jb!R%z@rCcGT)-2k7&x9kZZT66}Ztid~6t0jKb&9mm zpa}LCb`bz`{MzpZR#E*QuBiZXI#<`5qxx=&LMr-UUf~@dRk}YI2hbMsAMWOmDzYtm zjof16D=mc`^B$+_bCG$$@R0t;e?~UkF?7<(vkb70*EQB1rfUWXh$j)R2)+dNAH5%R zEBs^?N;UMdy}V};59Gu#0$q53$}|+q7CIGg_w_WlvE}AdqoS<7DY1LWS9?TrfmcvT zaypmplwn=P4;a8-%l^e?f`OpGb}%(_mFsL&GywhyN(-VROj`4~V~9bGv%UhcA|YW% zs{;nh@aDX11y^HOFXB$a7#Sr3cEtNd4eLm@Y#fc&j)TGvbbMwze zXtekX_wJqxe4NhuW$r}cNy|L{V=t#$%SuWEW)YZTH|!iT79k#?632OFse{+BT_gau zJwQcbH{b}dzKO?^dV&3nTILYlGw{27UJ72ZN){BILd_HV_s$WfI2DC<9LIHFmtyw? zQ;?MuK7g%Ym+4e^W#5}WDLpko%jPOC=aN)3!=8)s#Rnercak&b3ESRX3z{xfKBF8L z5%CGkFmGO@x?_mPGlpEej!3!AMddChabyf~nJNZxx!D&{@xEb!TDyvqSj%Y5@A{}9 zRzoBn0?x}=krh{ok3Nn%e)#~uh;6jpezhA)ySb^b#E>73e*frBFu6IZ^D7Ii&rsiU z%jzygxT-n*joJpY4o&8UXr2s%j^Q{?e-voloX`4DQyEK+DmrZh8A$)iWL#NO9+Y@!sO2f@rI!@jN@>HOA< z?q2l{^%mY*PNx2FoX+A7X3N}(RV$B`g&N=e0uvAvEN1W^{*W?zT1i#fxuw10%~))J zjx#gxoVlXREWZf4hRkgdHx5V_S*;p-y%JtGgQ4}lnA~MBz-AFdxUxU1RIT$`sal|X zPB6sEVRjGbXIP0U+?rT|y5+ev&OMX*5C$n2SBPZr`jqzrmpVrNciR0e*Wm?fK6DY& zl(XQZ60yWXV-|Ps!A{EF;=_z(YAF=T(-MkJXUoX zI{UMQDAV2}Ya?EisdEW;@pE6dt;j0fg5oT2dxCi{wqWJ<)|SR6fxX~5CzblPGr8cb zUBVJ2CQd~3L?7yfTpLNbt)He1D>*KXI^GK%<`bq^cUq$Q@uJifG>p3LU(!H=C)aEL zenk7pVg}0{dKU}&l)Y2Y2eFMdS(JS0}oZUuVaf2+K*YFNGHB`^YGcIpnBlMhO7d4@vV zv(@N}(k#REdul8~fP+^F@ky*wt@~&|(&&meNO>rKDEnB{ykAZ}k>e@lad7to>Ao$B zz<1(L=#J*u4_LB=8w+*{KFK^u00NAmeNN7pr+Pf+N*Zl^dO{LM-hMHyP6N!~`24jd zXYP|Ze;dRXKdF2iJG$U{k=S86l@pytLx}$JFFs8e)*Vi?aVBtGJ3JZUj!~c{(rw5>vuRF$`^p!P8w1B=O!skwkO5yd4_XuG^QVF z`-r5K7(IPSiKQ2|U9+`@Js!g6sfJwAHVd|s?|mnC*q zp|B|z)(8+mxXyxQ{8Pg3F4|tdpgZZSoU4P&9I8)nHo1@)9_9u&NcT^FI)6|hsAZFk zZ+arl&@*>RXBf-OZxhZerOr&dN5LW9@gV=oGFbK*J+m#R-|e6(Loz(;g@T^*oO)0R zN`N=X46b{7yk5FZGr#5&n1!-@j@g02g|X>MOpF3#IjZ_4wg{dX+G9eqS+Es9@6nC7 zD9$NuVJI}6ZlwtUm5cCAiYv0(Yi{%eH+}t)!E^>^KxB5^L~a`4%1~5q6h>d;paC9c zTj0wTCKrhWf+F#5>EgX`sl%POl?oyCq0(w0xoL?L%)|Q7d|Hl92rUYAU#lc**I&^6p=4lNQPa0 znQ|A~i0ip@`B=FW-Q;zh?-wF;Wl5!+q3GXDu-x&}$gUO)NoO7^$BeEIrd~1Dh{Tr` z8s<(Bn@gZ(mkIGnmYh_ehXnq78QL$pNDi)|QcT*|GtS%nz1uKE+E{7jdEBp%h0}%r zD2|KmYGiPa4;md-t_m5YDz#c*oV_FqXd85d@eub?9N61QuYcb3CnVWpM(D-^|CmkL z(F}L&N7qhL2PCq)fRh}XO@U`Yn<?TNGR4L(mF7#4u29{i~@k;pLsgl({YW5`Mo+p=zZn3L*4{JU;++dG9 X@eDJUQo;Ye2mwlRs?y0|+_a0zY+Zo%Dkae}+MySoIppb75o?vUW_?)>@g{U2`ERQIXV zeY$JrWnMZ$QC<=ii4X|@0H8`si75jB(ElJb00HAB%>SlLR{!zO|C9P3zxw_U8?1d8uRZ=({Ga4shyN}3 zAK}WA(ds|``G4jA)9}Bt2Hy0+f3rV1E6b|@?hpGA=PI&r8)ah|)I2s(P5Ic*Ndhn^ z*T&j@gbCTv7+8rpYbR^Ty}1AY)YH;p!m948r#%7x^Z@_-w{pDl|1S4`EM3n_PaXvK z1JF)E3qy$qTj5Xs{jU9k=y%SQ0>8E$;x?p9ayU0bZZeo{5Z@&FKX>}s!0+^>C^D#z z>xsCPvxD3Z=dP}TTOSJhNTPyVt14VCQ9MQFN`rn!c&_p?&4<5_PGm4a;WS&1(!qKE z_H$;dDdiPQ!F_gsN`2>`X}$I=B;={R8%L~`>RyKcS$72ai$!2>d(YkciA^J0@X%G4 z4cu!%Ps~2JuJ8ex`&;Fa0NQOq_nDZ&X;^A=oc1&f#3P1(!5il>6?uK4QpEG8z0Rhu zvBJ+A9RV?z%v?!$=(vcH?*;vRs*+PPbOQ3cdPr5=tOcLqmfx@#hOqX0iN)wTTO21jH<>jpmwRIAGw7`a|sl?9y9zRBh>(_%| zF?h|P7}~RKj?HR+q|4U`CjRmV-$mLW>MScKnNXiv{vD3&2@*u)-6P@h0A`eeZ7}71 zK(w%@R<4lLt`O7fs1E)$5iGb~fPfJ?WxhY7c3Q>T-w#wT&zW522pH-B%r5v#5y^CF zcC30Se|`D2mY$hAlIULL%-PNXgbbpRHgn<&X3N9W!@BUk@9g*P5mz-YnZBb*-$zMM z7Qq}ic0mR8n{^L|=+diODdV}Q!gwr?y+2m=3HWwMq4z)DqYVg0J~^}-%7rMR@S1;9 z7GFj6K}i32X;3*$SmzB&HW{PJ55kT+EI#SsZf}bD7nW^Haf}_gXciYKX{QBxIPSx2Ma? zHQqgzZq!_{&zg{yxqv3xq8YV+`S}F6A>Gtl39_m;K4dA{pP$BW0oIXJ>jEQ!2V3A2 zdpoTxG&V=(?^q?ZTj2ZUpDUdMb)T?E$}CI>r@}PFPWD9@*%V6;4Ag>D#h>!s)=$0R zRXvdkZ%|c}ubej`jl?cS$onl9Tw52rBKT)kgyw~Xy%z62Lr%V6Y=f?2)J|bZJ5(Wx zmji`O;_B+*X@qe-#~`HFP<{8$w@z4@&`q^Q-Zk8JG3>WalhnW1cvnoVw>*R@c&|o8 zZ%w!{Z+MHeZ*OE4v*otkZqz11*s!#s^Gq>+o`8Z5 z^i-qzJLJh9!W-;SmFkR8HEZJWiXk$40i6)7 zZpr=k2lp}SasbM*Nbn3j$sn0;rUI;%EDbi7T1ZI4qL6PNNM2Y%6{LMIKW+FY_yF3) zSKQ2QSujzNMSL2r&bYs`|i2Dnn z=>}c0>a}>|uT!IiMOA~pVT~R@bGlm}Edf}Kq0?*Af6#mW9f9!}RjW7om0c9Qlp;yK z)=XQs(|6GCadQbWIhYF=rf{Y)sj%^Id-ARO0=O^Ad;Ph+ z0?$eE1xhH?{T$QI>0JP75`r)U_$#%K1^BQ8z#uciKf(C701&RyLQWBUp*Q7eyn76} z6JHpC9}R$J#(R0cDCkXoFSp;j6{x{b&0yE@P7{;pCEpKjS(+1RQy38`=&Yxo%F=3y zCPeefABp34U-s?WmU#JJw23dcC{sPPFc2#J$ZgEN%zod}J~8dLm*fx9f6SpO zn^Ww3bt9-r0XaT2a@Wpw;C23XM}7_14#%QpubrIw5aZtP+CqIFmsG4`Cm6rfxl9n5 z7=r2C-+lM2AB9X0T_`?EW&Byv&K?HS4QLoylJ|OAF z`8atBNTzJ&AQ!>sOo$?^0xj~D(;kS$`9zbEGd>f6r`NC3X`tX)sWgWUUOQ7w=$TO&*j;=u%25ay-%>3@81tGe^_z*C7pb9y*Ed^H3t$BIKH2o+olp#$q;)_ zfpjCb_^VFg5fU~K)nf*d*r@BCC>UZ!0&b?AGk_jTPXaSnCuW110wjHPPe^9R^;jo3 zwvzTl)C`Zl5}O2}3lec=hZ*$JnkW#7enKKc)(pM${_$9Hc=Sr_A9Biwe*Y=T?~1CK z6eZ9uPICjy-sMGbZl$yQmpB&`ouS8v{58__t0$JP%i3R&%QR3ianbZqDs<2#5FdN@n5bCn^ZtH992~5k(eA|8|@G9u`wdn7bnpg|@{m z^d6Y`*$Zf2Xr&|g%sai#5}Syvv(>Jnx&EM7-|Jr7!M~zdAyjt*xl;OLhvW-a%H1m0 z*x5*nb=R5u><7lyVpNAR?q@1U59 zO+)QWwL8t zyip?u_nI+K$uh{y)~}qj?(w0&=SE^8`_WMM zTybjG=999h38Yes7}-4*LJ7H)UE8{mE(6;8voE+TYY%33A>S6`G_95^5QHNTo_;Ao ztIQIZ_}49%{8|=O;isBZ?=7kfdF8_@azfoTd+hEJKWE!)$)N%HIe2cplaK`ry#=pV z0q{9w-`i0h@!R8K3GC{ivt{70IWG`EP|(1g7i_Q<>aEAT{5(yD z=!O?kq61VegV+st@XCw475j6vS)_z@efuqQgHQR1T4;|-#OLZNQJPV4k$AX1Uk8Lm z{N*b*ia=I+MB}kWpupJ~>!C@xEN#Wa7V+7{m4j8c?)ChV=D?o~sjT?0C_AQ7B-vxqX30s0I_`2$in86#`mAsT-w?j{&AL@B3$;P z31G4(lV|b}uSDCIrjk+M1R!X7s4Aabn<)zpgT}#gE|mIvV38^ODy@<&yflpCwS#fRf9ZX3lPV_?8@C5)A;T zqmouFLFk;qIs4rA=hh=GL~sCFsXHsqO6_y~*AFt939UYVBSx1s(=Kb&5;j7cSowdE;7()CC2|-i9Zz+_BIw8#ll~-tyH?F3{%`QCsYa*b#s*9iCc`1P1oC26?`g<9))EJ3%xz+O!B3 zZ7$j~To)C@PquR>a1+Dh>-a%IvH_Y7^ys|4o?E%3`I&ADXfC8++hAdZfzIT#%C+Jz z1lU~K_vAm0m8Qk}K$F>|>RPK%<1SI0(G+8q~H zAsjezyP+u!Se4q3GW)`h`NPSRlMoBjCzNPesWJwVTY!o@G8=(6I%4XHGaSiS3MEBK zhgGFv6Jc>L$4jVE!I?TQuwvz_%CyO!bLh94nqK11C2W$*aa2ueGopG8DnBICVUORP zgytv#)49fVXDaR$SukloYC3u7#5H)}1K21=?DKj^U)8G;MS)&Op)g^zR2($<>C*zW z;X7`hLxiIO#J`ANdyAOJle4V%ppa*(+0i3w;8i*BA_;u8gOO6)MY`ueq7stBMJTB; z-a0R>hT*}>z|Gg}@^zDL1MrH+2hsR8 zHc}*9IvuQC^Ju)^#Y{fOr(96rQNPNhxc;mH@W*m206>Lo<*SaaH?~8zg&f&%YiOEG zGiz?*CP>Bci}!WiS=zj#K5I}>DtpregpP_tfZtPa(N<%vo^#WCQ5BTv0vr%Z{)0q+ z)RbfHktUm|lg&U3YM%lMUM(fu}i#kjX9h>GYctkx9Mt_8{@s%!K_EI zScgwy6%_fR?CGJQtmgNAj^h9B#zmaMDWgH55pGuY1Gv7D z;8Psm(vEPiwn#MgJYu4Ty9D|h!?Rj0ddE|&L3S{IP%H4^N!m`60ZwZw^;eg4sk6K{ ziA^`Sbl_4~f&Oo%n;8Ye(tiAdlZKI!Z=|j$5hS|D$bDJ}p{gh$KN&JZYLUjv4h{NY zBJ>X9z!xfDGY z+oh_Z&_e#Q(-}>ssZfm=j$D&4W4FNy&-kAO1~#3Im;F)Nwe{(*75(p=P^VI?X0GFakfh+X-px4a%Uw@fSbmp9hM1_~R>?Z8+ ziy|e9>8V*`OP}4x5JjdWp}7eX;lVxp5qS}0YZek;SNmm7tEeSF*-dI)6U-A%m6YvCgM(}_=k#a6o^%-K4{`B1+}O4x zztDT%hVb;v#?j`lTvlFQ3aV#zkX=7;YFLS$uIzb0E3lozs5`Xy zi~vF+%{z9uLjKvKPhP%x5f~7-Gj+%5N`%^=yk*Qn{`> z;xj&ROY6g`iy2a@{O)V(jk&8#hHACVDXey5a+KDod_Z&}kHM}xt7}Md@pil{2x7E~ zL$k^d2@Ec2XskjrN+IILw;#7((abu;OJii&v3?60x>d_Ma(onIPtcVnX@ELF0aL?T zSmWiL3(dOFkt!x=1O!_0n(cAzZW+3nHJ{2S>tgSK?~cFha^y(l@-Mr2W$%MN{#af8J;V*>hdq!gx=d0h$T7l}>91Wh07)9CTX zh2_ZdQCyFOQ)l(}gft0UZG`Sh2`x-w`5vC2UD}lZs*5 zG76$akzn}Xi))L3oGJ75#pcN=cX3!=57$Ha=hQ2^lwdyU#a}4JJOz6ddR%zae%#4& za)bFj)z=YQela(F#Y|Q#dp}PJghITwXouVaMq$BM?K%cXn9^Y@g43$=O)F&ZlOUom zJiad#dea;-eywBA@e&D6Pdso1?2^(pXiN91?jvcaUyYoKUmvl5G9e$W!okWe*@a<^ z8cQQ6cNSf+UPDx%?_G4aIiybZHHagF{;IcD(dPO!#=u zWfqLcPc^+7Uu#l(Bpxft{*4lv#*u7X9AOzDO z1D9?^jIo}?%iz(_dwLa{ex#T}76ZfN_Z-hwpus9y+4xaUu9cX}&P{XrZVWE{1^0yw zO;YhLEW!pJcbCt3L8~a7>jsaN{V3>tz6_7`&pi%GxZ=V3?3K^U+*ryLSb)8^IblJ0 zSRLNDvIxt)S}g30?s_3NX>F?NKIGrG_zB9@Z>uSW3k2es_H2kU;Rnn%j5qP)!XHKE zPB2mHP~tLCg4K_vH$xv`HbRsJwbZMUV(t=ez;Ec(vyHH)FbfLg`c61I$W_uBB>i^r z&{_P;369-&>23R%qNIULe=1~T$(DA`ev*EWZ6j(B$(te}x1WvmIll21zvygkS%vwG zzkR6Z#RKA2!z!C%M!O>!=Gr0(J0FP=-MN=5t-Ir)of50y10W}j`GtRCsXBakrKtG& zazmITDJMA0C51&BnLY)SY9r)NVTMs);1<=oosS9g31l{4ztjD3#+2H7u_|66b|_*O z;Qk6nalpqdHOjx|K&vUS_6ITgGll;TdaN*ta=M_YtyC)I9Tmr~VaPrH2qb6sd~=AcIxV+%z{E&0@y=DPArw zdV7z(G1hBx7hd{>(cr43^WF%4Y@PXZ?wPpj{OQ#tvc$pABJbvPGvdR`cAtHn)cSEV zrpu}1tJwQ3y!mSmH*uz*x0o|CS<^w%&KJzsj~DU0cLQUxk5B!hWE>aBkjJle8z~;s z-!A=($+}Jq_BTK5^B!`R>!MulZN)F=iXXeUd0w5lUsE5VP*H*oCy(;?S$p*TVvTxwAeWFB$jHyb0593)$zqalVlDX=GcCN1gU0 zlgU)I$LcXZ8Oyc2TZYTPu@-;7<4YYB-``Qa;IDcvydIA$%kHhJKV^m*-zxcvU4viy&Kr5GVM{IT>WRywKQ9;>SEiQD*NqplK-KK4YR`p0@JW)n_{TU3bt0 zim%;(m1=#v2}zTps=?fU5w^(*y)xT%1vtQH&}50ZF!9YxW=&7*W($2kgKyz1mUgfs zfV<*XVVIFnohW=|j+@Kfo!#liQR^x>2yQdrG;2o8WZR+XzU_nG=Ed2rK?ntA;K5B{ z>M8+*A4!Jm^Bg}aW?R?6;@QG@uQ8&oJ{hFixcfEnJ4QH?A4>P=q29oDGW;L;= z9-a0;g%c`C+Ai!UmK$NC*4#;Jp<1=TioL=t^YM)<<%u#hnnfSS`nq63QKGO1L8RzX z@MFDqs1z ztYmxDl@LU)5acvHk)~Z`RW7=aJ_nGD!mOSYD>5Odjn@TK#LY{jf?+piB5AM-CAoT_ z?S-*q7}wyLJzK>N%eMPuFgN)Q_otKP;aqy=D5f!7<=n(lNkYRXVpkB{TAYLYg{|(jtRqYmg$xH zjmq?B(RE4 zQx^~Pt}gxC2~l=K$$-sYy_r$CO(d=+b3H1MB*y_5g6WLaWTXn+TKQ|hNY^>Mp6k*$ zwkovomhu776vQATqT4blf~g;TY(MWCrf^^yfWJvSAB$p5l;jm@o#=!lqw+Lqfq>X= z$6~kxfm7`3q4zUEB;u4qa#BdJxO!;xGm)wwuisj{0y2x{R(IGMrsIzDY9LW>m!Y`= z04sx3IjnYvL<4JqxQ8f7qYd0s2Ig%`ytYPEMKI)s(LD}D@EY>x`VFtqvnADNBdeao zC96X+MxnwKmjpg{U&gP3HE}1=s!lv&D{6(g_lzyF3A`7Jn*&d_kL<;dAFx!UZ>hB8 z5A*%LsAn;VLp>3${0>M?PSQ)9s3}|h2e?TG4_F{}{Cs>#3Q*t$(CUc}M)I}8cPF6% z=+h(Kh^8)}gj(0}#e7O^FQ6`~fd1#8#!}LMuo3A0bN`o}PYsm!Y}sdOz$+Tegc=qT z8x`PH$7lvnhJp{kHWb22l;@7B7|4yL4UOOVM0MP_>P%S1Lnid)+k9{+3D+JFa#Pyf zhVc#&df87APl4W9X)F3pGS>@etfl=_E5tBcVoOfrD4hmVeTY-cj((pkn%n@EgN{0f zwb_^Rk0I#iZuHK!l*lN`ceJn(sI{$Fq6nN& zE<-=0_2WN}m+*ivmIOxB@#~Q-cZ>l136w{#TIJe478`KE7@=a{>SzPHsKLzYAyBQO zAtuuF$-JSDy_S@6GW0MOE~R)b;+0f%_NMrW(+V#c_d&U8Z9+ec4=HmOHw?gdjF(Lu zzra83M_BoO-1b3;9`%&DHfuUY)6YDV21P$C!Rc?mv&{lx#f8oc6?0?x zK08{WP65?#>(vPfA-c=MCY|%*1_<3D4NX zeVTi-JGl2uP_2@0F{G({pxQOXt_d{g_CV6b?jNpfUG9;8yle-^4KHRvZs-_2siata zt+d_T@U$&t*xaD22(fH(W1r$Mo?3dc%Tncm=C6{V9y{v&VT#^1L04vDrLM9qBoZ4@ z6DBN#m57hX7$C(=#$Y5$bJmwA$T8jKD8+6A!-IJwA{WOfs%s}yxUw^?MRZjF$n_KN z6`_bGXcmE#5e4Ym)aQJ)xg3Pg0@k`iGuHe?f(5LtuzSq=nS^5z>vqU0EuZ&75V%Z{ zYyhRLN^)$c6Ds{f7*FBpE;n5iglx5PkHfWrj3`x^j^t z7ntuV`g!9Xg#^3!x)l*}IW=(Tz3>Y5l4uGaB&lz{GDjm2D5S$CExLT`I1#n^lBH7Y zDgpMag@`iETKAI=p<5E#LTkwzVR@=yY|uBVI1HG|8h+d;G-qfuj}-ZR6fN>EfCCW z9~wRQoAPEa#aO?3h?x{YvV*d+NtPkf&4V0k4|L=uj!U{L+oLa(z#&iuhJr3-PjO3R z5s?=nn_5^*^Rawr>>Nr@K(jwkB#JK-=+HqwfdO<+P5byeim)wvqGlP-P|~Nse8=XF zz`?RYB|D6SwS}C+YQv+;}k6$-%D(@+t14BL@vM z2q%q?f6D-A5s$_WY3{^G0F131bbh|g!}#BKw=HQ7mx;Dzg4Z*bTLQSfo{ed{4}NZW zfrRm^Ca$rlE{Ue~uYv>R9{3smwATcdM_6+yWIO z*ZRH~uXE@#p$XTbCt5j7j2=86e{9>HIB6xDzV+vAo&B?KUiMP|ttOElepnl%|DPqL b{|{}U^kRn2wo}j7|0ATu<;8xA7zX}7|B6mN diff --git a/public/logo_icon.svg b/public/logo_icon.svg new file mode 100644 index 0000000..10b2c08 --- /dev/null +++ b/public/logo_icon.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/manifest.json b/public/manifest.json index 080d6c7..eb95a91 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "DJ GUI", + "name": "Open Source Data Viewer for DataJoint Users", "icons": [ { "src": "favicon.ico", @@ -8,12 +8,12 @@ "type": "image/x-icon" }, { - "src": "logo192.png", + "src": "logo_icon.svg", "type": "image/png", "sizes": "192x192" }, { - "src": "logo512.png", + "src": "logo_icon.svg", "type": "image/png", "sizes": "512x512" } From 61c5568fff5b2d9eb9d48c943cfa5ce29cc2bd33 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Fri, 5 Feb 2021 10:45:13 -0600 Subject: [PATCH 027/325] fix typo --- src/Components/MainTableView/InsertTuple.css | 8 ++++---- src/Components/MainTableView/InsertTuple.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Components/MainTableView/InsertTuple.css b/src/Components/MainTableView/InsertTuple.css index e26f8ed..367be17 100644 --- a/src/Components/MainTableView/InsertTuple.css +++ b/src/Components/MainTableView/InsertTuple.css @@ -17,22 +17,22 @@ form { overflow-x: auto; } -.rowControlls { +.rowControls { align-self: flex-end; display: flex; } -.rowControlls .icon { +.rowControls .icon { margin-right: 8px; color: rgb(80, 80, 80); cursor: pointer; } -.rowControlls .icon.deleteRow:hover { +.rowControls .icon.deleteRow:hover { color: rgb(151, 0, 0); } -.rowControlls .icon.addRow:hover { +.rowControls .icon.addRow:hover { color: rgb(5, 114, 5); } diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index 99c0551..322c28b 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -397,7 +397,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str

Insert

-
+
From c1075f9e3c56649982fd6baa9221e7c9a89016f7 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Fri, 5 Feb 2021 11:00:20 -0600 Subject: [PATCH 028/325] change cursor pointer for login button --- src/Components/Login.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Components/Login.css b/src/Components/Login.css index 2ac9e66..72b410c 100644 --- a/src/Components/Login.css +++ b/src/Components/Login.css @@ -77,6 +77,7 @@ button.login-input-button.ready { background-color: #4A9F5A; color: rgb(245, 245, 245); box-shadow: 1px 1px 3px rgb(124, 123, 123); + cursor: pointer; } .form-message { From e75819d8c84887114dc2edc52df81ad9da554d01 Mon Sep 17 00:00:00 2001 From: Maho Sasaki Date: Fri, 5 Feb 2021 13:19:24 -0600 Subject: [PATCH 029/325] rephrase description about the app --- public/index.html | 2 +- public/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/index.html b/public/index.html index cffbace..4affd8c 100644 --- a/public/index.html +++ b/public/index.html @@ -7,7 +7,7 @@ - DataJoint GUI + DataJoint LabBook diff --git a/public/manifest.json b/public/manifest.json index e455874..6232a90 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,5 +1,5 @@ { - "short_name": "DJ GUI", + "short_name": "DJ LabBook", "name": "Open Source GUI Application for DataJoint Users", "icons": [ { diff --git a/src/Components/Login.tsx b/src/Components/Login.tsx index cedfe1c..684aaa7 100644 --- a/src/Components/Login.tsx +++ b/src/Components/Login.tsx @@ -72,7 +72,7 @@ class Login extends Component { } // Attempt to authenticate - const response = await fetch('/api/login', { + const response = await fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/login`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ diff --git a/src/Components/MainTableView/CheckDependency.tsx b/src/Components/MainTableView/CheckDependency.tsx index 653a27d..5dd3b6b 100644 --- a/src/Components/MainTableView/CheckDependency.tsx +++ b/src/Components/MainTableView/CheckDependency.tsx @@ -67,7 +67,7 @@ class CheckDependency extends React.Component<{token: string, selectedSchemaName } } - fetch(`/api/record/dependency?schemaName=${this.props.selectedSchemaName}&tableName=${this.props.selectedTableName}&restriction=${encodeURIComponent(btoa(JSON.stringify(processedEntry)))}`, + fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/record/dependency?schemaName=${this.props.selectedSchemaName}&tableName=${this.props.selectedTableName}&restriction=${encodeURIComponent(btoa(JSON.stringify(processedEntry)))}`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token }, diff --git a/src/Components/MainTableView/DeleteTuple.tsx b/src/Components/MainTableView/DeleteTuple.tsx index f969c6d..7409785 100644 --- a/src/Components/MainTableView/DeleteTuple.tsx +++ b/src/Components/MainTableView/DeleteTuple.tsx @@ -76,7 +76,7 @@ class DeleteTuple extends React.Component<{token: string, selectedSchemaName: st this.setState({isDeletingEntry: true}) // TODO: Run api fetch for list of dependencies/permission - fetch('/api/delete_tuple', { + fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/delete_tuple`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token }, body: JSON.stringify({schemaName: this.props.selectedSchemaName, tableName: this.props.selectedTableName, restrictionTuple: processedEntry}) diff --git a/src/Components/MainTableView/InsertTuple.tsx b/src/Components/MainTableView/InsertTuple.tsx index 7b24163..1edc892 100644 --- a/src/Components/MainTableView/InsertTuple.tsx +++ b/src/Components/MainTableView/InsertTuple.tsx @@ -148,7 +148,7 @@ class InsertTuple extends React.Component<{token: string, selectedSchemaName:str } // All checks passed thus attempt insert - fetch('/api/insert_tuple', { + fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/insert_tuple`, { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token}, body: JSON.stringify({schemaName: this.props.selectedSchemaName, tableName: this.props.selectedTableName, tuple: tupleBuffer}) diff --git a/src/Components/MainTableView/TableView.tsx b/src/Components/MainTableView/TableView.tsx index addf09c..9de203b 100644 --- a/src/Components/MainTableView/TableView.tsx +++ b/src/Components/MainTableView/TableView.tsx @@ -50,7 +50,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri if (this.state.currentView === 'tableContent') { this.setState({isLoading: true}) // retrieve table headers - fetch('/api/get_table_attributes', { + fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/get_table_attributes`, { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token}, body: JSON.stringify({schemaName: this.props.selectedSchemaName, tableName: this.props.selectedTableName}) @@ -72,7 +72,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri }) } if (this.state.currentView === 'tableInfo') { - fetch('/api/get_table_definition', { + fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/get_table_definition`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token }, body: JSON.stringify({ schemaName: this.props.selectedSchemaName, tableName: this.props.selectedTableName }) @@ -98,7 +98,7 @@ class TableView extends React.Component<{token: string, selectedSchemaName: stri */ fetchTableContent(restrictions?: Array) { // Construct restriction base64 restriction from restriction - let apiUrl = '/api/fetch_tuples'; + let apiUrl = `${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/fetch_tuples`; if (restrictions !== undefined) { let restrictionsInAPIFormat = [] diff --git a/src/Components/MainTableView/UpdateTuple.tsx b/src/Components/MainTableView/UpdateTuple.tsx index 058e560..7bbf51b 100644 --- a/src/Components/MainTableView/UpdateTuple.tsx +++ b/src/Components/MainTableView/UpdateTuple.tsx @@ -163,7 +163,7 @@ class UpdateTuple extends React.Component<{token: string, selectedSchemaName:str } // All checks passed thus attempt insert - fetch('/api/update_tuple', { + fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/update_tuple`, { method: 'POST', headers: {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + this.props.token}, body: JSON.stringify({schemaName: this.props.selectedSchemaName, tableName: this.props.selectedTableName, tuple: tupleBuffer}) diff --git a/src/Components/NavBar.tsx b/src/Components/NavBar.tsx index 1811ac2..8120027 100644 --- a/src/Components/NavBar.tsx +++ b/src/Components/NavBar.tsx @@ -22,7 +22,7 @@ class NavBar extends React.Component<{hostname: string, isLoggedIn: boolean}, DJ } componentDidMount() { - fetch('/api/version', { + fetch(`${process.env.REACT_APP_DJLABBOOK_BACKEND_PREFIX}/version`, { method: 'GET', headers: {'Content-Type': 'application/json'} }) @@ -47,7 +47,7 @@ class NavBar extends React.Component<{hostname: string, isLoggedIn: boolean}, DJ return (