@macrostrat/column-views 3.0.2 → 3.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 +12 -0
- package/dist/data-provider/column-nav.js +1 -1
- package/dist/data-provider/index.d.ts +0 -2
- package/dist/data-provider/store.cjs +49 -6
- package/dist/data-provider/store.cjs.map +1 -1
- package/dist/data-provider/store.js +46 -3
- package/dist/data-provider/store.js.map +1 -1
- package/dist/data-provider/unit-selection.cjs +9 -9
- package/dist/data-provider/unit-selection.cjs.map +1 -1
- package/dist/data-provider/unit-selection.d.ts +1 -1
- package/dist/data-provider/unit-selection.js +2 -2
- package/dist/data-provider/unit-selection.js.map +1 -1
- package/dist/index.cjs +5 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -23
- package/dist/index.js.map +1 -1
- package/dist/maps/column-correlation/state.cjs +2 -2
- package/dist/maps/column-correlation/state.cjs.map +1 -1
- package/dist/maps/column-correlation/state.d.ts +1 -0
- package/dist/maps/column-correlation/state.js +1 -1
- package/dist/maps/column-correlation/state.js.map +1 -1
- package/dist/maps/column-navigation/mapbox/state.cjs +3 -3
- package/dist/maps/column-navigation/mapbox/state.cjs.map +1 -1
- package/dist/maps/column-navigation/mapbox/state.js +1 -1
- package/dist/maps/column-navigation/mapbox/state.js.map +1 -1
- package/dist/maps/column-navigation/svg/data-fetcher.cjs +25 -0
- package/dist/maps/column-navigation/svg/data-fetcher.cjs.map +1 -0
- package/dist/maps/column-navigation/svg/data-fetcher.d.ts +6 -0
- package/dist/maps/column-navigation/svg/data-fetcher.js +25 -0
- package/dist/maps/column-navigation/svg/data-fetcher.js.map +1 -0
- package/dist/maps/column-navigation/svg/layers.cjs +2 -3
- package/dist/maps/column-navigation/svg/layers.cjs.map +1 -1
- package/dist/maps/column-navigation/svg/layers.js +1 -2
- package/dist/maps/column-navigation/svg/layers.js.map +1 -1
- package/dist/section.cjs +3 -3
- package/dist/section.cjs.map +1 -1
- package/dist/section.js +2 -2
- package/dist/section.js.map +1 -1
- package/dist/unit-details/panel.cjs +76 -57
- package/dist/unit-details/panel.cjs.map +1 -1
- package/dist/unit-details/panel.js +72 -53
- package/dist/unit-details/panel.js.map +1 -1
- package/dist/units/boxes.cjs +1 -0
- package/dist/units/boxes.cjs.map +1 -1
- package/dist/units/boxes.js +1 -0
- package/dist/units/boxes.js.map +1 -1
- package/dist/units/index.cjs +4 -4
- package/dist/units/index.cjs.map +1 -1
- package/dist/units/index.js +1 -1
- package/dist/units/index.js.map +1 -1
- package/package.json +23 -17
- package/src/correlation-chart/stories/correlation-chart.stories.ts +29 -22
- package/src/data-provider/index.ts +0 -2
- package/src/data-provider/store.ts +51 -10
- package/src/data-provider/unit-selection.ts +4 -4
- package/src/maps/column-correlation/state.ts +2 -1
- package/src/maps/column-navigation/mapbox/state.ts +1 -1
- package/src/maps/column-navigation/svg/column-navigation-svg-map.stories.ts +1 -1
- package/src/maps/column-navigation/svg/data-fetcher.ts +34 -0
- package/src/maps/column-navigation/svg/layers.ts +1 -1
- package/src/section.ts +1 -1
- package/src/unit-details/panel.ts +97 -60
- package/src/units/boxes.ts +2 -1
- package/src/units/index.ts +1 -1
- package/dist/data-provider/base.cjs +0 -352
- package/dist/data-provider/base.cjs.map +0 -1
- package/dist/data-provider/base.d.ts +0 -65
- package/dist/data-provider/base.js +0 -349
- package/dist/data-provider/base.js.map +0 -1
- package/dist/data-provider/core.cjs +0 -58
- package/dist/data-provider/core.cjs.map +0 -1
- package/dist/data-provider/core.d.ts +0 -31
- package/dist/data-provider/core.js +0 -56
- package/dist/data-provider/core.js.map +0 -1
- package/dist/data-provider/fetch.cjs +0 -212
- package/dist/data-provider/fetch.cjs.map +0 -1
- package/dist/data-provider/fetch.d.ts +0 -27
- package/dist/data-provider/fetch.js +0 -210
- package/dist/data-provider/fetch.js.map +0 -1
- package/dist/data-provider/store.d.ts +0 -34
- package/dist/unit-details/panel.d.ts +0 -87
- package/src/data-provider/base.ts +0 -475
- package/src/data-provider/core.ts +0 -89
- package/src/data-provider/fetch.ts +0 -278
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
import { LithologyTagFeature } from '@macrostrat/data-components';
|
|
3
|
-
import { Environment, UnitLong, Lithology, Interval } from '@macrostrat/api-types';
|
|
4
|
-
export interface UnitDetailsPanelProps {
|
|
5
|
-
unit: any;
|
|
6
|
-
onClose?: any;
|
|
7
|
-
className?: string;
|
|
8
|
-
actions?: ReactNode;
|
|
9
|
-
hiddenActions?: ReactNode;
|
|
10
|
-
features?: Set<UnitDetailsFeature>;
|
|
11
|
-
lithologyFeatures?: Set<LithologyTagFeature>;
|
|
12
|
-
onSelectUnit?: (unitID: number) => void;
|
|
13
|
-
onClickItem?: MacrostratItemClickHandler;
|
|
14
|
-
}
|
|
15
|
-
export declare function UnitDetailsPanel({ unit, onClose, className, features, lithologyFeatures, actions, hiddenActions, onSelectUnit, onClickItem, }: UnitDetailsPanelProps): import('react').ReactElement<{
|
|
16
|
-
className: string;
|
|
17
|
-
}, string | import('react').JSXElementConstructor<any>>;
|
|
18
|
-
export declare function LegendPanelHeader({ title, id, onClose, actions, hiddenActions, }: {
|
|
19
|
-
title?: string | null;
|
|
20
|
-
id?: number | null;
|
|
21
|
-
onClose?: () => void;
|
|
22
|
-
actions?: ReactNode | null;
|
|
23
|
-
hiddenActions?: ReactNode | null;
|
|
24
|
-
}): import('react').DOMElement<import('react').DOMAttributes<Element>, Element>;
|
|
25
|
-
export declare enum UnitDetailsFeature {
|
|
26
|
-
AdjacentUnits = "adjacent-units",
|
|
27
|
-
Color = "color",
|
|
28
|
-
OutcropType = "outcrop-type",
|
|
29
|
-
JSONToggle = "json-toggle",
|
|
30
|
-
DepthRange = "depth-range",
|
|
31
|
-
ColumnName = "column-name"
|
|
32
|
-
}
|
|
33
|
-
export type MacrostratItemClickHandler = (event: MouseEvent, item: Lithology | Environment | UnitLong | Interval | {
|
|
34
|
-
strat_name_id: number;
|
|
35
|
-
}) => void;
|
|
36
|
-
export declare function ReferencesField({ refs, className, ...rest }: {
|
|
37
|
-
[x: string]: any;
|
|
38
|
-
refs: any;
|
|
39
|
-
className?: any;
|
|
40
|
-
}): import('react').FunctionComponentElement<{
|
|
41
|
-
label?: string;
|
|
42
|
-
value?: any;
|
|
43
|
-
inline?: boolean;
|
|
44
|
-
showIfEmpty?: boolean;
|
|
45
|
-
className?: string;
|
|
46
|
-
children?: any;
|
|
47
|
-
unit?: string;
|
|
48
|
-
row?: boolean;
|
|
49
|
-
}>;
|
|
50
|
-
export declare function AgeLabel({ age, maximumFractionDigits, minimumFractionDigits, className, }: {
|
|
51
|
-
age: number;
|
|
52
|
-
className?: string;
|
|
53
|
-
maximumFractionDigits?: number;
|
|
54
|
-
minimumFractionDigits?: number;
|
|
55
|
-
}): import('react').FunctionComponentElement<{
|
|
56
|
-
value?: any;
|
|
57
|
-
unit?: string;
|
|
58
|
-
children?: any;
|
|
59
|
-
className?: string;
|
|
60
|
-
}>;
|
|
61
|
-
export declare function Duration({ value, maximumFractionDigits, minimumFractionDigits, }: {
|
|
62
|
-
value: any;
|
|
63
|
-
maximumFractionDigits?: number;
|
|
64
|
-
minimumFractionDigits?: number;
|
|
65
|
-
}): import('react').FunctionComponentElement<{
|
|
66
|
-
value?: any;
|
|
67
|
-
unit?: string;
|
|
68
|
-
children?: any;
|
|
69
|
-
className?: string;
|
|
70
|
-
}>;
|
|
71
|
-
export declare function ClickableText({ onClick, className, children, }: {
|
|
72
|
-
onClick: () => void;
|
|
73
|
-
className?: string;
|
|
74
|
-
children: ReactNode;
|
|
75
|
-
}): import('react').DetailedReactHTMLElement<{
|
|
76
|
-
onClick: () => void;
|
|
77
|
-
className: string;
|
|
78
|
-
}, HTMLElement>;
|
|
79
|
-
export declare function Identifier({ id, onClick, className, }: {
|
|
80
|
-
id: number | string;
|
|
81
|
-
onClick?: (id: number | string) => void;
|
|
82
|
-
className?: string;
|
|
83
|
-
}): import('react').FunctionComponentElement<{
|
|
84
|
-
onClick: () => void;
|
|
85
|
-
className?: string;
|
|
86
|
-
children: ReactNode;
|
|
87
|
-
}>;
|
|
@@ -1,475 +0,0 @@
|
|
|
1
|
-
/** Data provider for information that needs to be loaded in bulk for frontend views */
|
|
2
|
-
import baseFetch from "cross-fetch";
|
|
3
|
-
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
4
|
-
import h from "@macrostrat/hyper";
|
|
5
|
-
import { create, useStore } from "zustand";
|
|
6
|
-
import {
|
|
7
|
-
ColumnGeoJSONRecord,
|
|
8
|
-
ColumnGeoJSONRecordWithID,
|
|
9
|
-
Environment,
|
|
10
|
-
MacrostratRef,
|
|
11
|
-
StratName,
|
|
12
|
-
Interval,
|
|
13
|
-
} from "@macrostrat/api-types";
|
|
14
|
-
import {
|
|
15
|
-
fetchAllColumns,
|
|
16
|
-
fetchEnvironments,
|
|
17
|
-
fetchIntervals,
|
|
18
|
-
fetchLithologies,
|
|
19
|
-
fetchRefs,
|
|
20
|
-
fetchStratNames,
|
|
21
|
-
type ColumnStatusCode,
|
|
22
|
-
} from "./fetch";
|
|
23
|
-
import { APIProvider } from "@macrostrat/ui-components";
|
|
24
|
-
import { ColumnProvider } from "@macrostrat/column-components";
|
|
25
|
-
|
|
26
|
-
import { ReactNode } from "react";
|
|
27
|
-
import { useMacrostratColumnData } from "./store";
|
|
28
|
-
|
|
29
|
-
export interface MacrostratDataProviderProps {
|
|
30
|
-
baseURL: string;
|
|
31
|
-
children: React.ReactNode;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface ColumnFootprintsStorage {
|
|
35
|
-
project_id: number;
|
|
36
|
-
// Whether the "in process" flag was used
|
|
37
|
-
inProcess: boolean;
|
|
38
|
-
// The column footprints
|
|
39
|
-
columns: ColumnGeoJSONRecordWithID[];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
interface RefsSlice {
|
|
43
|
-
refs: Map<number, MacrostratRef>;
|
|
44
|
-
inFlightRequests: Set<string>; // Track requests to avoid duplicates
|
|
45
|
-
getRefs(ids: number[]): Promise<MacrostratRef[]>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
interface MacrostratStore extends RefsSlice {
|
|
49
|
-
baseURL: string;
|
|
50
|
-
fetch: any;
|
|
51
|
-
lithologies: Map<number, any> | null;
|
|
52
|
-
getLithologies(ids: number[] | null): Promise<any>;
|
|
53
|
-
intervals: Map<number, any> | null;
|
|
54
|
-
getIntervals(
|
|
55
|
-
ids: number[] | null,
|
|
56
|
-
timescaleID: number | null,
|
|
57
|
-
): Promise<Interval[]>;
|
|
58
|
-
environments: Map<number, Environment> | null;
|
|
59
|
-
getEnvironments(ids: number[] | null): Promise<Environment[]>;
|
|
60
|
-
columnFootprints: Map<number, ColumnFootprintsStorage>;
|
|
61
|
-
getColumns(
|
|
62
|
-
projectID: number | null,
|
|
63
|
-
inProcess: boolean,
|
|
64
|
-
): Promise<ColumnGeoJSONRecord[]>;
|
|
65
|
-
// Strat names unify both "strat names" and "concepts"
|
|
66
|
-
stratNames: Map<number, StratName> | null;
|
|
67
|
-
getStratNames(ids: number[] | null): Promise<StratName[]>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function createMacrostratStore(
|
|
71
|
-
baseURL: string = "https://macrostrat.org/api/v2",
|
|
72
|
-
) {
|
|
73
|
-
return create<MacrostratStore>((set, get): MacrostratStore => {
|
|
74
|
-
return {
|
|
75
|
-
baseURL,
|
|
76
|
-
inFlightRequests: new Set(),
|
|
77
|
-
async fetch(url: string, options?: RequestInit) {
|
|
78
|
-
const url1 = baseURL + url;
|
|
79
|
-
// Avoid duplicate requests
|
|
80
|
-
const { inFlightRequests } = get();
|
|
81
|
-
if (inFlightRequests.has(url1)) {
|
|
82
|
-
return null; // Return null if already in flight
|
|
83
|
-
}
|
|
84
|
-
inFlightRequests.add(url1);
|
|
85
|
-
//set({ inFlightRequests });
|
|
86
|
-
const res = await baseFetch(url1, options);
|
|
87
|
-
inFlightRequests.delete(url1);
|
|
88
|
-
//set({in})
|
|
89
|
-
return res;
|
|
90
|
-
},
|
|
91
|
-
...createLithologiesSlice(set, get),
|
|
92
|
-
...createIntervalsSlice(set, get),
|
|
93
|
-
...createEnvironmentsSlice(set, get),
|
|
94
|
-
...createColumnsSlice(set, get),
|
|
95
|
-
...createRefsSlice(set, get),
|
|
96
|
-
...createStratNamesSlice(set, get),
|
|
97
|
-
};
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function createRefsSlice(set, get) {
|
|
102
|
-
return {
|
|
103
|
-
refs: new Map(),
|
|
104
|
-
async getRefs(ids: number[]): Promise<MacrostratRef[]> {
|
|
105
|
-
const { refs, fetch } = get();
|
|
106
|
-
const missing = ids.filter((id) => !refs.has(id));
|
|
107
|
-
if (missing.length == 0) {
|
|
108
|
-
return ids.map((id) => refs.get(id));
|
|
109
|
-
}
|
|
110
|
-
const data = await fetchRefs(missing, fetch);
|
|
111
|
-
if (data == null) return [];
|
|
112
|
-
for (const d of data) {
|
|
113
|
-
refs.set(d.ref_id, d);
|
|
114
|
-
}
|
|
115
|
-
set({ refs });
|
|
116
|
-
return ids.map((id) => refs.get(id));
|
|
117
|
-
},
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function createColumnsSlice(set, get) {
|
|
122
|
-
// Column footprints separated by project
|
|
123
|
-
return {
|
|
124
|
-
columnFootprints: new Map(),
|
|
125
|
-
async getColumns(projectID: number | null, inProcess: boolean) {
|
|
126
|
-
const { columnFootprints, baseURL, fetch } = get();
|
|
127
|
-
const key = projectID ?? -1;
|
|
128
|
-
let _inProcess = inProcess;
|
|
129
|
-
|
|
130
|
-
let footprints = columnFootprints.get(key);
|
|
131
|
-
if (footprints == null || footprints.inProcess != _inProcess) {
|
|
132
|
-
// Fetch the columns
|
|
133
|
-
const statusCode: ColumnStatusCode[] = ["active"];
|
|
134
|
-
if (_inProcess) {
|
|
135
|
-
statusCode.push("in process");
|
|
136
|
-
}
|
|
137
|
-
const columns = await fetchAllColumns({
|
|
138
|
-
projectID,
|
|
139
|
-
statusCode,
|
|
140
|
-
fetch,
|
|
141
|
-
});
|
|
142
|
-
if (columns == null) {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
footprints = {
|
|
146
|
-
project_id: projectID,
|
|
147
|
-
inProcess,
|
|
148
|
-
columns,
|
|
149
|
-
};
|
|
150
|
-
// We could break multi-project result sets into separate caches here...
|
|
151
|
-
// Copy the original map
|
|
152
|
-
const columnFootprints2 = new Map(columnFootprints);
|
|
153
|
-
columnFootprints2.set(key, footprints);
|
|
154
|
-
set({ columnFootprints: columnFootprints2 });
|
|
155
|
-
}
|
|
156
|
-
return footprints.columns;
|
|
157
|
-
},
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function createLithologiesSlice(set, get) {
|
|
162
|
-
return {
|
|
163
|
-
lithologies: null,
|
|
164
|
-
async getLithologies(ids: number[] | null) {
|
|
165
|
-
const { lithologies, fetch } = get();
|
|
166
|
-
let lithMap = lithologies;
|
|
167
|
-
if (lithMap == null) {
|
|
168
|
-
const data = await fetchLithologies(fetch);
|
|
169
|
-
if (data == null) return;
|
|
170
|
-
lithMap = new Map(data.map((d) => [d.lith_id, d]));
|
|
171
|
-
set({ lithologies: lithMap });
|
|
172
|
-
}
|
|
173
|
-
// Now get the lithologies
|
|
174
|
-
if (ids == null) return lithMap.values();
|
|
175
|
-
return ids.map((id) => lithMap.get(id));
|
|
176
|
-
},
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function createEnvironmentsSlice(set, get) {
|
|
181
|
-
return {
|
|
182
|
-
environments: null,
|
|
183
|
-
async getEnvironments(ids: number[] | null): Promise<Environment[]> {
|
|
184
|
-
const { environments, fetch } = get();
|
|
185
|
-
let envMap = environments;
|
|
186
|
-
if (envMap == null) {
|
|
187
|
-
const data = await fetchEnvironments(fetch);
|
|
188
|
-
if (data == null) return [];
|
|
189
|
-
envMap = new Map(data.map((d) => [d.environ_id, d]));
|
|
190
|
-
set({ environments: envMap });
|
|
191
|
-
}
|
|
192
|
-
// Now get the environments
|
|
193
|
-
if (ids == null) return envMap.values();
|
|
194
|
-
return ids.map((id) => envMap.get(id));
|
|
195
|
-
},
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function createIntervalsSlice(set, get) {
|
|
200
|
-
return {
|
|
201
|
-
intervals: null,
|
|
202
|
-
async getIntervals(ids: number[] | null, timescaleID: number | null) {
|
|
203
|
-
const { intervals, fetch } = get();
|
|
204
|
-
let _intervals = intervals;
|
|
205
|
-
if (intervals == null || !includesTimescale(intervals, timescaleID)) {
|
|
206
|
-
// Fetch the intervals
|
|
207
|
-
const data = await fetchIntervals(timescaleID, fetch);
|
|
208
|
-
if (data == null) {
|
|
209
|
-
return [];
|
|
210
|
-
}
|
|
211
|
-
const intervalMap = intervals ?? new Map();
|
|
212
|
-
for (const d of data) {
|
|
213
|
-
intervalMap.set(d.int_id, d);
|
|
214
|
-
}
|
|
215
|
-
_intervals = intervalMap;
|
|
216
|
-
set({ intervals: _intervals });
|
|
217
|
-
}
|
|
218
|
-
if (ids == null && timescaleID == null)
|
|
219
|
-
return Array.from(_intervals.values());
|
|
220
|
-
if (timescaleID != null) {
|
|
221
|
-
return Array.from(_intervals.values() as any[]).filter(
|
|
222
|
-
(d) => d.timescale_id == timescaleID,
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
return ids.map((id) => intervals.get(id));
|
|
226
|
-
},
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function createStratNamesSlice(set, get) {
|
|
231
|
-
return {
|
|
232
|
-
stratNames: null,
|
|
233
|
-
async getStratNames(ids: number[] | null): Promise<StratName[]> {
|
|
234
|
-
const { stratNames, fetch } = get();
|
|
235
|
-
let nameMap = stratNames ?? new Map();
|
|
236
|
-
let stratNamesAlreadyLoaded = [];
|
|
237
|
-
let stratNamesToLoad = [];
|
|
238
|
-
for (const id of ids) {
|
|
239
|
-
if (nameMap.has(id)) {
|
|
240
|
-
stratNamesAlreadyLoaded.push(nameMap.get(id));
|
|
241
|
-
} else {
|
|
242
|
-
stratNamesToLoad.push(id);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
if (stratNamesToLoad.length > 0) {
|
|
246
|
-
const data = await fetchStratNames(stratNamesToLoad, fetch);
|
|
247
|
-
if (data == null) return stratNamesAlreadyLoaded;
|
|
248
|
-
for (const d of data) {
|
|
249
|
-
nameMap.set(d.strat_name_id, d);
|
|
250
|
-
}
|
|
251
|
-
set({ stratNames: nameMap });
|
|
252
|
-
}
|
|
253
|
-
return ids.map((id) => nameMap.get(id));
|
|
254
|
-
},
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function includesTimescale(intervals: Map<number, any>, timescaleID: number) {
|
|
259
|
-
if (intervals == null) return false;
|
|
260
|
-
if (timescaleID == null) return true;
|
|
261
|
-
return Array.from(intervals.values()).some(
|
|
262
|
-
(d) => d.timescale_id == timescaleID,
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
type MacrostratSelector = (store: MacrostratStore) => any;
|
|
267
|
-
|
|
268
|
-
export function useMacrostratStore(selector: MacrostratSelector | "api") {
|
|
269
|
-
const ctx = useContext(MacrostratDataProviderContext);
|
|
270
|
-
if (ctx == null) {
|
|
271
|
-
throw new Error("Missing MacrostratDataProvider");
|
|
272
|
-
}
|
|
273
|
-
if (selector === "api") {
|
|
274
|
-
return ctx;
|
|
275
|
-
}
|
|
276
|
-
return useStore(ctx, selector);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
export function useMacrostratBaseURL(
|
|
280
|
-
defaultURL = "https://macrostrat.org/api/v2",
|
|
281
|
-
): string {
|
|
282
|
-
/** Get the Macrostrat base URL from the store if set, otherwise return a default value */
|
|
283
|
-
const ctx = useContext(MacrostratDataProviderContext);
|
|
284
|
-
if (ctx == null) {
|
|
285
|
-
// Return default URL if no provider is present
|
|
286
|
-
return defaultURL;
|
|
287
|
-
}
|
|
288
|
-
return ctx.getState().baseURL;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export function useMacrostratFetch() {
|
|
292
|
-
const ctx = useContext(MacrostratDataProviderContext);
|
|
293
|
-
if (ctx == null) {
|
|
294
|
-
throw new Error("Missing MacrostratDataProvider");
|
|
295
|
-
}
|
|
296
|
-
return ctx.getState().fetch;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
type DataTypeKey =
|
|
300
|
-
| "lithologies"
|
|
301
|
-
| "intervals"
|
|
302
|
-
| "columns"
|
|
303
|
-
| "environments"
|
|
304
|
-
| "refs"
|
|
305
|
-
| "strat_names";
|
|
306
|
-
|
|
307
|
-
const dataTypeMapping = {
|
|
308
|
-
lithologies: (store) => store.getLithologies,
|
|
309
|
-
intervals: (store) => store.getIntervals,
|
|
310
|
-
columns: (store) => store.getColumns,
|
|
311
|
-
environments: (store) => store.getEnvironments,
|
|
312
|
-
refs: (store) => store.getRefs,
|
|
313
|
-
strat_names: (store) => store.getStratNames,
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
export function useMacrostratDefs(dataType: string): Map<number, any> | null {
|
|
317
|
-
if (dataType == "columns") {
|
|
318
|
-
throw new Error("Columns are not provided as a map");
|
|
319
|
-
}
|
|
320
|
-
const operator = useMacrostratStore(dataTypeMapping[dataType]);
|
|
321
|
-
useEffect(() => {
|
|
322
|
-
operator();
|
|
323
|
-
}, []);
|
|
324
|
-
return useMacrostratStore((state) => state[dataType]);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export function useMacrostratColumns(
|
|
328
|
-
projectID: number | null,
|
|
329
|
-
inProcess: boolean,
|
|
330
|
-
) {
|
|
331
|
-
const getColumns = useMacrostratStore((s) => s.getColumns);
|
|
332
|
-
const columnsMap = useMacrostratStore((s) => s.columnFootprints);
|
|
333
|
-
const key = projectID ?? -1;
|
|
334
|
-
const colData = columnsMap?.get(key);
|
|
335
|
-
useEffect(() => {
|
|
336
|
-
// Refetch if the columns are not available, or if we have requested inProcess columns where we didn't before
|
|
337
|
-
if (colData == null || (inProcess && !colData.inProcess)) {
|
|
338
|
-
getColumns(projectID, inProcess);
|
|
339
|
-
}
|
|
340
|
-
// If we've already fetched the columns there's nothing to do...
|
|
341
|
-
}, [colData, inProcess, getColumns]);
|
|
342
|
-
|
|
343
|
-
return useMemo(() => {
|
|
344
|
-
if (colData == null) return null;
|
|
345
|
-
let columns = colData.columns;
|
|
346
|
-
if (!inProcess && colData.inProcess) {
|
|
347
|
-
// Our available set of columns includes 'in process' columns, but we don't want them
|
|
348
|
-
columns.features = columns.features?.filter(
|
|
349
|
-
(d) => d.properties.status != "in process",
|
|
350
|
-
);
|
|
351
|
-
}
|
|
352
|
-
return columns;
|
|
353
|
-
}, [colData, inProcess]);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
export function useMacrostratColumnInfo(
|
|
357
|
-
columnID: number,
|
|
358
|
-
): ColumnGeoJSONRecord["properties"] | null {
|
|
359
|
-
/** Get basic info for a column, without automatically fetching it (assumes the overall set of relevant columns has already been fetched) */
|
|
360
|
-
const columnsMap = useMacrostratStore((s) => s.columnFootprints);
|
|
361
|
-
return useMemo(() => {
|
|
362
|
-
for (const colData of columnsMap.values()) {
|
|
363
|
-
const col = colData.columns.find((d) => d.properties.col_id === columnID);
|
|
364
|
-
if (col != null) return col.properties;
|
|
365
|
-
}
|
|
366
|
-
return null;
|
|
367
|
-
}, [columnsMap, columnID]);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
export function useMacrostratData(dataType: DataTypeKey, ...args: any[]) {
|
|
371
|
-
const selector = dataTypeMapping[dataType];
|
|
372
|
-
const operator = useMacrostratStore(selector);
|
|
373
|
-
|
|
374
|
-
const [value, setValue] = useState(null);
|
|
375
|
-
|
|
376
|
-
useEffect(() => {
|
|
377
|
-
try {
|
|
378
|
-
operator(...args).then(setValue);
|
|
379
|
-
} catch (e) {
|
|
380
|
-
console.error(e);
|
|
381
|
-
}
|
|
382
|
-
}, [operator, ...args]);
|
|
383
|
-
|
|
384
|
-
return value;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/** By default, we provide a store linked to the production API */
|
|
388
|
-
const MacrostratDataProviderContext = createContext(createMacrostratStore());
|
|
389
|
-
|
|
390
|
-
export function MacrostratDataProvider(props: MacrostratDataProviderProps) {
|
|
391
|
-
const { baseURL = "https://dev.macrostrat.org/api/v2", children } = props;
|
|
392
|
-
|
|
393
|
-
const [store] = useState(() => createMacrostratStore(baseURL));
|
|
394
|
-
|
|
395
|
-
return h(
|
|
396
|
-
MacrostratAPIProvider,
|
|
397
|
-
{ baseURL },
|
|
398
|
-
h(MacrostratDataProviderContext.Provider, { value: store }, children),
|
|
399
|
-
);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/** Legacy API provider so useAPIResult can work */
|
|
403
|
-
|
|
404
|
-
type APIProviderProps = {
|
|
405
|
-
children: ReactNode;
|
|
406
|
-
useDev?: boolean;
|
|
407
|
-
baseURL?: string;
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
export function MacrostratAPIProvider({
|
|
411
|
-
children,
|
|
412
|
-
useDev = false,
|
|
413
|
-
baseURL,
|
|
414
|
-
}: APIProviderProps) {
|
|
415
|
-
baseURL ??= useDev
|
|
416
|
-
? "https://dev.macrostrat.org/api/v2"
|
|
417
|
-
: "https://macrostrat.org/api/v2";
|
|
418
|
-
|
|
419
|
-
return h(
|
|
420
|
-
APIProvider,
|
|
421
|
-
{
|
|
422
|
-
baseURL,
|
|
423
|
-
unwrapResponse: (res) => res.success.data,
|
|
424
|
-
},
|
|
425
|
-
children,
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
export function MacrostratColumnProvider(props) {
|
|
430
|
-
/** A column provider specialized the Macrostrat API. Maps more
|
|
431
|
-
* generic concepts to Macrostrat-specific ones.
|
|
432
|
-
*/
|
|
433
|
-
|
|
434
|
-
const { axisType } = useMacrostratColumnData();
|
|
435
|
-
const { units, domain, pixelScale, scale, children } = props;
|
|
436
|
-
return h(
|
|
437
|
-
ColumnProvider,
|
|
438
|
-
{
|
|
439
|
-
axisType,
|
|
440
|
-
divisions: units,
|
|
441
|
-
range: domain,
|
|
442
|
-
pixelsPerMeter: pixelScale,
|
|
443
|
-
scale,
|
|
444
|
-
},
|
|
445
|
-
children,
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/** This is now a legacy provider */
|
|
450
|
-
export function LithologiesProvider({ children }) {
|
|
451
|
-
useEffect(() => {
|
|
452
|
-
console.warn(
|
|
453
|
-
"LithologiesProvider is deprecated. Replace with MacrostratDataProvider",
|
|
454
|
-
);
|
|
455
|
-
}, []);
|
|
456
|
-
return children;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
export function useLithologies() {
|
|
460
|
-
const getLithologies = useMacrostratStore((s) => s.getLithologies);
|
|
461
|
-
const lithologies = useMacrostratStore((s) => s.lithologies);
|
|
462
|
-
useEffect(() => {
|
|
463
|
-
if (lithologies == null) getLithologies();
|
|
464
|
-
}, [lithologies, getLithologies]);
|
|
465
|
-
return lithologies;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
export function useEnvironments() {
|
|
469
|
-
const getEnvironments = useMacrostratStore((s) => s.getEnvironments);
|
|
470
|
-
const environments = useMacrostratStore((s) => s.environments);
|
|
471
|
-
useEffect(() => {
|
|
472
|
-
if (environments == null) getEnvironments();
|
|
473
|
-
}, [environments, getEnvironments]);
|
|
474
|
-
return environments;
|
|
475
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { atom, type WritableAtom } from "jotai";
|
|
2
|
-
import { createIsolation } from "jotai-scope";
|
|
3
|
-
import { BaseUnit } from "@macrostrat/api-types";
|
|
4
|
-
import { ReactNode, useEffect, useRef } from "react";
|
|
5
|
-
import h from "@macrostrat/hyper";
|
|
6
|
-
|
|
7
|
-
interface StateIsolation {
|
|
8
|
-
Provider: (props: {
|
|
9
|
-
store?: any;
|
|
10
|
-
initialValues?: AtomMap;
|
|
11
|
-
children: ReactNode;
|
|
12
|
-
}) => ReactNode;
|
|
13
|
-
useStore: () => any;
|
|
14
|
-
useAtom: any;
|
|
15
|
-
useAtomValue: any;
|
|
16
|
-
useSetAtom: any;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const scope: StateIsolation = createIsolation();
|
|
20
|
-
|
|
21
|
-
export type AtomMap = [WritableAtom<any, any, any>, any][];
|
|
22
|
-
|
|
23
|
-
type ProviderProps = {
|
|
24
|
-
children: ReactNode;
|
|
25
|
-
atoms?: AtomMap;
|
|
26
|
-
shouldUpdateAtoms?: boolean;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export function ScopedProvider({
|
|
30
|
-
children,
|
|
31
|
-
atoms,
|
|
32
|
-
shouldUpdateAtoms = true,
|
|
33
|
-
}: ProviderProps) {
|
|
34
|
-
// Always use the same store instance in this tree
|
|
35
|
-
let val = null;
|
|
36
|
-
try {
|
|
37
|
-
val = scope.useStore();
|
|
38
|
-
// This store has already been provided
|
|
39
|
-
return children;
|
|
40
|
-
} catch {
|
|
41
|
-
return h(scope.Provider, { store: null, initialValues: atoms }, [
|
|
42
|
-
h.if(shouldUpdateAtoms)(AtomUpdater, { atoms }),
|
|
43
|
-
children,
|
|
44
|
-
]);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function AtomUpdater({
|
|
49
|
-
atoms,
|
|
50
|
-
}: {
|
|
51
|
-
atoms: [WritableAtom<any, any, any>, any][];
|
|
52
|
-
}) {
|
|
53
|
-
/**
|
|
54
|
-
* A generic updater to sync Jotai atoms with state passed as props.
|
|
55
|
-
* Useful for scoped providers where state needs to be synced outside
|
|
56
|
-
* the current context.
|
|
57
|
-
*/
|
|
58
|
-
/** TODO: this is an awkward way to keep atoms updated */
|
|
59
|
-
// The scoped store
|
|
60
|
-
const store = scope.useStore();
|
|
61
|
-
|
|
62
|
-
// Warn on atoms changing length
|
|
63
|
-
const prevLengthRef = useRef(atoms.length);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
if (prevLengthRef.current !== atoms.length) {
|
|
66
|
-
console.error("Error: number of atoms in ScopedAtomUpdater has changed.");
|
|
67
|
-
prevLengthRef.current = atoms.length;
|
|
68
|
-
}
|
|
69
|
-
}, [atoms.length]);
|
|
70
|
-
|
|
71
|
-
for (const [atom, value] of atoms) {
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
store.set(atom, value);
|
|
74
|
-
}, [store, value]);
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export const columnUnitsAtom = atom<BaseUnit[]>();
|
|
80
|
-
|
|
81
|
-
export const columnUnitsMapAtom = atom<Map<number, BaseUnit> | null>((get) => {
|
|
82
|
-
const units = get(columnUnitsAtom);
|
|
83
|
-
if (!units) return null;
|
|
84
|
-
const unitMap = new Map<number, BaseUnit>();
|
|
85
|
-
units.forEach((unit) => {
|
|
86
|
-
unitMap.set(unit.unit_id, unit);
|
|
87
|
-
});
|
|
88
|
-
return unitMap;
|
|
89
|
-
});
|