Skip to content

Commit

Permalink
Merge pull request #35 from HALFpipe/dev/import
Browse files Browse the repository at this point in the history
Add import button
  • Loading branch information
HippocampusGirl authored May 10, 2022
2 parents fc99854 + c4b382c commit 40fa080
Show file tree
Hide file tree
Showing 9 changed files with 2,567 additions and 3,153 deletions.
5,501 changes: 2,402 additions & 3,099 deletions package-lock.json

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,40 +25,40 @@
"./src/model/model.ts"
],
"dependencies": {
"@babel/core": "^7.17.8",
"@babel/preset-env": "^7.16.11",
"@babel/core": "^7.17.10",
"@babel/preset-env": "^7.17.10",
"@types/d3-format": "^3.0.1",
"@types/inflected": "^1.1.29",
"@types/resize-observer-browser": "^0.1.7",
"autoprefixer": "^10.4.4",
"babel-loader": "^8.2.3",
"browserslist": "^4.20.2",
"autoprefixer": "^10.4.7",
"babel-loader": "^8.2.5",
"browserslist": "^4.20.3",
"clean-webpack-plugin": "^4.0.0",
"collections": "^5.1.13",
"core-js": "^3.21.1",
"core-js": "^3.22.5",
"d3-format": "^3.1.0",
"got": "^12.0.2",
"got": "^12.0.4",
"html-webpack-plugin": "^5.5.0",
"inflected": "^2.1.0",
"node-sass": "^7.0.1",
"postcss": "^8.4.12",
"postcss": "^8.4.13",
"postcss-inline-svg": "^5.0.0",
"postcss-loader": "^6.2.1",
"postcss-normalize": "^10.0.1",
"postcss-reporter": "^7.0.5",
"postcss-value-parser": "^4.2.0",
"raw-loader": "^4.0.2",
"sass-loader": "^12.6.0",
"ts-loader": "^9.2.8",
"typescript": "^4.6.2",
"webpack": "^5.70.0",
"ts-loader": "^9.3.0",
"typescript": "^4.6.4",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2"
},
"devDependencies": {
"@types/jest": "^27.4.1",
"jest": "^27.5.1",
"prettier": "^2.6.0",
"ts-jest": "^27.1.3",
"webpack-dev-server": "^4.7.4"
"@types/jest": "^27.5.0",
"jest": "^28.1.0",
"prettier": "^2.6.2",
"ts-jest": "^28.0.2",
"webpack-dev-server": "^4.9.0"
}
}
36 changes: 36 additions & 0 deletions src/model/__tests__/database.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Database } from "../database";
import { Img } from "../dataclass";

