Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: local slpk feature #391

Merged
merged 5 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module.exports = {
},
parser: "@typescript-eslint/parser",
extends: ["standard-with-typescript", "plugin:react/recommended"],
// ignorePatterns: ["**/*.html"],
ignorePatterns: ["**/*.slpk"],
overrides: [
{
env: {
Expand Down
11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.17",
"@hyperjump/json-schema": "^0.23.2",
"@loaders.gl/3d-tiles": "^4.1.0-alpha.11",
"@loaders.gl/core": "^4.1.0-alpha.11",
"@loaders.gl/i3s": "^4.1.0-alpha.11",
"@loaders.gl/tiles": "^4.1.0-alpha.11",
"@loaders.gl/loader-utils": "^4.3.3",
"@loaders.gl/3d-tiles": "^4.3.3",
"@loaders.gl/core": "^4.3.3",
"@loaders.gl/i3s": "^4.3.3",
"@loaders.gl/tiles": "^4.3.3",
"@luma.gl/core": "^8.5.14",
"@math.gl/core": "^3.6.0",
"@math.gl/proj4": "^3.6.3",
Expand Down Expand Up @@ -113,7 +114,7 @@
"webpack-dev-server": "^5.0.4"
},
"resolutions": {
"@loaders.gl/tiles": "^4.1.0-alpha.11"
"@loaders.gl/tiles": "^4.3.3"
},
"volta": {
"node": "18.18.2",
Expand Down
6 changes: 6 additions & 0 deletions src/components/bookmarks-panel/bookmarks-panel.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ jest.mock("../../utils/hooks/layout");

const dragAndDropText = "Drag and drop your json file here";

Object.defineProperty(globalThis, "crypto", {
value: {
randomUUID: () => "",
},
});

const TEST_BOOKMARKS = [
{
id: "testId1",
Expand Down
8 changes: 5 additions & 3 deletions src/components/bookmarks-panel/bookmarks-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,11 @@ export const BookmarksPanel = ({
onEditBookmarks={onEditBookmarksClickHandler}
onClearBookmarks={onClearBookmarksClickHandler}
onUploadBookmarks={() => {
setPopoverType(
bookmarks.length ? PopoverType.uploadWarning : PopoverType.upload
);
setTimeout(() => {
setPopoverType(
bookmarks.length ? PopoverType.uploadWarning : PopoverType.upload
);
}, 1);
}}
onDownloadBookmarks={onDownloadBookmarks}
onCollapsed={onCollapsed}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ describe("UnsavedBookmarkWarning", () => {
const { container } = callRender(renderWithTheme);
const fileInteractionContiner = container.firstChild.firstChild;
expect(container.firstChild).toBeInTheDocument();
expect(fileInteractionContiner.childNodes.length).toBe(3);
expect(fileInteractionContiner.childNodes.length).toBe(2);
});
});
17 changes: 13 additions & 4 deletions src/components/comparison/comparison-side/comparison-side.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { parseTilesetUrlParams } from "../../../utils/url-utils";
import {
findExampleAndUpdateWithViewState,
getActiveLayersByIds,
getLayerUrl,
handleSelectAllLeafsInGroup,
selectNestedLayers,
} from "../../../utils/layer-utils";
Expand Down Expand Up @@ -234,7 +235,13 @@ export const ComparisonSide = ({
const tilesetsData: TilesetMetadata[] = [];

for (const layer of activeLayers) {
const params = parseTilesetUrlParams(layer.url, layer);
let params = { tilesetUrl: "" as string | File, token: "" };
if (typeof layer.url === "string") {
params = parseTilesetUrlParams(layer.url, layer);
} else {
params.tilesetUrl = layer.url;
}

const { tilesetUrl, token } = params;

tilesetsData.push({
Expand All @@ -254,8 +261,9 @@ export const ComparisonSide = ({
})
);
if (buildingExplorerOpened && tilesetsData[0]) {
const tilesetDataUrl = getLayerUrl(tilesetsData[0].url);
void dispatch(
getBSLStatisticsSummary({ statSummaryUrl: tilesetsData[0].url, side })
getBSLStatisticsSummary({ statSummaryUrl: tilesetDataUrl, side })
);
}
}, [activeLayers, buildingExplorerOpened]);
Expand All @@ -279,7 +287,7 @@ export const ComparisonSide = ({

if (loadedTilesetsCount && activeLayersCount) {
const isBSL = loadedTilesetsCount > activeLayersCount;
let statsName = activeLayers[0].url;
let statsName = getLayerUrl(activeLayers[0].url);

if (!isBSL) {
statsName = loadedTilesets
Expand Down Expand Up @@ -312,12 +320,13 @@ export const ComparisonSide = ({
.map((sublayer) => ({
id: sublayer.id,
url: sublayer.url,
fetch: sublayer.fetch,
token: sublayer.token,
type: sublayer.type ?? TilesetType.I3S,
}));
};

const onTraversalCompleteHandler = (selectedTiles) => {
const onTraversalCompleteHandler = (selectedTiles: Tile3D[]) => {
// A parent tileset of selected tiles
const aTileset = selectedTiles?.[0]?.tileset;
// Make sure that the actual tileset has been traversed traversed
Expand Down
1 change: 1 addition & 0 deletions src/components/deck-gl-wrapper/deck-gl-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ interface DeckGlI3sProps {
layers3d: Array<{
id?: number;
url?: string;
fetch?: ((input: RequestInfo | URL, init?: RequestInit | undefined) => Promise<Response>);
token?: string | null;
type: TilesetType;
}>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import "@testing-library/jest-dom";
const onInsertMock = jest.fn();
const onCancelMock = jest.fn();

Object.defineProperty(globalThis, "crypto", {
value: {
randomUUID: () => "",
},
});

const callRender = (
renderFunc,
props = {},
Expand Down
65 changes: 44 additions & 21 deletions src/components/layers-panel/insert-panel/insert-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type LayoutProps,
TilesetType,
BaseMapGroup,
FileType,
} from "../../../types";
import {
getCurrentLayoutProperty,
Expand All @@ -23,20 +24,23 @@ import {
getLayerNameInfo,
selectLayerNames,
} from "../../../redux/slices/layer-names-slice";
import { UploadPanel } from "../../upload-panel/upload-panel";
import { getLayerUrl } from "../../../utils/layer-utils";

const NO_NAME_ERROR = "Please enter name";
const INVALID_URL_ERROR = "Invalid URL";

export interface CustomLayerData {
name: string;
url: string;
url: string | File;
token?: string;
group?: BaseMapGroup;
}

interface InsertLayerProps {
title: string;
groups?: string[];
noFile?: boolean;
onInsert: (object: CustomLayerData) => Promise<void> | void;
onCancel: () => void;
children?: React.ReactNode;
Expand Down Expand Up @@ -101,13 +105,14 @@ const SpinnerContainer = styled.div<VisibilityProps>`
export const InsertPanel = ({
title,
groups,
noFile,
onInsert,
onCancel,
children = null,
}: InsertLayerProps) => {
const [group, setGroup] = useState<BaseMapGroup>(BaseMapGroup.Maplibre);
const [name, setName] = useState("");
const [url, setUrl] = useState("");
const [url, setUrl] = useState<string | File>("");
const [token, setToken] = useState("");

const [nameError, setNameError] = useState("");
Expand All @@ -116,29 +121,33 @@ export const InsertPanel = ({
const layerNames = useAppSelector(selectLayerNames);
const dispatch = useAppDispatch();

const getNewLayerUrl = () => getLayerUrl(url);

const validateFields = (): void => {
let isFormValid = true;
const type = getTilesetType(url);
const type = getTilesetType(typeof url === "string" ? url : url.name);

try {
// eslint-disable-next-line no-new
new URL(url);
} catch (_) {
setUrlError(INVALID_URL_ERROR);
isFormValid = false;
if (typeof url === "string") {
try {
// eslint-disable-next-line no-new
new URL(url);
} catch (_) {
setUrlError(INVALID_URL_ERROR);
isFormValid = false;
}
}

if (
(type !== TilesetType.I3S && !name) ||
(type === TilesetType.I3S && !name && !layerNames[url]?.name)
(type === TilesetType.I3S && !name && !layerNames[getNewLayerUrl()]?.name)
) {
setNameError(NO_NAME_ERROR);
isFormValid = false;
}

if (isFormValid) {
void onInsert({
name: name || layerNames[url]?.name,
name: name || layerNames[getNewLayerUrl()]?.name,
url,
token,
group: groups ? group : undefined,
Expand All @@ -147,16 +156,16 @@ export const InsertPanel = ({
};

useEffect(() => {
const type = getTilesetType(url);
const type = getTilesetType(getNewLayerUrl());
if (isValidateInProgress && type === TilesetType.I3S) {
if (
(layerNames[url] !== undefined &&
layerNames[url].status === FetchingStatus.ready) ||
(layerNames[getNewLayerUrl()] !== undefined &&
layerNames[getNewLayerUrl()].status === FetchingStatus.ready) ||
name.length > 0
) {
setValidateInProgress(false);
validateFields();
} else if (!layerNames[url]) {
} else if (!layerNames[getNewLayerUrl()]) {
void dispatch(getLayerNameInfo({ layerUrl: url, token, type }));
}
}
Expand All @@ -165,27 +174,34 @@ export const InsertPanel = ({
const handleInsert = (event) => {
event.preventDefault();

if (getTilesetType(url) !== TilesetType.I3S) {
if (getTilesetType(getNewLayerUrl()) !== TilesetType.I3S) {
validateFields();
} else {
setValidateInProgress(true);
}
};

const handleInputChange = (event) => {
const { name, value } = event.target;
const { name: fieldName, value, files } = event.target;

switch (name) {
switch (fieldName) {
case "BasemapProvider":
setGroup(value);
setGroup(value as BaseMapGroup);
setNameError("");
break;
case "Name":
setName(value);
setNameError("");
break;
case "URL":
setUrl(value);
if (files) {
setUrl(files[0]);
if (!name) {
setName(files[0].name.substring(0, files[0].name.length - 5));
}
} else {
setUrl(value);
}
setUrlError("");
break;
case "Token":
Expand Down Expand Up @@ -225,7 +241,7 @@ export const InsertPanel = ({
<InputText
name="URL"
label="URL"
value={url}
value={typeof url === "string" ? url : ""}
error={urlError}
onChange={handleInputChange}
/>
Expand All @@ -235,6 +251,13 @@ export const InsertPanel = ({
value={token}
onChange={handleInputChange}
/>
{!noFile && <UploadPanel
dragAndDropText={"Drag and drop your .slpk file here"}
noPadding={true}
accept=".slpk"
onFileEvent={(files) => { handleInputChange({ target: { files, name: "URL" } }); }}
fileType={FileType.binary}
/>}
</InputsWrapper>
<ButtonsWrapper>
<ActionButton
Expand Down
Loading
Loading