kopia lustrzana https://github.com/bellingcat/auto-archiver
Remove unused files, set up for RTD
rodzic
15da907e81
commit
1141c00e9a
|
@ -9,6 +9,7 @@ build:
|
||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
tools:
|
tools:
|
||||||
python: "3.10"
|
python: "3.10"
|
||||||
|
node: "22"
|
||||||
jobs:
|
jobs:
|
||||||
post_install:
|
post_install:
|
||||||
- pip install poetry
|
- pip install poetry
|
||||||
|
@ -17,6 +18,9 @@ build:
|
||||||
# See https://github.com/readthedocs/readthedocs.org/pull/11152/
|
# See https://github.com/readthedocs/readthedocs.org/pull/11152/
|
||||||
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs
|
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs
|
||||||
|
|
||||||
|
# install node dependencies and build the settings
|
||||||
|
- cd scripts/settings && npm install && npm run build && cp dist/index.html ../../docs/source/installation/settings_base.html && cd ../..
|
||||||
|
|
||||||
|
|
||||||
sphinx:
|
sphinx:
|
||||||
configuration: docs/source/conf.py
|
configuration: docs/source/conf.py
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Configuration Editor
|
||||||
|
|
||||||
|
```{raw} html
|
||||||
|
:file: settings.html
|
||||||
|
```
|
File diff suppressed because one or more lines are too long
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
installation.md
|
installation.md
|
||||||
configurations.md
|
configurations.md
|
||||||
|
config_editor.md
|
||||||
authentication.md
|
authentication.md
|
||||||
requirements.md
|
requirements.md
|
||||||
config_cheatsheet.md
|
config_cheatsheet.md
|
||||||
|
|
|
@ -23,7 +23,7 @@ for module in available_modules:
|
||||||
|
|
||||||
all_modules_ordered_by_type = sorted(available_modules, key=lambda x: (MODULE_TYPES.index(x.type[0]), not x.requires_setup))
|
all_modules_ordered_by_type = sorted(available_modules, key=lambda x: (MODULE_TYPES.index(x.type[0]), not x.requires_setup))
|
||||||
|
|
||||||
output_schame = {
|
output_schema = {
|
||||||
'modules': dict((module.name,
|
'modules': dict((module.name,
|
||||||
{
|
{
|
||||||
'name': module.name,
|
'name': module.name,
|
||||||
|
@ -40,4 +40,4 @@ output_schame = {
|
||||||
current_file_dir = os.path.dirname(os.path.abspath(__file__))
|
current_file_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
output_file = os.path.join(current_file_dir, 'settings/src/schema.json')
|
output_file = os.path.join(current_file_dir, 'settings/src/schema.json')
|
||||||
with open(output_file, 'w') as file:
|
with open(output_file, 'w') as file:
|
||||||
json.dump(output_schame, file, indent=4, cls=SchemaEncoder)
|
json.dump(output_schema, file, indent=4, cls=SchemaEncoder)
|
|
@ -2,7 +2,6 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
||||||
<meta name="viewport" content="initial-scale=1, width=device-width" />
|
<meta name="viewport" content="initial-scale=1, width=device-width" />
|
||||||
<!-- Fonts to support Material Design -->
|
<!-- Fonts to support Material Design -->
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
Przed Szerokość: | Wysokość: | Rozmiar: 1.5 KiB |
|
@ -27,7 +27,7 @@ import type { DragStartEvent, DragEndEvent, UniqueIdentifier } from "@dnd-kit/co
|
||||||
import { Module } from './types';
|
import { Module } from './types';
|
||||||
|
|
||||||
import { modules, steps, module_types } from './schema.json';
|
import { modules, steps, module_types } from './schema.json';
|
||||||
import {
|
import {
|
||||||
Stack,
|
Stack,
|
||||||
Button,
|
Button,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
@ -50,7 +50,7 @@ function FileDrop({ setYamlFile }: { setYamlFile: React.Dispatch<React.SetStateA
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let reader = new FileReader();
|
let reader = new FileReader();
|
||||||
reader.onload = function(e) {
|
reader.onload = function (e) {
|
||||||
let contents = e.target ? e.target.result : '';
|
let contents = e.target ? e.target.result : '';
|
||||||
try {
|
try {
|
||||||
let document = parseDocument(contents as string);
|
let document = parseDocument(contents as string);
|
||||||
|
@ -72,13 +72,13 @@ function FileDrop({ setYamlFile }: { setYamlFile: React.Dispatch<React.SetStateA
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div style={{width:'100%', border:'dashed', textAlign:'center', borderWidth:'1px', padding:'20px'}}>
|
<div style={{ width: '100%', border: 'dashed', textAlign: 'center', borderWidth: '1px', padding: '20px' }}>
|
||||||
|
|
||||||
<input name="file" type="file" accept=".yaml" onChange={openYAMLFile} />
|
<input name="file" type="file" accept=".yaml" onChange={openYAMLFile} />
|
||||||
<Typography style={{marginTop:'20px' }} variant="body1" color={showError ? 'error' : ''} >
|
<Typography style={{ marginTop: '20px' }} variant="body1" color={showError ? 'error' : ''} >
|
||||||
{label}
|
{label}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -91,13 +91,13 @@ function ModuleTypes({ stepType, setEnabledModules, enabledModules, configValues
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setItems(enabledModules[stepType].map(([name, enabled]: [string, boolean]) => name));
|
setItems(enabledModules[stepType].map(([name, enabled]: [string, boolean]) => name));
|
||||||
}
|
}
|
||||||
, [enabledModules]);
|
, [enabledModules]);
|
||||||
|
|
||||||
const toggleModule = (event: any) => {
|
const toggleModule = (event: any) => {
|
||||||
// make sure that 'feeder' and 'formatter' types only have one value
|
// make sure that 'feeder' and 'formatter' types only have one value
|
||||||
let name = event.target.id;
|
let name = event.target.id;
|
||||||
let checked = event.target.checked;
|
let checked = event.target.checked;
|
||||||
if (stepType === 'feeder' || stepType === 'formatter') {
|
if (stepType === 'feeders' || stepType === 'formatters') {
|
||||||
// check how many modules of this type are enabled
|
// check how many modules of this type are enabled
|
||||||
const checkedModules = enabledModules[stepType].filter(([m, enabled]: [string, boolean]) => {
|
const checkedModules = enabledModules[stepType].filter(([m, enabled]: [string, boolean]) => {
|
||||||
return (m !== name && enabled) || (checked && m === name)
|
return (m !== name && enabled) || (checked && m === name)
|
||||||
|
@ -110,11 +110,11 @@ function ModuleTypes({ stepType, setEnabledModules, enabledModules, configValues
|
||||||
} else {
|
} else {
|
||||||
setShowError(false);
|
setShowError(false);
|
||||||
}
|
}
|
||||||
let newEnabledModules = Object.fromEntries(Object.keys(enabledModules).map((type : string) => {
|
let newEnabledModules = Object.fromEntries(Object.keys(enabledModules).map((type: string) => {
|
||||||
return [type, enabledModules[type].map(([m, enabled]: [string, boolean]) => {
|
return [type, enabledModules[type].map(([m, enabled]: [string, boolean]) => {
|
||||||
return (m === name) ? [m, checked] : [m, enabled];
|
return (m === name) ? [m, checked] : [m, enabled];
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
setEnabledModules(newEnabledModules);
|
setEnabledModules(newEnabledModules);
|
||||||
}
|
}
|
||||||
|
@ -135,61 +135,62 @@ function ModuleTypes({ stepType, setEnabledModules, enabledModules, configValues
|
||||||
const { active, over } = event;
|
const { active, over } = event;
|
||||||
|
|
||||||
if (active.id !== over?.id) {
|
if (active.id !== over?.id) {
|
||||||
const oldIndex = items.indexOf(active.id as string);
|
const oldIndex = items.indexOf(active.id as string);
|
||||||
const newIndex = items.indexOf(over?.id as string);
|
const newIndex = items.indexOf(over?.id as string);
|
||||||
|
|
||||||
let newArray = arrayMove(items, oldIndex, newIndex);
|
let newArray = arrayMove(items, oldIndex, newIndex);
|
||||||
// set it also on steps
|
// set it also on steps
|
||||||
let newEnabledModules = { ...enabledModules };
|
let newEnabledModules = { ...enabledModules };
|
||||||
newEnabledModules[stepType] = enabledModules[stepType].sort((a, b) => {
|
newEnabledModules[stepType] = enabledModules[stepType].sort((a, b) => {
|
||||||
return newArray.indexOf(a[0]) - newArray.indexOf(b[0]);
|
return newArray.indexOf(a[0]) - newArray.indexOf(b[0]);
|
||||||
})
|
})
|
||||||
setEnabledModules(newEnabledModules);
|
setEnabledModules(newEnabledModules);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box sx={{ my: 4 }}>
|
<Box sx={{ my: 4 }}>
|
||||||
<Typography id={stepType} variant="h6" style={{ textTransform: 'capitalize' }} >
|
<Typography id={stepType} variant="h6" style={{ textTransform: 'capitalize' }} >
|
||||||
{stepType}
|
{stepType}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" >
|
<Typography variant="body1" >
|
||||||
Select the {stepType} you wish to enable. You can drag and drop them to reorder them.
|
Select the {stepType} you wish to enable. You can drag and move to reorder.
|
||||||
</Typography>
|
Learn more about {stepType} <a href={`https://auto-archiver.readthedocs.io/en/latest/modules/${stepType.slice(0,-1)}.html`} target="_blank">here</a>.
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
{showError ? <Typography variant="body1" color="error" >Only one {stepType} can be enabled at a time.</Typography> : null}
|
{showError ? <Typography variant="body1" color="error" >Only one {stepType.slice(0,-1)} can be enabled at a time.</Typography> : null}
|
||||||
|
|
||||||
<DndContext
|
<DndContext
|
||||||
sensors={sensors}
|
sensors={sensors}
|
||||||
collisionDetection={closestCenter}
|
collisionDetection={closestCenter}
|
||||||
onDragEnd={handleDragEnd}
|
onDragEnd={handleDragEnd}
|
||||||
onDragStart={handleDragStart}
|
onDragStart={handleDragStart}
|
||||||
>
|
>
|
||||||
<Grid container spacing={1} key={stepType}>
|
<Grid container spacing={1} key={stepType}>
|
||||||
<SortableContext items={items} strategy={rectSortingStrategy}>
|
<SortableContext items={items} strategy={rectSortingStrategy}>
|
||||||
{items.map((name: string) => {
|
{items.map((name: string) => {
|
||||||
let m: Module = modules[name];
|
let m: Module = modules[name];
|
||||||
return (
|
return (
|
||||||
<StepCard key={name} type={stepType} module={m} toggleModule={toggleModule} enabledModules={enabledModules} configValues={configValues} />
|
<StepCard key={name} type={stepType} module={m} toggleModule={toggleModule} enabledModules={enabledModules} configValues={configValues} />
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<DragOverlay>
|
<DragOverlay>
|
||||||
{activeId ? (
|
{activeId ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
backgroundColor: "grey",
|
backgroundColor: "grey",
|
||||||
opacity:0.1,
|
opacity: 0.1,
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
|
|
||||||
) : null}
|
) : null}
|
||||||
</DragOverlay>
|
</DragOverlay>
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,41 +210,41 @@ export default function App() {
|
||||||
}, {})
|
}, {})
|
||||||
);
|
);
|
||||||
|
|
||||||
const saveSettings = function(copy: boolean = false) {
|
const saveSettings = function (copy: boolean = false) {
|
||||||
// edit the yamlFile
|
// edit the yamlFile
|
||||||
|
|
||||||
// generate the steps config
|
// generate the steps config
|
||||||
let stepsConfig = enabledModules;
|
let stepsConfig = enabledModules;
|
||||||
|
|
||||||
// create a yaml file from
|
// create a yaml file from
|
||||||
const finalYaml = {
|
const finalYaml = {
|
||||||
'steps': Object.keys(steps).reduce((acc, stepType: string) => {
|
'steps': Object.keys(steps).reduce((acc, stepType: string) => {
|
||||||
acc[stepType] = stepsConfig[stepType].filter(([name, enabled]: [string, boolean]) => enabled).map(([name, enabled]: [string, boolean]) => name);
|
acc[stepType] = stepsConfig[stepType].filter(([name, enabled]: [string, boolean]) => enabled).map(([name, enabled]: [string, boolean]) => name);
|
||||||
return acc;
|
return acc;
|
||||||
}, {})
|
}, {})
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(configValues).map((module: string) => {
|
Object.keys(configValues).map((module: string) => {
|
||||||
let module_values = configValues[module];
|
let module_values = configValues[module];
|
||||||
if (module_values) {
|
if (module_values) {
|
||||||
finalYaml[module] = module_values;
|
finalYaml[module] = module_values;
|
||||||
}
|
|
||||||
});
|
|
||||||
let newFile = new Document(finalYaml);
|
|
||||||
if (copy) {
|
|
||||||
navigator.clipboard.writeText(String(newFile)).then(() => {
|
|
||||||
alert("Settings copied to clipboard.");
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// offer the file for download
|
|
||||||
const blob = new Blob([String(newFile)], { type: 'application/x-yaml' });
|
|
||||||
const url = URL.createObjectURL(blob);
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.href = url;
|
|
||||||
a.download = 'orchestration.yaml';
|
|
||||||
a.click();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
let newFile = new Document(finalYaml);
|
||||||
|
if (copy) {
|
||||||
|
navigator.clipboard.writeText(String(newFile)).then(() => {
|
||||||
|
alert("Settings copied to clipboard.");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// offer the file for download
|
||||||
|
const blob = new Blob([String(newFile)], { type: 'application/x-yaml' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'orchestration.yaml';
|
||||||
|
a.click();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// load the configs, and set the default values if they exist
|
// load the configs, and set the default values if they exist
|
||||||
|
@ -262,7 +263,7 @@ export default function App() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
setConfigValues(newConfigValues);
|
setConfigValues(newConfigValues);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -274,25 +275,25 @@ export default function App() {
|
||||||
// make a deep copy of settings
|
// make a deep copy of settings
|
||||||
let stepSettings = settings['steps'];
|
let stepSettings = settings['steps'];
|
||||||
let newEnabledModules = Object.fromEntries(Object.keys(steps).map((type: string) => {
|
let newEnabledModules = Object.fromEntries(Object.keys(steps).map((type: string) => {
|
||||||
return [type, steps[type].map((name: string) => {
|
return [type, steps[type].map((name: string) => {
|
||||||
return [name, stepSettings[type].indexOf(name) !== -1];
|
return [name, stepSettings[type].indexOf(name) !== -1];
|
||||||
}).sort((a, b) => {
|
|
||||||
let aIndex = stepSettings[type].indexOf(a[0]);
|
|
||||||
let bIndex = stepSettings[type].indexOf(b[0]);
|
|
||||||
if (aIndex === -1 && bIndex === -1) {
|
|
||||||
return a - b;
|
|
||||||
}
|
|
||||||
if (bIndex === -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (aIndex === -1) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return aIndex - bIndex;
|
|
||||||
})];
|
|
||||||
}).sort((a, b) => {
|
}).sort((a, b) => {
|
||||||
return module_types.indexOf(a[0]) - module_types.indexOf(b[0]);
|
let aIndex = stepSettings[type].indexOf(a[0]);
|
||||||
}));
|
let bIndex = stepSettings[type].indexOf(b[0]);
|
||||||
|
if (aIndex === -1 && bIndex === -1) {
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
if (bIndex === -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (aIndex === -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return aIndex - bIndex;
|
||||||
|
})];
|
||||||
|
}).sort((a, b) => {
|
||||||
|
return module_types.indexOf(a[0]) - module_types.indexOf(b[0]);
|
||||||
|
}));
|
||||||
setEnabledModules(newEnabledModules);
|
setEnabledModules(newEnabledModules);
|
||||||
}, [yamlFile]);
|
}, [yamlFile]);
|
||||||
|
|
||||||
|
@ -301,44 +302,41 @@ export default function App() {
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg">
|
||||||
<Box sx={{ my: 4 }}>
|
<Box sx={{ my: 4 }}>
|
||||||
<Typography variant="h2" >
|
|
||||||
Auto Archiver Settings
|
|
||||||
</Typography>
|
|
||||||
<Box sx={{ my: 4 }}>
|
<Box sx={{ my: 4 }}>
|
||||||
<Typography variant="h5" >
|
<Typography variant="h5" >
|
||||||
1. Select your <pre style={{display:'inline'}}>orchestration.yaml</pre> settings file.
|
1. Select your orchestration.yaml settings file.
|
||||||
</Typography>
|
</Typography>
|
||||||
<FileDrop setYamlFile={setYamlFile}/>
|
<FileDrop setYamlFile={setYamlFile} />
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ my: 4 }}>
|
<Box sx={{ my: 4 }}>
|
||||||
<Typography variant="h5" >
|
<Typography variant="h5" >
|
||||||
2. Choose the Modules you wish to enable/disable
|
2. Choose the Modules you wish to enable/disable
|
||||||
</Typography>
|
</Typography>
|
||||||
{Object.keys(steps).map((stepType: string) => {
|
{Object.keys(steps).map((stepType: string) => {
|
||||||
return (
|
return (
|
||||||
<Box key={stepType} sx={{ my: 4 }}>
|
<Box key={stepType} sx={{ my: 4 }}>
|
||||||
<ModuleTypes stepType={stepType} setEnabledModules={setEnabledModules} enabledModules={enabledModules} configValues={configValues} />
|
<ModuleTypes stepType={stepType} setEnabledModules={setEnabledModules} enabledModules={enabledModules} configValues={configValues} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ my: 4 }}>
|
<Box sx={{ my: 4 }}>
|
||||||
<Typography variant="h5" >
|
<Typography variant="h5" >
|
||||||
3. Configure your Enabled Modules
|
3. Configure your Enabled Modules
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body1" >
|
<Typography variant="body1" >
|
||||||
Next to each module you've enabled, you can click 'Configure' to set the module's settings.
|
Next to each module you've enabled, you can click 'Configure' to set the module's settings.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ my: 4 }}>
|
<Box sx={{ my: 4 }}>
|
||||||
<Typography variant="h5" >
|
<Typography variant="h5" >
|
||||||
4. Save your settings
|
4. Save your settings
|
||||||
</Typography>
|
</Typography>
|
||||||
<Stack direction="row" spacing={2} sx={{ my: 2 }}>
|
<Stack direction="row" spacing={2} sx={{ my: 2 }}>
|
||||||
<Button variant="contained" color="primary" onClick={() => saveSettings(true)}>Copy Settings to Clipboard</Button>
|
<Button variant="contained" color="primary" onClick={() => saveSettings(true)}>Copy Settings to Clipboard</Button>
|
||||||
<Button variant="contained" color="primary" onClick={() => saveSettings()}>Save Settings to File</Button>
|
<Button variant="contained" color="primary" onClick={() => saveSettings()}>Save Settings to File</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import Link from '@mui/material/Link';
|
|
||||||
import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
|
|
||||||
import Typography from '@mui/material/Typography';
|
|
||||||
|
|
||||||
function LightBulbIcon(props: SvgIconProps) {
|
|
||||||
return (
|
|
||||||
<SvgIcon {...props}>
|
|
||||||
<path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z" />
|
|
||||||
</SvgIcon>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProTip() {
|
|
||||||
return (
|
|
||||||
<Typography sx={{ mt: 6, mb: 3, color: 'text.secondary' }}>
|
|
||||||
<LightBulbIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
|
|
||||||
{'Pro tip: See more '}
|
|
||||||
<Link href="https://mui.com/material-ui/getting-started/templates/">templates</Link>
|
|
||||||
{' in the Material UI documentation.'}
|
|
||||||
</Typography>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import ReactMarkdown from 'react-markdown';
|
||||||
|
|
||||||
import { CSS } from "@dnd-kit/utilities";
|
import { CSS } from "@dnd-kit/utilities";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardActions,
|
CardActions,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
|
@ -23,17 +23,22 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
Stack,
|
Stack,
|
||||||
Typography,
|
Typography,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import Grid from '@mui/material/Grid2';
|
import Grid from '@mui/material/Grid2';
|
||||||
import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
|
import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
|
||||||
import { Module } from "./types";
|
import HelpIconOutlined from '@mui/icons-material/HelpOutline';
|
||||||
|
import { Module, Config } from "./types";
|
||||||
|
|
||||||
Object.defineProperty(String.prototype, 'capitalize', {
|
|
||||||
value: function() {
|
// adds 'capitalize' method to String prototype
|
||||||
|
declare global {
|
||||||
|
interface String {
|
||||||
|
capitalize(): string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String.prototype.capitalize = function (this: string) {
|
||||||
return this.charAt(0).toUpperCase() + this.slice(1);
|
return this.charAt(0).toUpperCase() + this.slice(1);
|
||||||
},
|
};
|
||||||
enumerable: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const StepCard = ({
|
const StepCard = ({
|
||||||
type,
|
type,
|
||||||
|
@ -46,7 +51,7 @@ const StepCard = ({
|
||||||
module: Module,
|
module: Module,
|
||||||
toggleModule: any,
|
toggleModule: any,
|
||||||
enabledModules: any,
|
enabledModules: any,
|
||||||
configValues: any
|
configValues: any
|
||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
|
@ -55,147 +60,157 @@ const StepCard = ({
|
||||||
transform,
|
transform,
|
||||||
transition,
|
transition,
|
||||||
isDragging
|
isDragging
|
||||||
} = useSortable({ id: module.name });
|
} = useSortable({ id: module.name });
|
||||||
|
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
transform: CSS.Transform.toString(transform),
|
transform: CSS.Transform.toString(transform),
|
||||||
transition,
|
transition,
|
||||||
zIndex: isDragging ? "100" : "auto",
|
zIndex: isDragging ? "100" : "auto",
|
||||||
opacity: isDragging ? 0.3 : 1
|
opacity: isDragging ? 0.3 : 1
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = module.name;
|
let name = module.name;
|
||||||
const [helpOpen, setHelpOpen] = useState(false);
|
const [helpOpen, setHelpOpen] = useState(false);
|
||||||
const [configOpen, setConfigOpen] = useState(false);
|
const [configOpen, setConfigOpen] = useState(false);
|
||||||
const enabled = enabledModules[type].find((m: any) => m[0] === name)[1];
|
const enabled = enabledModules[type].find((m: any) => m[0] === name)[1];
|
||||||
|
|
||||||
return (
|
|
||||||
<Grid ref={setNodeRef} size={{ xs: 6, sm: 4, md: 3 }} style={style}>
|
|
||||||
<Card>
|
|
||||||
<CardHeader
|
|
||||||
title={
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Checkbox id={name} onClick={toggleModule} checked={enabled} />}
|
|
||||||
label={module.display_name} />
|
|
||||||
}
|
|
||||||
action ={
|
|
||||||
<IconButton size="small" {...listeners} {...attributes}>
|
|
||||||
<DragIndicatorIcon />
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<CardActions>
|
|
||||||
<Button size="small" onClick={() => setHelpOpen(true)}>Info</Button>
|
|
||||||
{enabled && module.configs && name != 'cli_feeder' ? (
|
|
||||||
<Button size="small" onClick={() => setConfigOpen(true)}>Configure</Button>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
</CardActions>
|
return (
|
||||||
</Card>
|
<Grid ref={setNodeRef} size={{ xs: 6, sm: 4, md: 3 }} style={style}>
|
||||||
<Dialog
|
<Card >
|
||||||
open={helpOpen}
|
<CardHeader
|
||||||
onClose={() => setHelpOpen(false)}
|
title={
|
||||||
maxWidth="lg"
|
<FormControlLabel
|
||||||
>
|
style={{paddingRight: '0 !important'}}
|
||||||
<DialogTitle>
|
control={<Checkbox sx={{paddingTop:0, paddingBottom:0}} id={name} onClick={toggleModule} checked={enabled} />}
|
||||||
{module.display_name}
|
label={module.display_name} />
|
||||||
</DialogTitle>
|
}
|
||||||
<DialogContent>
|
/>
|
||||||
<ReactMarkdown>
|
<CardActions>
|
||||||
{module.manifest.description.split("\n").map((line: string) => line.trim()).join("\n")}
|
<Box sx={{ justifyContent: 'space-between', display: 'flex', width: '100%' }}>
|
||||||
</ReactMarkdown>
|
<Box>
|
||||||
</DialogContent>
|
<IconButton size="small" onClick={() => setHelpOpen(true)}>
|
||||||
</Dialog>
|
<HelpIconOutlined />
|
||||||
{module.configs && name != 'cli_feeder' && <ConfigPanel module={module} open={configOpen} setOpen={setConfigOpen} configValues={configValues} />}
|
</IconButton>
|
||||||
</Grid>
|
{enabled && module.configs && name != 'cli_feeder' ? (
|
||||||
|
<Button size="small" onClick={() => setConfigOpen(true)}>Configure</Button>
|
||||||
|
) : null}
|
||||||
|
</Box>
|
||||||
|
<IconButton size="small" sx={{textAlight: 'right', cursor: 'grab' }} {...listeners} {...attributes}>
|
||||||
|
<DragIndicatorIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Box>
|
||||||
|
</CardActions>
|
||||||
|
</Card>
|
||||||
|
<Dialog
|
||||||
|
open={helpOpen}
|
||||||
|
onClose={() => setHelpOpen(false)}
|
||||||
|
maxWidth="lg"
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
{module.display_name}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<ReactMarkdown>
|
||||||
|
{module.manifest.description.split("\n").map((line: string) => line.trim()).join("\n")}
|
||||||
|
</ReactMarkdown>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
{module.configs && name != 'cli_feeder' && <ConfigPanel module={module} open={configOpen} setOpen={setConfigOpen} configValues={configValues} />}
|
||||||
|
</Grid>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ConfigPanel({ module, open, setOpen, configValues }: { module: any, open: boolean, setOpen: any, configValues: any }) {
|
|
||||||
|
|
||||||
|
function ConfigField({ config_value, module, configValues }: { config_value: any, module: Module, configValues: any }) {
|
||||||
function setConfigValue(config: any, value: any) {
|
function setConfigValue(config: any, value: any) {
|
||||||
configValues[module.name][config] = value;
|
configValues[module.name][config] = value;
|
||||||
}
|
}
|
||||||
|
const config_args: Config = module.configs[config_value];
|
||||||
|
const config_name: string = config_value.replace(/_/g, " ");
|
||||||
|
const config_display_name = config_name.capitalize();
|
||||||
|
const value = configValues[module.name][config_value] || config_args.default;
|
||||||
return (
|
return (
|
||||||
<>
|
<Box>
|
||||||
<Dialog
|
<Typography variant='body1' style={{ fontWeight: 'bold' }}>{config_display_name} {config_args.required && (`(required)`)} </Typography>
|
||||||
key={module}
|
<FormControl size="small">
|
||||||
open={open}
|
{config_args.type === 'bool' ?
|
||||||
onClose={() => setOpen(false)}
|
<FormControlLabel control={
|
||||||
maxWidth="lg"
|
<Checkbox defaultChecked={value} size="small" id={`${module}.${config_value}`}
|
||||||
>
|
onChange={(e) => {
|
||||||
<DialogTitle>
|
setConfigValue(config_value, e.target.checked);
|
||||||
{module.display_name}
|
}}
|
||||||
</DialogTitle>
|
/>} label={config_args.help}
|
||||||
<DialogContent>
|
/>
|
||||||
<Stack key={module} direction="column" spacing={1}>
|
|
||||||
{Object.keys(module.configs).map((config_value: any) => {
|
|
||||||
const config_args = module.configs[config_value];
|
|
||||||
const config_name = config_value.replace(/_/g," ");
|
|
||||||
const config_display_name = config_name.capitalize();
|
|
||||||
const value = configValues[module.name][config_value] || config_args.default;
|
|
||||||
return (
|
|
||||||
<Box key={config_value}>
|
|
||||||
<Typography variant='body1' style={{fontWeight : 'bold'}}>{config_display_name}</Typography>
|
|
||||||
<FormControl size="small">
|
|
||||||
{ config_args.type === 'bool' ?
|
|
||||||
<FormControlLabel control={
|
|
||||||
<Checkbox defaultChecked={value} size="small" id={`${module}.${config_value}`}
|
|
||||||
onChange={(e) => {
|
|
||||||
setConfigValue(config_value, e.target.checked);
|
|
||||||
}}
|
|
||||||
/>} label={config_args.help}
|
|
||||||
/>
|
|
||||||
:
|
:
|
||||||
(
|
(
|
||||||
config_args.choices !== undefined ?
|
config_args.choices !== undefined ?
|
||||||
<Select size="small" id={`${module}.${config_value}`}
|
<Select size="small" id={`${module}.${config_value}`}
|
||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setConfigValue(config_value, e.target.value);
|
setConfigValue(config_value, e.target.value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{config_args.choices.map((choice: any) => {
|
{config_args.choices.map((choice: any) => {
|
||||||
return (
|
return (
|
||||||
<MenuItem key={`${module}.${config_value}.${choice}`}
|
<MenuItem key={`${module}.${config_value}.${choice}`}
|
||||||
value={choice}>{choice}</MenuItem>
|
value={choice}>{choice}</MenuItem>
|
||||||
);
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
:
|
||||||
|
(config_args.type === 'json_loader' ?
|
||||||
|
<TextField multiline size="small" id={`${module}.${config_value}`} defaultValue={JSON.stringify(value, null, 2)} rows={6} onChange={
|
||||||
|
(e) => {
|
||||||
|
try {
|
||||||
|
let val = JSON.parse(e.target.value);
|
||||||
|
setConfigValue(config_value, val);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} />
|
||||||
|
:
|
||||||
|
<TextField size="small" id={`${module}.${config_value}`} defaultValue={value} type={config_args.type === 'int' ? 'number' : 'text'}
|
||||||
|
onChange={(e) => {
|
||||||
|
setConfigValue(config_value, e.target.value);
|
||||||
|
}}
|
||||||
|
required={config_args.required}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{config_args.type !== 'bool' && (
|
||||||
|
<FormHelperText >{config_args.help.capitalize()}</FormHelperText>
|
||||||
|
)}
|
||||||
|
</FormControl>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ConfigPanel({ module, open, setOpen, configValues }: { module: Module, open: boolean, setOpen: any, configValues: any }) {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={() => setOpen(false)}
|
||||||
|
maxWidth="lg"
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
{module.display_name}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<Stack direction="column" spacing={1}>
|
||||||
|
{Object.keys(module.configs).map((config_value: any) => {
|
||||||
|
return (
|
||||||
|
<ConfigField key={config_value} config_value={config_value} module={module} configValues={configValues} />
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</Select>
|
</Stack>
|
||||||
:
|
</DialogContent>
|
||||||
( config_args.type === 'json_loader' ?
|
</Dialog>
|
||||||
<TextField multiline size="small" id={`${module}.${config_value}`} defaultValue={JSON.stringify(value, null, 2)} rows={6} onChange={
|
</>
|
||||||
(e) => {
|
|
||||||
try {
|
|
||||||
let val = JSON.parse(e.target.value);
|
|
||||||
setConfigValue(config_value, val);
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} />
|
|
||||||
:
|
|
||||||
<TextField size="small" id={`${module}.${config_value}`} defaultValue={value} type={config_args.type === 'int' ? 'number' : 'text'}
|
|
||||||
onChange={(e) => {
|
|
||||||
setConfigValue(config_value, e.target.value);
|
|
||||||
}} />
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
{config_args.type !== 'bool' && (
|
|
||||||
<FormHelperText >{config_args.help}</FormHelperText>
|
|
||||||
)}
|
|
||||||
</FormControl>
|
|
||||||
</Box>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Stack>
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StepCard;
|
export default StepCard;
|
|
@ -3,6 +3,9 @@ export interface Config {
|
||||||
description: string;
|
description: string;
|
||||||
type: string?;
|
type: string?;
|
||||||
default: any;
|
default: any;
|
||||||
|
help: string;
|
||||||
|
choices: string[];
|
||||||
|
required: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Manifest {
|
interface Manifest {
|
||||||
|
@ -15,4 +18,4 @@ export interface Module {
|
||||||
configs: { [key: string]: Config };
|
configs: { [key: string]: Config };
|
||||||
manifest: Manifest;
|
manifest: Manifest;
|
||||||
display_name: string;
|
display_name: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
/// <reference types="vite/client" />
|
|
Ładowanie…
Reference in New Issue