describe("Database", () => {
const path = "report.svg";

const img1 = Img.load({sub: "01", desc: "skull_strip_report", hash: "1", path});
img1.index = 0;

const img2 = Img.load({sub: "02", desc: "skull_strip_report", hash: "2", path});
img2.index = 1;

const imgsArray = [img1, img2];

const database = new Database();
database.put(imgsArray);

it("gets closest image", () => {
let closestImg = database.closest({"sub": "01", "type": "tsnr_rpt"});
expect(closestImg.sub).toBe("01");
expect(closestImg.type).toBe("skull_strip_report");

closestImg = database.closest({"sub": "03", "type": "tsnr_rpt"});
expect(closestImg.sub).toBe("01");
expect(closestImg.type).toBe("skull_strip_report");
});

it("finds exact match", () => {
let [ exactImg ] = database.findAll({sub: "01", type: "skull_strip_report"});
expect(exactImg.hash).toBe("1");

let result = database.findAll({sub: "03"});
expect(result.length).toBe(0);
});

});
80 changes: 58 additions & 22 deletions src/model/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,37 +23,73 @@ export class Database {

put(imgsArray: Array<Img>): void {
this.imgsArray = imgsArray;

for (const img of this.imgsArray) {
for (const k of entities) {
const v = img[k];
const valuedict = this.indexSets[k];
if (!(v in valuedict)) {
valuedict[v] = new FastSet<number>();
for (const key of entities) {
const value = img[key];

const valueMap = this.indexSets[key];

if (!(value in valueMap)) {
valueMap[value] = new FastSet<number>();
}
valuedict[v].add(img.index);

valueMap[value].add(img.index);
}
}
}

closest(obj: Tagged, entities: Entity[]): Img {
let set: FastSet<number> | null = null;
for (const k of entities) {
if (obj[k] !== null && obj[k] in this.indexSets[k]) {
if (set === null) {
set = this.indexSets[k][obj[k]];
} else {
const candidateSet = set.intersection(this.indexSets[k][obj[k]]);
if (candidateSet.length === 0) {
break;
} else {
set = candidateSet;
}
matches(obj: Tagged, exact: boolean, basedOnEntities?: Entity[]): number[] | null {
basedOnEntities = basedOnEntities || [...entities];

let matches: FastSet<number> | null = null;
for (const key of basedOnEntities) {
const value = obj[key];

if (value === null) {
continue;
}
if (!(value in this.indexSets[key])) {
continue;
}

let indexSet = this.indexSets[key][value];
if (matches === null) {
matches = indexSet;
} else {
indexSet = matches.intersection(indexSet);
if (!exact && indexSet.length === 0) {
break;
}

matches = indexSet;
}
}
if (set !== null) {
return this.imgsArray[set.sorted()[0]];

if (matches === null) {
return null;
}

return matches.toArray().sort();
}

findAll(obj: Tagged): Img[] {
const matches = this.matches(obj, true);

if (matches === null) {
return Array();
}
return this.imgsArray[0]; // return default if no match

return matches.map((index) => this.imgsArray[index]);
}

closest(obj: Tagged, basedOnEntities?: Entity[]): Img {
const matches = this.matches(obj, false, basedOnEntities);

if (matches === null || matches.length < 1) {
return this.imgsArray[0]; // default if no match
}

return this.imgsArray[matches[0]];
}
}
8 changes: 7 additions & 1 deletion src/model/dataclass/img.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import {
import { keyPath } from "../key-path";
import { Indexed, Tagged } from "../types";

interface Loadable extends Tagged {
path: string;
hash: string;
desc: string;
};

export class Img implements Indexed, Tagged {
index: number;

Expand Down Expand Up @@ -60,7 +66,7 @@ export class Img implements Indexed, Tagged {
return Img.relatedImgsMap.get(this.keyPath);
}

static async load(obj: Tagged): Promise<Img | null> {
static load(obj: Loadable): Img | null {
if (!("sub" in obj)) {
console.warn("Val obj missing 'sub':", obj);
return null;
Expand Down
6 changes: 3 additions & 3 deletions src/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class Model {

static async load(): Promise<Model> {
const model = new Model();

const reportDfds: Array<Deferred> = new Array<Deferred>();
for (let i = 0; i < 4; i++) {
reportDfds.push(new Deferred());
Expand Down Expand Up @@ -95,15 +95,15 @@ export class Model {
model.preprocStatuses[sub].push(preprocStatus);

} else if ("path" in element) { // reportimgs.js
const img = await Img.load(element);
const img = Img.load(element);
if (img !== null) {
model.addImg(img);
}

} else if ("node" in element) { // reporterror.js
const nodeError = await NodeError.load(element);
const sub = nodeError.sub;

if (!(sub in model.preprocStatuses)) {
model.nodeErrors[sub] = new Array<NodeError>();
}
Expand Down
6 changes: 1 addition & 5 deletions src/view-model/ratings-view-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class RatingsViewModel {
let scanKeyPath: string = "";
let scan: Scan;
let imgRatingProperty: RatingProperty;
for (const [i, img] of this.model.imgsArray.entries()) {
for (const img of this.model.imgsArray.values()) {
if (!this.model.ratingPropertiesByHash.has(img.hash)) {
throw new Error(`RatingProperty not found for img '${img.hash}'`);
}
Expand Down Expand Up @@ -180,10 +180,6 @@ export class RatingsViewModel {
}
}

// get img(): Img {
// return
// }

set(hash: string, rating: Rating): void {
if (!this.model.ratingPropertiesByHash.has(hash)) {
throw new Error(`Unknown hash '${hash}'`);
Expand Down
4 changes: 2 additions & 2 deletions src/view/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export class Attribute {
}

// inspired by hyperscript
export function h(tag: string, attrs: Attribute[], children: Node[]): HTMLElement {
let element: HTMLElement = document.createElement(tag);
export function h<K extends keyof HTMLElementTagNameMap>(tag: K, attrs: Attribute[], children: Node[]): HTMLElementTagNameMap[K] {
let element = document.createElement(tag);

for (let attr of attrs) {
element.setAttribute(attr.key, attr.value);
Expand Down
47 changes: 42 additions & 5 deletions src/view/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,20 @@ export class Sidebar extends HTMLElement {
this.viewModel = viewModel;

const importButton = h(
"button",
"a",
[new Attribute("class", "dropdown-item")],
[t("Import...")]
);
const fileInput = h(
"input",
[
new Attribute("type", "file"),
new Attribute("hidden", ""),
new Attribute("accept", ".json"),
],
[]
);

const exportButton = h(
"a",
[
Expand All @@ -47,6 +57,7 @@ export class Sidebar extends HTMLElement {
],
[t("Export")]
);

const viewTypeButton: { [key in ViewType]?: HTMLElement } = {};
for (const viewType of viewTypes) {
viewTypeButton[viewType] = h(
Expand Down Expand Up @@ -91,7 +102,7 @@ export class Sidebar extends HTMLElement {
"ul",
[new Attribute("class", "dropdown-menu")],
[
// h("li", [], [importButton]),
h("li", [], [importButton, fileInput]),
h("li", [], [exportButton]),
h("li", [], [this.viewTypeButtonGroup]),
h("li", [], [this.sortKeyButtonGroup]),
Expand All @@ -107,9 +118,35 @@ export class Sidebar extends HTMLElement {
menuButton.classList.toggle("active");
});

// importButton.addEventListener("click", () => {
// //
// });
importButton.addEventListener("click", (e) => {
e.preventDefault();
fileInput.click();
});
fileInput.addEventListener("change", () => {
const [ file ] = fileInput.files;
const reader = new FileReader();

reader.addEventListener("load", () => {
const database = viewModel.model.database;

const objs = JSON.parse(reader.result as string);
for (const obj of objs) {
const { rating } = obj;
delete obj["rating"];

if (rating == "none") {
continue;
}

for (const img of database.findAll(obj)) {
viewModel.ratingsViewModel.set(img.hash, rating);
}
}
});

reader.readAsText(file);
});

exportButton.addEventListener("click", () => {
const objs = new Array();
for (const [hash, ratingProperty] of viewModel.model.ratingPropertiesByHash) {
Expand Down

0 comments on commit 40fa080

Please sign in to comment.