@macrostrat/feedback-components 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -5
- package/dist/esm/feedback-components.4359bc80.js +70 -0
- package/dist/esm/feedback-components.4359bc80.js.map +1 -0
- package/dist/{extractions.54be85f8.js → esm/feedback-components.5df2a926.js} +52 -24
- package/dist/esm/feedback-components.5df2a926.js.map +1 -0
- package/dist/esm/feedback-components.6a6c8af5.js +552 -0
- package/dist/esm/feedback-components.6a6c8af5.js.map +1 -0
- package/dist/{main.module.ca3db294.js → esm/feedback-components.6d32ee91.js} +1 -1
- package/dist/{main.module.ca3db294.js.map → esm/feedback-components.6d32ee91.js.map} +1 -1
- package/dist/esm/feedback-components.7cd9b6cc.js +114 -0
- package/dist/esm/feedback-components.7cd9b6cc.js.map +1 -0
- package/dist/{node.30d0b8c3.js → esm/feedback-components.87533431.js} +12 -7
- package/dist/esm/feedback-components.87533431.js.map +1 -0
- package/dist/esm/feedback-components.921dcd46.js +241 -0
- package/dist/esm/feedback-components.921dcd46.js.map +1 -0
- package/dist/{type-selector.e75dd247.js → esm/feedback-components.ad9f284e.js} +11 -10
- package/dist/esm/feedback-components.ad9f284e.js.map +1 -0
- package/dist/esm/feedback-components.b7d9b015.css +156 -0
- package/dist/esm/feedback-components.b7d9b015.css.map +1 -0
- package/dist/{edit-state.e8edb13a.js → esm/feedback-components.bf5f7cf7.js} +105 -14
- package/dist/esm/feedback-components.bf5f7cf7.js.map +1 -0
- package/dist/{main.module.f9f92ece.css → esm/feedback-components.bf93773c.css} +1 -1
- package/dist/{main.module.f9f92ece.css.map → esm/feedback-components.bf93773c.css.map} +1 -1
- package/dist/{main.module.d6508c0e.css → esm/feedback-components.e273ed5b.css} +1 -1
- package/dist/{main.module.d6508c0e.css.map → esm/feedback-components.e273ed5b.css.map} +1 -1
- package/dist/{main.module.21bbfaf4.js → esm/feedback-components.f9850d85.js} +1 -1
- package/dist/{main.module.21bbfaf4.js.map → esm/feedback-components.f9850d85.js.map} +1 -1
- package/dist/{index.d.ts → esm/index.d.ts} +38 -13
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/{index.js → esm/index.js} +2 -2
- package/dist/node/feedback-components.15e1316d.js +2 -0
- package/dist/node/feedback-components.15e1316d.js.map +1 -0
- package/dist/node/feedback-components.2f391fa4.js +2 -0
- package/dist/node/feedback-components.2f391fa4.js.map +1 -0
- package/dist/node/feedback-components.65d8488e.js +2 -0
- package/dist/node/feedback-components.65d8488e.js.map +1 -0
- package/dist/node/feedback-components.6681dbde.js +2 -0
- package/dist/node/feedback-components.6681dbde.js.map +1 -0
- package/dist/node/feedback-components.77b6fc89.css +2 -0
- package/dist/node/feedback-components.77b6fc89.css.map +1 -0
- package/dist/node/feedback-components.794f429b.js +2 -0
- package/dist/node/feedback-components.794f429b.js.map +1 -0
- package/dist/node/feedback-components.7caa447a.js +2 -0
- package/dist/node/feedback-components.7caa447a.js.map +1 -0
- package/dist/node/feedback-components.83c21466.css +2 -0
- package/dist/node/feedback-components.83c21466.css.map +1 -0
- package/dist/node/feedback-components.8b03e8be.js +2 -0
- package/dist/node/feedback-components.8b03e8be.js.map +1 -0
- package/dist/node/feedback-components.9eb1d41a.css +2 -0
- package/dist/node/feedback-components.9eb1d41a.css.map +1 -0
- package/dist/node/feedback-components.acac789b.js +2 -0
- package/dist/node/feedback-components.acac789b.js.map +1 -0
- package/dist/node/feedback-components.e2f3c4b7.js +2 -0
- package/dist/node/feedback-components.e2f3c4b7.js.map +1 -0
- package/dist/node/feedback-components.e8aa70b8.js +2 -0
- package/dist/node/feedback-components.e8aa70b8.js.map +1 -0
- package/dist/node/index.js +2 -0
- package/dist/node/index.js.map +1 -0
- package/package.json +29 -15
- package/src/extractions/index.ts +76 -21
- package/src/extractions/types.ts +6 -1
- package/src/feedback/edit-state.ts +146 -16
- package/src/feedback/feedback.module.sass +93 -1
- package/src/feedback/graph.ts +71 -30
- package/src/feedback/index.ts +444 -71
- package/src/feedback/node.ts +7 -1
- package/src/feedback/text-visualizer.ts +258 -47
- package/src/feedback/type-selector/index.ts +4 -2
- package/dist/edit-state.e8edb13a.js.map +0 -1
- package/dist/extractions.54be85f8.js.map +0 -1
- package/dist/feedback.46c2b5c4.js +0 -252
- package/dist/feedback.46c2b5c4.js.map +0 -1
- package/dist/feedback.module.7e16830e.css +0 -44
- package/dist/feedback.module.7e16830e.css.map +0 -1
- package/dist/feedback.module.c28cbac7.js +0 -28
- package/dist/feedback.module.c28cbac7.js.map +0 -1
- package/dist/graph.cb42b871.js +0 -83
- package/dist/graph.cb42b871.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/node.30d0b8c3.js.map +0 -1
- package/dist/text-visualizer.77af0d24.js +0 -101
- package/dist/text-visualizer.77af0d24.js.map +0 -1
- package/dist/type-selector.e75dd247.js.map +0 -1
- package/stories/feedback.stories.ts +0 -40
- package/stories/test-data.ts +0 -330
- /package/dist/{index.js.map → esm/index.js.map} +0 -0
package/src/extractions/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Entity, EntityExt, Highlight, EntityType } from "./types";
|
|
|
5
5
|
import { CSSProperties } from "react";
|
|
6
6
|
import { asChromaColor } from "@macrostrat/color-utils";
|
|
7
7
|
import hyper from "@macrostrat/hyper";
|
|
8
|
+
import { useDarkMode } from "@macrostrat/ui-components";
|
|
8
9
|
|
|
9
10
|
export type { Entity, EntityExt };
|
|
10
11
|
|
|
@@ -12,7 +13,7 @@ const h = hyper.styled(styles);
|
|
|
12
13
|
|
|
13
14
|
export function buildHighlights(
|
|
14
15
|
entities: EntityExt[],
|
|
15
|
-
parent: EntityExt | null
|
|
16
|
+
parent: EntityExt | null,
|
|
16
17
|
): Highlight[] {
|
|
17
18
|
let highlights = [];
|
|
18
19
|
let parents = [];
|
|
@@ -25,8 +26,8 @@ export function buildHighlights(
|
|
|
25
26
|
start: entity.indices[0],
|
|
26
27
|
end: entity.indices[1],
|
|
27
28
|
text: entity.name,
|
|
28
|
-
backgroundColor: entity.type
|
|
29
|
-
tag: entity.type
|
|
29
|
+
backgroundColor: entity.type?.color,
|
|
30
|
+
tag: entity.type?.name ?? "lith",
|
|
30
31
|
id: entity.id,
|
|
31
32
|
parents,
|
|
32
33
|
});
|
|
@@ -40,17 +41,21 @@ export function enhanceData(extractionData, models, entityTypes) {
|
|
|
40
41
|
...extractionData,
|
|
41
42
|
model: models.get(extractionData.model_id),
|
|
42
43
|
entities: extractionData.entities?.map((d) =>
|
|
43
|
-
enhanceEntity(d, entityTypes)
|
|
44
|
+
enhanceEntity(d, entityTypes),
|
|
44
45
|
),
|
|
45
46
|
};
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export function getTagStyle(
|
|
49
50
|
baseColor: string,
|
|
50
|
-
options: { highlighted?: boolean; inDarkMode?: boolean; active?: boolean }
|
|
51
|
+
options: { highlighted?: boolean; inDarkMode?: boolean; active?: boolean },
|
|
51
52
|
): CSSProperties {
|
|
52
|
-
const _baseColor = asChromaColor(baseColor ?? "#
|
|
53
|
-
const {
|
|
53
|
+
const _baseColor = asChromaColor(baseColor ?? "#fff");
|
|
54
|
+
const {
|
|
55
|
+
highlighted = true,
|
|
56
|
+
inDarkMode = useDarkMode().isEnabled,
|
|
57
|
+
active = false,
|
|
58
|
+
} = options;
|
|
54
59
|
|
|
55
60
|
let mixAmount = highlighted ? 0.8 : 0.5;
|
|
56
61
|
let backgroundAlpha = highlighted ? 0.8 : 0.2;
|
|
@@ -60,27 +65,38 @@ export function getTagStyle(
|
|
|
60
65
|
backgroundAlpha = 1;
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
const mixTarget =
|
|
68
|
+
const mixTarget = "black";
|
|
64
69
|
|
|
65
|
-
const color = _baseColor.mix(mixTarget, mixAmount).
|
|
70
|
+
const color = active ? "#000" : _baseColor.mix(mixTarget, mixAmount).hex();
|
|
66
71
|
const borderColor = highlighted
|
|
67
|
-
? _baseColor.mix(mixTarget, mixAmount /
|
|
72
|
+
? _baseColor.mix(mixTarget, mixAmount / 1.1).hex()
|
|
68
73
|
: "transparent";
|
|
69
74
|
|
|
75
|
+
let backgroundColor = active
|
|
76
|
+
? _baseColor.alpha(backgroundAlpha).hex()
|
|
77
|
+
: normalizeColor(_baseColor.alpha(backgroundAlpha).hex());
|
|
78
|
+
|
|
79
|
+
// handle white backgrounds in light mode
|
|
80
|
+
if (!inDarkMode && backgroundColor === "#ffffff") {
|
|
81
|
+
console.log("Adjusting background color for light mode:", backgroundColor);
|
|
82
|
+
backgroundColor = "#f0f0f0";
|
|
83
|
+
}
|
|
84
|
+
|
|
70
85
|
return {
|
|
71
86
|
color,
|
|
72
|
-
backgroundColor
|
|
87
|
+
backgroundColor,
|
|
73
88
|
boxSizing: "border-box",
|
|
74
89
|
borderStyle: "solid",
|
|
75
90
|
borderColor,
|
|
76
|
-
borderWidth: "
|
|
91
|
+
borderWidth: "1.5px",
|
|
77
92
|
fontWeight: active ? "bold" : "normal",
|
|
93
|
+
fontSize: "0.9em",
|
|
78
94
|
};
|
|
79
95
|
}
|
|
80
96
|
|
|
81
97
|
function enhanceEntity(
|
|
82
98
|
entity: Entity,
|
|
83
|
-
entityTypes: Map<number, EntityType
|
|
99
|
+
entityTypes: Map<number, EntityType>,
|
|
84
100
|
): EntityExt {
|
|
85
101
|
return {
|
|
86
102
|
...entity,
|
|
@@ -90,8 +106,8 @@ function enhanceEntity(
|
|
|
90
106
|
}
|
|
91
107
|
|
|
92
108
|
function addColor(entityType: EntityType, match = false) {
|
|
93
|
-
const color = asChromaColor(entityType.color ?? "#
|
|
94
|
-
match ? 1 : 2
|
|
109
|
+
const color = asChromaColor(entityType.color ?? "#fff").brighten(
|
|
110
|
+
match ? 1 : 2,
|
|
95
111
|
);
|
|
96
112
|
|
|
97
113
|
return { ...entityType, color: color.css() };
|
|
@@ -113,7 +129,7 @@ export function ExtractionContext({
|
|
|
113
129
|
h(ModelInfo, { data: data.model }),
|
|
114
130
|
h(
|
|
115
131
|
"ul.entities",
|
|
116
|
-
data.entities.map((d) => h(ExtractionInfo, { data: d, matchComponent }))
|
|
132
|
+
data.entities.map((d) => h(ExtractionInfo, { data: d, matchComponent })),
|
|
117
133
|
),
|
|
118
134
|
]);
|
|
119
135
|
}
|
|
@@ -140,15 +156,16 @@ export function EntityTag({
|
|
|
140
156
|
matchComponent = null,
|
|
141
157
|
}: EntityTagProps) {
|
|
142
158
|
const { name, type, match } = data;
|
|
159
|
+
|
|
143
160
|
const className = classNames(
|
|
144
161
|
{
|
|
145
162
|
matched: match != null,
|
|
146
|
-
type: data.type
|
|
163
|
+
type: data.type?.name ?? "lith",
|
|
147
164
|
},
|
|
148
|
-
"entity"
|
|
165
|
+
"entity",
|
|
149
166
|
);
|
|
150
167
|
|
|
151
|
-
const style = getTagStyle(type
|
|
168
|
+
const style = getTagStyle(type?.color, { highlighted, active });
|
|
152
169
|
|
|
153
170
|
let _matchLink = null;
|
|
154
171
|
if (match != null && matchComponent != null) {
|
|
@@ -168,7 +185,7 @@ export function EntityTag({
|
|
|
168
185
|
}
|
|
169
186
|
},
|
|
170
187
|
},
|
|
171
|
-
[type
|
|
188
|
+
[type?.name, _matchLink],
|
|
172
189
|
),
|
|
173
190
|
]);
|
|
174
191
|
}
|
|
@@ -187,7 +204,7 @@ function ExtractionInfo({
|
|
|
187
204
|
h.if(children.length > 0)([
|
|
188
205
|
h(
|
|
189
206
|
"ul.children",
|
|
190
|
-
children.map((d) => h(ExtractionInfo, { data: d, matchComponent }))
|
|
207
|
+
children.map((d) => h(ExtractionInfo, { data: d, matchComponent })),
|
|
191
208
|
),
|
|
192
209
|
]),
|
|
193
210
|
]);
|
|
@@ -217,3 +234,41 @@ function HighlightedText(props: { text: string; highlights: Highlight[] }) {
|
|
|
217
234
|
parts.push(text.slice(start));
|
|
218
235
|
return h("span", parts);
|
|
219
236
|
}
|
|
237
|
+
|
|
238
|
+
function normalizeColor(hex8) {
|
|
239
|
+
const background = useDarkMode().isEnabled ? "#000000" : "#ffffff";
|
|
240
|
+
|
|
241
|
+
const r = parseInt(hex8.slice(1, 3), 16);
|
|
242
|
+
const g = parseInt(hex8.slice(3, 5), 16);
|
|
243
|
+
const b = parseInt(hex8.slice(5, 7), 16);
|
|
244
|
+
const a = parseInt(hex8.slice(7, 9), 16) / 255;
|
|
245
|
+
|
|
246
|
+
const bgR = parseInt(background.slice(1, 3), 16);
|
|
247
|
+
const bgG = parseInt(background.slice(3, 5), 16);
|
|
248
|
+
const bgB = parseInt(background.slice(5, 7), 16);
|
|
249
|
+
|
|
250
|
+
const blend = (fg, bg) => Math.round((1 - a) * bg + a * fg);
|
|
251
|
+
|
|
252
|
+
const blendedR = blend(r, bgR);
|
|
253
|
+
const blendedG = blend(g, bgG);
|
|
254
|
+
const blendedB = blend(b, bgB);
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
"#" +
|
|
258
|
+
blendedR.toString(16).padStart(2, "0") +
|
|
259
|
+
blendedG.toString(16).padStart(2, "0") +
|
|
260
|
+
blendedB.toString(16).padStart(2, "0")
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function isHighlighted(id: number, selectedNodes: number[], nodes: any[]) {
|
|
265
|
+
if (selectedNodes?.length === 0) return true;
|
|
266
|
+
return (
|
|
267
|
+
selectedNodes?.includes(id) ||
|
|
268
|
+
nodes?.some(
|
|
269
|
+
(node) =>
|
|
270
|
+
selectedNodes?.includes(node.id) &&
|
|
271
|
+
node.children.some((child) => child.id === id),
|
|
272
|
+
)
|
|
273
|
+
);
|
|
274
|
+
}
|
package/src/extractions/types.ts
CHANGED
|
@@ -38,15 +38,25 @@ type TreeAction =
|
|
|
38
38
|
| { type: "select-entity-type"; payload: EntityType }
|
|
39
39
|
| { type: "toggle-entity-type-selector"; payload?: boolean | null }
|
|
40
40
|
| { type: "deselect" }
|
|
41
|
-
| { type: "reset" }
|
|
41
|
+
| { type: "reset" }
|
|
42
|
+
| { type: "delete-entity-type"; payload: { id: number } }
|
|
43
|
+
| {
|
|
44
|
+
type: "add-entity-type";
|
|
45
|
+
payload: { name: string; description: string; color: string };
|
|
46
|
+
}
|
|
47
|
+
| {
|
|
48
|
+
type: "update-entity-type";
|
|
49
|
+
payload: { id: number; name: string; description: string; color: string };
|
|
50
|
+
};
|
|
42
51
|
|
|
43
52
|
export type TreeDispatch = Dispatch<TreeAction>;
|
|
44
53
|
|
|
45
54
|
export function useUpdatableTree(
|
|
46
55
|
initialTree: TreeData[],
|
|
47
|
-
entityTypes: Map<number, EntityType
|
|
56
|
+
entityTypes: Map<number, EntityType>,
|
|
48
57
|
): [TreeState, TreeDispatch] {
|
|
49
58
|
// Get the first entity type
|
|
59
|
+
// issue: grabs second entity instead of selected one
|
|
50
60
|
const type = entityTypes.values().next().value;
|
|
51
61
|
|
|
52
62
|
return useReducer(treeReducer, {
|
|
@@ -72,13 +82,63 @@ export function useTreeDispatch() {
|
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
function treeReducer(state: TreeState, action: TreeAction) {
|
|
75
|
-
console.log(action);
|
|
76
85
|
switch (action.type) {
|
|
86
|
+
case "add-entity-type": {
|
|
87
|
+
// Add a new entity type to the map
|
|
88
|
+
const { name, description, color } = action.payload;
|
|
89
|
+
const newId = state.lastInternalId - 1;
|
|
90
|
+
const newType: EntityType = {
|
|
91
|
+
id: newId,
|
|
92
|
+
name,
|
|
93
|
+
description: description === "" ? null : description,
|
|
94
|
+
color,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const newEntityTypesMap = new Map(state.entityTypesMap);
|
|
98
|
+
newEntityTypesMap.set(newId, newType);
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
...state,
|
|
102
|
+
entityTypesMap: newEntityTypesMap,
|
|
103
|
+
selectedEntityType: newType,
|
|
104
|
+
lastInternalId: newId,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
case "update-entity-type": {
|
|
108
|
+
// Update an existing entity type in the map
|
|
109
|
+
const { id, name, description, color } = action.payload;
|
|
110
|
+
const newEntityTypesMap = new Map(state.entityTypesMap);
|
|
111
|
+
const oldType = newEntityTypesMap.get(id);
|
|
112
|
+
|
|
113
|
+
if (!oldType) {
|
|
114
|
+
console.warn(`Entity type with id ${id} not found`);
|
|
115
|
+
return state;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const updatedType: EntityType = {
|
|
119
|
+
...oldType,
|
|
120
|
+
name,
|
|
121
|
+
description: description === "" ? null : description,
|
|
122
|
+
color,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
newEntityTypesMap.set(id, updatedType);
|
|
126
|
+
|
|
127
|
+
// Update the tree to reflect the new type
|
|
128
|
+
const newTree = updateTreeTypes(state.tree, oldType, updatedType);
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
...state,
|
|
132
|
+
tree: newTree,
|
|
133
|
+
entityTypesMap: newEntityTypesMap,
|
|
134
|
+
selectedEntityType: updatedType,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
77
137
|
case "move-node":
|
|
78
138
|
// For each node in the tree, if the node is in the dragIds, remove it from the tree and collect it
|
|
79
139
|
const [newTree, removedNodes] = removeNodes(
|
|
80
140
|
state.tree,
|
|
81
|
-
action.payload.dragIds
|
|
141
|
+
action.payload.dragIds,
|
|
82
142
|
);
|
|
83
143
|
|
|
84
144
|
let keyPath: (number | "children")[] = [];
|
|
@@ -97,7 +157,7 @@ function treeReducer(state: TreeState, action: TreeAction) {
|
|
|
97
157
|
// For each node in the tree, if the node is in the ids, remove it from the tree
|
|
98
158
|
const [newTree2, _removedNodes] = removeNodes(
|
|
99
159
|
state.tree,
|
|
100
|
-
action.payload.ids
|
|
160
|
+
action.payload.ids,
|
|
101
161
|
);
|
|
102
162
|
// Get children of the removed nodes
|
|
103
163
|
// If children are not present elsewhere in the tree, insert them
|
|
@@ -112,21 +172,39 @@ function treeReducer(state: TreeState, action: TreeAction) {
|
|
|
112
172
|
...state,
|
|
113
173
|
tree: [...newTree2, ...children],
|
|
114
174
|
selectedNodes: state.selectedNodes.filter(
|
|
115
|
-
(id) => !action.payload.ids.includes(id)
|
|
175
|
+
(id) => !action.payload.ids.includes(id),
|
|
116
176
|
),
|
|
117
177
|
};
|
|
118
178
|
case "select-node":
|
|
119
179
|
const { ids } = action.payload;
|
|
120
|
-
|
|
180
|
+
|
|
181
|
+
const type =
|
|
182
|
+
action.payload.ids.length > 0
|
|
183
|
+
? findNodeById(state.tree, ids[0])?.type
|
|
184
|
+
: null;
|
|
185
|
+
|
|
186
|
+
console.log("Selecting nodes:", ids, "Type:", type);
|
|
187
|
+
|
|
188
|
+
return { ...state, selectedNodes: ids, selectedEntityType: type };
|
|
121
189
|
// otherwise fall through to toggle-node-selected for a single ID
|
|
122
190
|
case "toggle-node-selected":
|
|
123
191
|
const nodesToAdd = action.payload.ids.filter(
|
|
124
|
-
(id) => !state.selectedNodes.includes(id)
|
|
192
|
+
(id) => !state.selectedNodes.includes(id),
|
|
125
193
|
);
|
|
126
194
|
const nodesToKeep = state.selectedNodes.filter(
|
|
127
|
-
(id) => !action.payload.ids.includes(id)
|
|
195
|
+
(id) => !action.payload.ids.includes(id),
|
|
128
196
|
);
|
|
129
|
-
|
|
197
|
+
|
|
198
|
+
const newType =
|
|
199
|
+
action.payload.ids.length > 0
|
|
200
|
+
? findNodeById(state.tree, action.payload.ids[0])?.type
|
|
201
|
+
: null;
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
...state,
|
|
205
|
+
selectedNodes: [...nodesToKeep, ...nodesToAdd],
|
|
206
|
+
selectedEntityType: newType,
|
|
207
|
+
};
|
|
130
208
|
|
|
131
209
|
case "create-node":
|
|
132
210
|
const newId = state.lastInternalId - 1;
|
|
@@ -146,6 +224,25 @@ function treeReducer(state: TreeState, action: TreeAction) {
|
|
|
146
224
|
lastInternalId: newId,
|
|
147
225
|
};
|
|
148
226
|
|
|
227
|
+
case "delete-entity-type": {
|
|
228
|
+
// Remove the entity type from the map
|
|
229
|
+
console.log("Deleting entity type:", action.payload.id);
|
|
230
|
+
const { id } = action.payload;
|
|
231
|
+
const newEntityTypesMap = new Map(state.entityTypesMap);
|
|
232
|
+
const oldType = newEntityTypesMap.get(id);
|
|
233
|
+
newEntityTypesMap.delete(id);
|
|
234
|
+
|
|
235
|
+
const defaultType = newEntityTypesMap.values().next().value;
|
|
236
|
+
const newTree = updateTreeTypes(state.tree, oldType, defaultType);
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
...state,
|
|
240
|
+
tree: newTree,
|
|
241
|
+
entityTypesMap: newEntityTypesMap,
|
|
242
|
+
selectedNodes: [],
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
149
246
|
/** Entity type selection */
|
|
150
247
|
case "toggle-entity-type-selector":
|
|
151
248
|
return {
|
|
@@ -197,7 +294,7 @@ function nodeIsInTree(tree: TreeData[], id: number): boolean {
|
|
|
197
294
|
|
|
198
295
|
function buildNestedSpec(
|
|
199
296
|
keyPath: (number | "children")[],
|
|
200
|
-
innerSpec: Spec<any
|
|
297
|
+
innerSpec: Spec<any>,
|
|
201
298
|
): Spec<TreeData[]> {
|
|
202
299
|
// Build a nested object from a key path
|
|
203
300
|
|
|
@@ -211,7 +308,7 @@ function buildNestedSpec(
|
|
|
211
308
|
|
|
212
309
|
function findNode(
|
|
213
310
|
tree: TreeData[],
|
|
214
|
-
id: number
|
|
311
|
+
id: number,
|
|
215
312
|
): (number | "children")[] | null {
|
|
216
313
|
// Find the index of the node with the given id in the tree, returning the key path
|
|
217
314
|
for (let i = 0; i < tree.length; i++) {
|
|
@@ -229,7 +326,7 @@ function findNode(
|
|
|
229
326
|
|
|
230
327
|
function removeNodes(
|
|
231
328
|
tree: TreeData[],
|
|
232
|
-
ids: number[]
|
|
329
|
+
ids: number[],
|
|
233
330
|
): [TreeData[], TreeData[]] {
|
|
234
331
|
/** Remove nodes with the given ids from the tree and return the new tree and the removed nodes */
|
|
235
332
|
let newTree: TreeData[] = [];
|
|
@@ -259,6 +356,8 @@ export interface EntityOutput {
|
|
|
259
356
|
name: string;
|
|
260
357
|
match: any | null;
|
|
261
358
|
reasoning: string | null;
|
|
359
|
+
color: string | null;
|
|
360
|
+
children: any[] | null;
|
|
262
361
|
}
|
|
263
362
|
|
|
264
363
|
export interface GraphData {
|
|
@@ -279,15 +378,17 @@ export function treeToGraph(tree: TreeData[]): GraphData {
|
|
|
279
378
|
continue;
|
|
280
379
|
}
|
|
281
380
|
|
|
282
|
-
const { indices, id, name } = node;
|
|
381
|
+
const { indices, id, name, type, children } = node;
|
|
283
382
|
|
|
284
383
|
const nodeData: EntityOutput = {
|
|
285
384
|
id,
|
|
286
|
-
type:
|
|
385
|
+
type: type.id,
|
|
386
|
+
color: type.color,
|
|
287
387
|
name,
|
|
288
388
|
txt_range: [indices],
|
|
289
389
|
reasoning: null,
|
|
290
390
|
match: node.match,
|
|
391
|
+
children,
|
|
291
392
|
};
|
|
292
393
|
|
|
293
394
|
nodeMap.set(node.id, node);
|
|
@@ -300,7 +401,7 @@ export function treeToGraph(tree: TreeData[]): GraphData {
|
|
|
300
401
|
|
|
301
402
|
// Now process the children
|
|
302
403
|
const { nodes: childNodes, edges: childEdges } = treeToGraph(
|
|
303
|
-
node.children
|
|
404
|
+
node.children,
|
|
304
405
|
);
|
|
305
406
|
nodes.push(...childNodes);
|
|
306
407
|
edges.push(...childEdges);
|
|
@@ -309,3 +410,32 @@ export function treeToGraph(tree: TreeData[]): GraphData {
|
|
|
309
410
|
|
|
310
411
|
return { nodes, edges };
|
|
311
412
|
}
|
|
413
|
+
|
|
414
|
+
function findNodeById(tree, id) {
|
|
415
|
+
for (const node of tree) {
|
|
416
|
+
if (node.id === id) {
|
|
417
|
+
return node;
|
|
418
|
+
}
|
|
419
|
+
if (node.children) {
|
|
420
|
+
const found = findNodeById(node.children, id);
|
|
421
|
+
if (found) return found;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function updateTreeTypes(tree, oldType, defaultType) {
|
|
428
|
+
return tree.map((node) => updateNodeType(node, oldType, defaultType));
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function updateNodeType(node, oldType, defaultType) {
|
|
432
|
+
const type = node.type.id === oldType.id ? defaultType : node.type;
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
...node,
|
|
436
|
+
type,
|
|
437
|
+
children: node.children
|
|
438
|
+
? updateTreeTypes(node.children, oldType, defaultType)
|
|
439
|
+
: [],
|
|
440
|
+
};
|
|
441
|
+
}
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
.node
|
|
9
9
|
cursor: pointer
|
|
10
10
|
|
|
11
|
+
circle
|
|
12
|
+
cursor: pointer
|
|
13
|
+
border: 1px solid black
|
|
11
14
|
|
|
15
|
+
.selected
|
|
16
|
+
border: 1px solid white
|
|
17
|
+
|
|
12
18
|
.feedback-text
|
|
13
19
|
margin-bottom: 2em
|
|
14
20
|
|
|
@@ -17,7 +23,6 @@
|
|
|
17
23
|
max-height: 600px
|
|
18
24
|
|
|
19
25
|
.control-panel
|
|
20
|
-
max-width: 15em
|
|
21
26
|
position: absolute
|
|
22
27
|
top: 1em
|
|
23
28
|
right: 1em
|
|
@@ -35,3 +40,90 @@
|
|
|
35
40
|
.selection-tree
|
|
36
41
|
margin: -1em 0
|
|
37
42
|
padding: 1em 0
|
|
43
|
+
width: 70% !important
|
|
44
|
+
|
|
45
|
+
.type-list
|
|
46
|
+
display: grid
|
|
47
|
+
grid-auto-flow: column
|
|
48
|
+
grid-template-rows: repeat(10, auto)
|
|
49
|
+
gap: 0.2em
|
|
50
|
+
|
|
51
|
+
.type-tag
|
|
52
|
+
padding: .2em .5em
|
|
53
|
+
border-radius: .2em
|
|
54
|
+
|
|
55
|
+
.description
|
|
56
|
+
max-width: 300px
|
|
57
|
+
padding: .5em
|
|
58
|
+
|
|
59
|
+
mark
|
|
60
|
+
border-radius: .2em
|
|
61
|
+
cursor: pointer
|
|
62
|
+
color: black !important
|
|
63
|
+
|
|
64
|
+
[role="treeitem"]
|
|
65
|
+
width: auto !important
|
|
66
|
+
|
|
67
|
+
.highlight
|
|
68
|
+
cursor: pointer
|
|
69
|
+
padding: .2em 0
|
|
70
|
+
border-radius: .2em
|
|
71
|
+
position: relative
|
|
72
|
+
zIndex: 10
|
|
73
|
+
|
|
74
|
+
.feedback-text-wrapper
|
|
75
|
+
position: relative
|
|
76
|
+
z-index: 0
|
|
77
|
+
overflow: visible
|
|
78
|
+
|
|
79
|
+
.type-container
|
|
80
|
+
display: flex
|
|
81
|
+
justify-content: space-between
|
|
82
|
+
align-items: center
|
|
83
|
+
column-gap: 1em
|
|
84
|
+
|
|
85
|
+
.add-type
|
|
86
|
+
cursor: pointer
|
|
87
|
+
display: flex
|
|
88
|
+
justify-content: space-between
|
|
89
|
+
padding: 0 .5em
|
|
90
|
+
align-items: center
|
|
91
|
+
|
|
92
|
+
p
|
|
93
|
+
margin: 0
|
|
94
|
+
|
|
95
|
+
.overlay-container
|
|
96
|
+
height: 80vh
|
|
97
|
+
width: 100vw
|
|
98
|
+
display: flex
|
|
99
|
+
justify-content: center
|
|
100
|
+
align-items: center
|
|
101
|
+
|
|
102
|
+
.add-type-overlay
|
|
103
|
+
background-color: var(--secondary-color)
|
|
104
|
+
padding: .5em 1em
|
|
105
|
+
display: flex
|
|
106
|
+
flex-direction: column
|
|
107
|
+
gap: 1em
|
|
108
|
+
border-radius: .2em
|
|
109
|
+
|
|
110
|
+
.title
|
|
111
|
+
display: flex
|
|
112
|
+
justify-content: space-between
|
|
113
|
+
align-items: center
|
|
114
|
+
|
|
115
|
+
h2
|
|
116
|
+
margin: 0
|
|
117
|
+
|
|
118
|
+
.form-group
|
|
119
|
+
display: flex
|
|
120
|
+
gap: 3em
|
|
121
|
+
|
|
122
|
+
.text-inputs
|
|
123
|
+
display: flex
|
|
124
|
+
flex-direction: column
|
|
125
|
+
gap: 1em
|
|
126
|
+
|
|
127
|
+
.icons
|
|
128
|
+
display: flex
|
|
129
|
+
gap: .25em
|