Skip to content

Commit

Permalink
Merge pull request #485 from NeurodataWithoutBorders/update-subject-t…
Browse files Browse the repository at this point in the history
…able

Subject Table Updates
  • Loading branch information
CodyCBakerPhD authored Oct 31, 2023
2 parents 9aa9233 + b5ffff2 commit 1ea2f56
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 47 deletions.
20 changes: 18 additions & 2 deletions src/renderer/src/stories/DateTimeSelector.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { LitElement, css } from "lit";

const convertToDateTimeLocalString = (date) => {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, "0");
const day = date.getDate().toString().padStart(2, "0");
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
return `${year}-${month}-${day}T${hours}:${minutes}`;
};

export class DateTimeSelector extends LitElement {
static get styles() {
return css`
Expand All @@ -15,10 +24,15 @@ export class DateTimeSelector extends LitElement {
}

set value(newValue) {
this.input.value = newValue;
if (newValue) this.input.value = newValue;
else {
const d = new Date();
d.setHours(0, 0, 0, 0);
this.input.value = convertToDateTimeLocalString(d);
}
}

constructor() {
constructor({ value } = {}) {
super();
this.input = document.createElement("input");
this.input.type = "datetime-local";
Expand All @@ -27,6 +41,8 @@ export class DateTimeSelector extends LitElement {
this.input.focus();
this.input.showPicker();
});

this.value = value ? convertToDateTimeLocalString(value) : value;
}

focus() {
Expand Down
67 changes: 52 additions & 15 deletions src/renderer/src/stories/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ const styles = `
.handsontable {
overflow: unset !important;
}
th > [data-required] > *:first-child::after {
content: '*';
margin-left: 2px;
color: gray;
}
th > [data-required=true] > *:first-child::after {
color: red;
}
`;

const styleSymbol = Symbol("table-styles");
Expand Down Expand Up @@ -105,7 +115,7 @@ export class Table extends LitElement {
let value;
if (col === this.keyColumn) {
if (hasRow) value = row;
else return "";
else return undefined;
} else
value =
(hasRow ? this.data[row][col] : undefined) ??
Expand Down Expand Up @@ -138,8 +148,8 @@ export class Table extends LitElement {

const nUnresolved = Object.keys(this.unresolved).length;
if (nUnresolved)
message = `${nUnresolved} row${nUnresolved > 1 ? "s are" : " is"} missing a${
this.keyColumn ? `${this.keyColumn} ` : "n "
message = `${nUnresolved} row${nUnresolved > 1 ? "s are" : " is"} missing a ${
this.keyColumn ? `${header(this.keyColumn)} ` : "n "
}entry`;

if (message) throw new Error(message);
Expand All @@ -149,6 +159,10 @@ export class Table extends LitElement {
onStatusChange = () => {};
onUpdate = () => {};

isRequired = (col) => {
return this.schema?.required?.includes(col);
};

updated() {
const div = (this.shadowRoot ?? this).querySelector("div");

Expand All @@ -169,13 +183,26 @@ export class Table extends LitElement {
}

// Sort Columns by Key Column and Requirement
const colHeaders = (this.colHeaders = Object.keys(entries).sort((a, b) => {
if (a === this.keyColumn) return -1;
if (b === this.keyColumn) return 1;
if (entries[a].required && !entries[b].required) return -1;
if (!entries[a].required && entries[b].required) return 1;
return 0;
}));
const colHeaders = (this.colHeaders = Object.keys(entries)
.sort((a, b) => {
//Sort alphabetically
if (a < b) return -1;
if (a > b) return 1;
return 0;
})
.sort((a, b) => {
const aRequired = this.isRequired(a);
const bRequired = this.isRequired(b);
if (aRequired && bRequired) return 0;
if (aRequired) return -1;
if (bRequired) return 1;
return 0;
})
.sort((a, b) => {
if (a === this.keyColumn) return -1;
if (b === this.keyColumn) return 1;
return 0;
}));

// Try to guess the key column if unspecified
if (!Array.isArray(this.data) && !this.keyColumn) {
Expand Down Expand Up @@ -236,7 +263,7 @@ export class Table extends LitElement {
};

let ogThis = this;
const isRequired = ogThis.schema?.required?.includes(k);
const isRequired = this.isRequired(k);

const validator = async function (value, callback) {
if (!value) {
Expand Down Expand Up @@ -282,11 +309,18 @@ export class Table extends LitElement {
return info;
});

const onAfterGetHeader = function (index, TH) {
const desc = entries[colHeaders[index]].description;
const onAfterGetHeader = (index, TH) => {
const col = colHeaders[index];
const desc = entries[col].description;

const rel = TH.querySelector(".relative");

const isRequired = this.isRequired(col);
if (isRequired) rel.setAttribute("data-required", this.validateEmptyCells ? true : undefined);

if (desc) {
const rel = TH.querySelector(".relative");
let span = rel.querySelector(".info");

if (!span) {
span = document.createElement("span");
span.classList.add("info");
Expand Down Expand Up @@ -373,7 +407,8 @@ export class Table extends LitElement {

// Transfer data to object
if (header === this.keyColumn) {
if (value !== rowName) {
console.log(value, rowName);
if (value && value !== rowName) {
const old = target[rowName] ?? {};
this.data[value] = old;
delete target[rowName];
Expand Down Expand Up @@ -407,11 +442,13 @@ export class Table extends LitElement {
table.addHook("afterRemoveRow", (_, amount, physicalRows) => {
nRows -= amount;
physicalRows.map(async (row) => {
const rowName = rowHeaders[row];
// const cols = this.data[rowHeaders[row]]
// Object.keys(cols).map(k => cols[k] = '')
// if (this.validateOnChange) Object.keys(cols).map(k => this.validateOnChange(k, { ...cols }, cols[k])) // Validate with empty values before removing
delete this.data[rowHeaders[row]];
delete unresolved[row];
this.onUpdate(rowName, null, undefined); // NOTE: Global metadata PR might simply set all data values to undefined
});
});

Expand Down
16 changes: 1 addition & 15 deletions src/renderer/src/stories/hot.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,6 @@ class DateTimeEditor extends Handsontable.editors.BaseEditor {

// Attach node to DOM, by appending it to the container holding the table
this.hot.rootElement.appendChild(this.DATETIME);

// // Immediately transfers the CopyPastePlugin FocusableWrapper element to the WC Shadow Root
const copyPastePlugin = this.hot.getPlugin("copyPaste");
const ogFn = copyPastePlugin.getOrCreateFocusableElement.bind(copyPastePlugin);
copyPastePlugin.getOrCreateFocusableElement = () => {
const res = ogFn();
const focusable = copyPastePlugin.focusableElement.getFocusableElement();
const root = this.hot.rootElement.getRootNode();
focusable.style.position = "absolute";
focusable.style.opacity = "0";
focusable.style.pointerEvents = "none";
copyPastePlugin.getOrCreateFocusableElement = ogFn;
root.append(focusable);
return res;
};
}

getValue() {
Expand Down Expand Up @@ -94,6 +79,7 @@ class ArrayEditor extends Handsontable.editors.TextEditor {

getValue() {
const value = super.getValue();

if (!value) return [];
else {
const split = value
Expand Down
37 changes: 22 additions & 15 deletions src/renderer/src/stories/pages/guided-mode/setup/GuidedSubjects.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,21 @@ export class GuidedSubjectsPage extends Page {

// Abort save if subject structure is invalid
beforeSave = () => {
this.info.globalState.subjects = merge(this.localState, this.info.globalState.subjects); // Merge the local and global states
try {
this.table.validate();
} catch (e) {
this.notify(e.message, "error");
throw e;
}

const { results, subjects } = this.info.globalState;
// Delete old subjects before merging
const { subjects: globalSubjects } = this.info.globalState;

// Object.keys(subjects).forEach((sub) => {
// if (!subjects[sub].sessions?.length) {
// delete subjects[sub]
// }
// });
for (let key in globalSubjects) {
if (!this.localState[key]) delete globalSubjects[key];
}

const noSessions = Object.keys(subjects).filter((sub) => !subjects[sub].sessions?.length);
const noSessions = Object.keys(this.localState).filter((sub) => !this.localState[sub].sessions?.length);
if (noSessions.length) {
const error = `${noSessions.length} subject${
noSessions.length > 1 ? "s are" : " is"
Expand All @@ -37,20 +41,23 @@ export class GuidedSubjectsPage extends Page {
throw new Error(error);
}

this.info.globalState.subjects = merge(this.localState, globalSubjects); // Merge the local and global states

const { results, subjects } = this.info.globalState;

// Object.keys(subjects).forEach((sub) => {
// if (!subjects[sub].sessions?.length) {
// delete subjects[sub]
// }
// });

const sourceDataObject = Object.keys(this.info.globalState.interfaces).reduce((acc, key) => {
acc[key] = {};
return acc;
}, {});

// Modify the results object to track new subjects / sessions
updateResultsFromSubjects(results, subjects, sourceDataObject); // NOTE: This directly mutates the results object

try {
this.table.validate();
} catch (e) {
this.notify(e.message, "error");
throw e;
}
};

footer = {
Expand Down

0 comments on commit 1ea2f56

Please sign in to comment.