Add functional settings menu
This commit is contained in:
parent
65c08d8d6a
commit
e1056637ab
5 changed files with 267 additions and 114 deletions
|
@ -51,6 +51,8 @@
|
|||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@fluentui/react": "^8.61.0",
|
||||
"@fluentui/react-icons-mdl2": "^1.3.4",
|
||||
"@reduxjs/toolkit": "^1.7.1",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/node": "^15.14.9",
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import { createGlobalStyle } from "styled-components";
|
||||
import Select from "react-select";
|
||||
import SerialPort from "serialport";
|
||||
import electron from "electron";
|
||||
import { registerIcons } from "@fluentui/react/lib/Styling";
|
||||
import { ChevronDownIcon, CancelIcon } from "@fluentui/react-icons-mdl2";
|
||||
import KnobSection from "./Components/KnobSection";
|
||||
import { useAppDispatch } from "./redux/hooks";
|
||||
import { connect, disconnect, setSerialPort } from "./redux/slices/serialConnectionSlice";
|
||||
import Settings from "./Components/Settings";
|
||||
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
|
@ -20,84 +17,19 @@ const GlobalStyle = createGlobalStyle`
|
|||
}
|
||||
`;
|
||||
|
||||
const options: [{value: string, label:string}] = [{ value: "placeholder", label: "Select Port" }];
|
||||
|
||||
const fetchPorts = async () => {
|
||||
const data = await SerialPort.list();
|
||||
options.shift();
|
||||
data.forEach((comPort) => { options.push({ value: comPort.path, label: comPort.path }); });
|
||||
};
|
||||
|
||||
const App = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
fetchPorts();
|
||||
|
||||
const [portSelectionValue, setPortSelectionValue] = useState(options[0]);
|
||||
const handlePortChange = async (selectedOption: any) => {
|
||||
setPortSelectionValue(selectedOption);
|
||||
dispatch(setSerialPort(selectedOption.value));
|
||||
};
|
||||
|
||||
registerIcons({
|
||||
icons: {
|
||||
ChevronDown: <ChevronDownIcon />,
|
||||
Cancel: <CancelIcon />,
|
||||
},
|
||||
});
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
<Settings />
|
||||
<GlobalStyle />
|
||||
<KnobSection />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
dispatch(connect());
|
||||
}}
|
||||
>
|
||||
connect
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
dispatch(disconnect());
|
||||
}}
|
||||
>
|
||||
disconnect
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
electron.ipcRenderer.send("asynchronous-message", "red");
|
||||
}}
|
||||
>
|
||||
tray red
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
electron.ipcRenderer.send("asynchronous-message", "green");
|
||||
}}
|
||||
>
|
||||
tray green
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
electron.ipcRenderer.send("asynchronous-message", "yellow");
|
||||
}}
|
||||
>
|
||||
tray yellow
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
electron.ipcRenderer.send("asynchronous-message", "default");
|
||||
}}
|
||||
>
|
||||
tray default
|
||||
</button>
|
||||
<Select
|
||||
value={portSelectionValue}
|
||||
onChange={handlePortChange}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default App;
|
||||
|
|
|
@ -1,50 +1,104 @@
|
|||
import electron from "electron";
|
||||
import React, { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import ReactDom from "react-dom";
|
||||
import { Dialog, DialogType, DialogFooter } from "@fluentui/react/lib/Dialog";
|
||||
import { PrimaryButton, DefaultButton } from "@fluentui/react/lib/Button";
|
||||
import { ThemeProvider, PartialTheme } from "@fluentui/react/lib/Theme";
|
||||
import { ComboBox, IComboBoxOption } from "@fluentui/react/lib/ComboBox";
|
||||
import SerialPort from "serialport";
|
||||
import { useAppDispatch, useAppSelector } from "../redux/hooks";
|
||||
import { connect, disconnect, setSerialPort } from "../redux/slices/serialConnectionSlice";
|
||||
|
||||
type Proptypes = {
|
||||
}
|
||||
const dialogStyles = { main: { maxWidth: 450 } };
|
||||
|
||||
const Content = styled.div`
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: #FFF;
|
||||
padding: 50px;
|
||||
z-index: 1000;
|
||||
`;
|
||||
const myTheme: PartialTheme = {
|
||||
palette: {
|
||||
themePrimary: "#0078d4",
|
||||
themeLighterAlt: "#eff6fc",
|
||||
themeLighter: "#deecf9",
|
||||
themeLight: "#c7e0f4",
|
||||
themeTertiary: "#71afe5",
|
||||
themeSecondary: "#2b88d8",
|
||||
themeDarkAlt: "#106ebe",
|
||||
themeDark: "#005a9e",
|
||||
themeDarker: "#004578",
|
||||
neutralLighterAlt: "#282828",
|
||||
neutralLighter: "#313131",
|
||||
neutralLight: "#3f3f3f",
|
||||
neutralQuaternaryAlt: "#484848",
|
||||
neutralQuaternary: "#4f4f4f",
|
||||
neutralTertiaryAlt: "#6d6d6d",
|
||||
neutralTertiary: "#c8c8c8",
|
||||
neutralSecondary: "#d0d0d0",
|
||||
neutralPrimaryAlt: "#dadada",
|
||||
neutralPrimary: "#ffffff",
|
||||
neutralDark: "#f4f4f4",
|
||||
black: "#f8f8f8",
|
||||
white: "#1f1f1f",
|
||||
},
|
||||
};
|
||||
|
||||
const Overlay = styled.div`
|
||||
position: fixed;
|
||||
top:0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
z-index: 999;
|
||||
`;
|
||||
const modalProps = {
|
||||
titleAriaId: "labelId",
|
||||
subtitleAriaId: "subTextId",
|
||||
isBlocking: false,
|
||||
styles: dialogStyles,
|
||||
};
|
||||
const dialogContentProps = {
|
||||
type: DialogType.close,
|
||||
title: "Settings",
|
||||
closeButtonAriaLabel: "Close",
|
||||
};
|
||||
|
||||
const options: IComboBoxOption[] = [
|
||||
];
|
||||
|
||||
const fetchPorts = async () => {
|
||||
const data = await SerialPort.list();
|
||||
options.forEach(() => {
|
||||
options.shift();
|
||||
});
|
||||
data.forEach((comPort) => { options.push({ key: comPort.path, text: comPort.path }); });
|
||||
};
|
||||
|
||||
const Settings: React.FC<Proptypes> = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [hidden, setHidden] = useState(true);
|
||||
const ipcHandler = () => {
|
||||
setOpen(true);
|
||||
setHidden(false);
|
||||
};
|
||||
electron.ipcRenderer.on("show-settings", ipcHandler);
|
||||
const dispatch = useAppDispatch();
|
||||
const handlePortChange = async (option: IComboBoxOption | undefined) => {
|
||||
if (option !== null && option !== undefined) {
|
||||
dispatch(setSerialPort(option.key.toString()));
|
||||
}
|
||||
};
|
||||
fetchPorts();
|
||||
const selector = useAppSelector((state) => state);
|
||||
console.log(selector.serialConnection.port);
|
||||
return (
|
||||
<ThemeProvider theme={myTheme}>
|
||||
<Dialog
|
||||
hidden={hidden}
|
||||
onDismiss={() => { setHidden(true); }}
|
||||
dialogContentProps={dialogContentProps}
|
||||
modalProps={modalProps}
|
||||
>
|
||||
<ComboBox
|
||||
label="COM Port"
|
||||
options={options}
|
||||
onMenuOpen={() => { fetchPorts(); }}
|
||||
onChange={(_, option) => { handlePortChange(option); }}
|
||||
selectedKey={selector.serialConnection.port}
|
||||
/>
|
||||
|
||||
if (!open) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ReactDom.createPortal(
|
||||
<>
|
||||
<Overlay />
|
||||
<Content>
|
||||
<button type="button" onClick={() => { setOpen(false); }}>close</button>
|
||||
</Content>
|
||||
</>,
|
||||
document.getElementById("portal")!,
|
||||
<DialogFooter>
|
||||
<PrimaryButton onClick={() => { dispatch(connect()); }} text="Connect" />
|
||||
<DefaultButton onClick={() => { dispatch(disconnect()); }} text="Disconnect" />
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ const els = require("electron-localshortcut");
|
|||
const { default: installExtension, REDUX_DEVTOOLS, REACT_DEVELOPER_TOOLS } = require("electron-devtools-installer");
|
||||
|
||||
const windowWidth = 900;
|
||||
const windowHeight = 300;
|
||||
const windowHeight = 230;
|
||||
|
||||
let tray = null;
|
||||
let mainWindow = null;
|
||||
|
@ -119,6 +119,7 @@ function createTray() {
|
|||
label: "Settings",
|
||||
click: () => {
|
||||
mainWindow.webContents.send("show-settings", true);
|
||||
mainWindow.show();
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1123,6 +1123,165 @@
|
|||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@fluentui/date-time-utilities@^8.5.0":
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/date-time-utilities/-/date-time-utilities-8.5.0.tgz#069af4907372d18f21e83bfc11b0f75abfd15c5b"
|
||||
integrity sha512-SddqPNEA5PBxZLvRY9ej2//iTzNWFqBt9kZ9rjieBlRtFPjztnDV10Zq3xlR6ss79dwkiP+S+SP4SmI2xuckHA==
|
||||
dependencies:
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/dom-utilities@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/dom-utilities/-/dom-utilities-2.2.0.tgz#99a67dff1579564cdb9d9a37cbc3b9e8c75c9bc0"
|
||||
integrity sha512-M4SmXu428wwQLu1iw6ST07iACjdKY5HiU+xpcgD3IQMMQazgN616GDzc6KZ1ebuBsF7B4TyQS7KZh9mfxnnldg==
|
||||
dependencies:
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/font-icons-mdl2@^8.2.4":
|
||||
version "8.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.2.4.tgz#cd5569805c53b7eb81315662a2d340a6381b8c7e"
|
||||
integrity sha512-Qep23/wpAwONuX0NSQa0D6RbGbEJQBjGMLdV4Qp6h4NKIGELsKJ1xEIa5ZCD68LzQHJsVtXDtOnSWi57Ug/P1A==
|
||||
dependencies:
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/style-utilities" "^8.6.4"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/foundation-legacy@^8.2.4":
|
||||
version "8.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/foundation-legacy/-/foundation-legacy-8.2.4.tgz#6aa5de708add9414cac71fb3e7c618d6ed2f8ec1"
|
||||
integrity sha512-3pBUhKxkfJiRmTcTkkv/QvvF4it4hng7xx5GqcOD7WDzCVXUBTdWCbK/41kCOrTV8kfpu7hzJReCwZeBLlymuQ==
|
||||
dependencies:
|
||||
"@fluentui/merge-styles" "^8.5.0"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/style-utilities" "^8.6.4"
|
||||
"@fluentui/utilities" "^8.8.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/keyboard-key@^0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/keyboard-key/-/keyboard-key-0.4.0.tgz#25e138764a4d7764050d19048da45bc86da498a2"
|
||||
integrity sha512-2jcD23FzOPaSXqWtfOSCzopkKtxTXUFuHZyVt4aqVRDEjPbkQ/7p37O1WL95xweWTR/9fEPO/gPtv9kOnXrJcA==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/merge-styles@^8.5.0":
|
||||
version "8.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/merge-styles/-/merge-styles-8.5.0.tgz#bb9d97a53ae77011994297bbefd7ae1d119bbbe2"
|
||||
integrity sha512-+WoaAaoYx/wfkrz1Ag40JqHvDUFfQcg+dQ3jaEOoau16y7EZGIe7oN8WYIXNMgWuMxH7r1QlanFbQZ+ziKjHmw==
|
||||
dependencies:
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/react-focus@^8.5.4":
|
||||
version "8.5.4"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/react-focus/-/react-focus-8.5.4.tgz#38bd4d50ee3307f40b5abbca817cbad05d055a61"
|
||||
integrity sha512-SjCz1IJn1T6a6o6xcaEPd5Hou9B3QbpheHNxKWOJSQHG6wazwnHJRhNyTcgiX5+D1KEbnO757EoyOoxIVsnENQ==
|
||||
dependencies:
|
||||
"@fluentui/keyboard-key" "^0.4.0"
|
||||
"@fluentui/merge-styles" "^8.5.0"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/style-utilities" "^8.6.4"
|
||||
"@fluentui/utilities" "^8.8.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/react-hooks@^8.5.2":
|
||||
version "8.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/react-hooks/-/react-hooks-8.5.2.tgz#074224b5300539b1d2968c1107f963323424b333"
|
||||
integrity sha512-YqyLDa/1SbQSrfGQ+nBUvQYJo2wOWGDAhQbdWTwQGjG7jEmRfmScqMY+KJGjM/Gisn6v8CG5d1duSZLmbm0syA==
|
||||
dependencies:
|
||||
"@fluentui/react-window-provider" "^2.2.0"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/utilities" "^8.8.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/react-icon-provider@^1.3.4":
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/react-icon-provider/-/react-icon-provider-1.3.4.tgz#32e0e29f22c55e2db1d7d3d486972cccbf6a6145"
|
||||
integrity sha512-owU2SXkP1kSFOuZUIHXQwK9NaJrtbT4RKhRd8lCsmRN31+zvC+bUkcegup6bFFUwtIt7Tu8TRv5v70j3YJKvAA==
|
||||
dependencies:
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/style-utilities" "^8.6.4"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/react-icons-mdl2@^1.3.4":
|
||||
version "1.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/react-icons-mdl2/-/react-icons-mdl2-1.3.4.tgz#b8ee52940ddbb41c5fc8b5f9f2ee6cadef57b2aa"
|
||||
integrity sha512-5nUxzNtg0wmPjh8qnijEu2asj+xsSpHZJc/jYzTRC2L/BZ9nDpDZX12wdAc2chmOn7THoi7Tw7Wnp6Ohd8Q0EA==
|
||||
dependencies:
|
||||
"@fluentui/react-icon-provider" "^1.3.4"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/utilities" "^8.8.0"
|
||||
"@microsoft/load-themed-styles" "^1.10.26"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/react-window-provider@^2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/react-window-provider/-/react-window-provider-2.2.0.tgz#c3ae2d89c9ee802d8c572f689d907da25f74396b"
|
||||
integrity sha512-1iZzfVQHZQn6IJSJD1pxnXi5H8T3vrZYi9aqKyVIPZ12DCTVE2gw8W3mnOjsfVuXMGdv1sA7dgd6v4xi9erBow==
|
||||
dependencies:
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/react@^8.61.0":
|
||||
version "8.61.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/react/-/react-8.61.0.tgz#a97408dea1fcd6ed49f74cfbaf37e3881d992fa8"
|
||||
integrity sha512-VgQMF/4prqorln9xstMWdEhqdLS0jc+GYsKB5vidLxKmUDSGpTnhOiJ6PJLEz4jgaSN2S59Kd71rFEEGjbn3Nw==
|
||||
dependencies:
|
||||
"@fluentui/date-time-utilities" "^8.5.0"
|
||||
"@fluentui/font-icons-mdl2" "^8.2.4"
|
||||
"@fluentui/foundation-legacy" "^8.2.4"
|
||||
"@fluentui/merge-styles" "^8.5.0"
|
||||
"@fluentui/react-focus" "^8.5.4"
|
||||
"@fluentui/react-hooks" "^8.5.2"
|
||||
"@fluentui/react-window-provider" "^2.2.0"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/style-utilities" "^8.6.4"
|
||||
"@fluentui/theme" "^2.6.3"
|
||||
"@fluentui/utilities" "^8.8.0"
|
||||
"@microsoft/load-themed-styles" "^1.10.26"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/set-version@^8.2.0":
|
||||
version "8.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/set-version/-/set-version-8.2.0.tgz#8b13b9532250e98fad4498de8ac4537e0561c6c2"
|
||||
integrity sha512-bqjpfhqaIkBy16vdYzdc7tER9Td7BTcmC+kCXuqkHOQVuG9LJfqVGRV0DA857KLhOxiy0GXwKMeDbNV5jJf6qQ==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/style-utilities@^8.6.4":
|
||||
version "8.6.4"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/style-utilities/-/style-utilities-8.6.4.tgz#fc1767bae9cfd9643a0eed02f75a9094d48b0a90"
|
||||
integrity sha512-jWG5zq7nc37Q6O1LzaoU2U8Ki4Xo5ySm3d5uzefDsEIQpK9E22c1mpUI3hDWwWKILxF3S3dYkHNqbsGH72JYaw==
|
||||
dependencies:
|
||||
"@fluentui/merge-styles" "^8.5.0"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/theme" "^2.6.3"
|
||||
"@fluentui/utilities" "^8.8.0"
|
||||
"@microsoft/load-themed-styles" "^1.10.26"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/theme@^2.6.3":
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/theme/-/theme-2.6.3.tgz#98851d56d23dde5e0d293c6434432fb20bd3e9dd"
|
||||
integrity sha512-fqqRDnbbPjSbY8PdbsSJMYidhFdjdSoYuDab5n8yiePEHyWQ5OcQFkf1j6V7dg+2fZvW3XTWWSQEboQl+kTdNQ==
|
||||
dependencies:
|
||||
"@fluentui/merge-styles" "^8.5.0"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
"@fluentui/utilities" "^8.8.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@fluentui/utilities@^8.8.0":
|
||||
version "8.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@fluentui/utilities/-/utilities-8.8.0.tgz#765887a0596c73cb5330fb12c1a17d6ff72cf315"
|
||||
integrity sha512-IwKN9ZkYMJApzcvJUlJd4ZURJCMwZG8FNsep05GAcDzynZygvH2Y1ECpIFn9VTSsrKxMKYFIQ61Rwg+AW/eBcw==
|
||||
dependencies:
|
||||
"@fluentui/dom-utilities" "^2.2.0"
|
||||
"@fluentui/merge-styles" "^8.5.0"
|
||||
"@fluentui/set-version" "^8.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
"@gar/promisify@^1.0.1":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
|
||||
|
@ -1189,6 +1348,11 @@
|
|||
lodash "^4.17.15"
|
||||
tmp-promise "^3.0.2"
|
||||
|
||||
"@microsoft/load-themed-styles@^1.10.26":
|
||||
version "1.10.247"
|
||||
resolved "https://registry.yarnpkg.com/@microsoft/load-themed-styles/-/load-themed-styles-1.10.247.tgz#964ef32836a050c09486a6e9d092e50c9fb642ec"
|
||||
integrity sha512-vKbuG3Mcbc4kkNAcIE13aIv5KoI2g+tHFFIZnFhtUilpYHc0VsMd4Fw7Jz81A8AB7L3wWu3OZB2CNiRnr1a3ew==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
|
||||
|
|
Reference in a new issue