-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Show package details (name and description) * Link from package overview to package detail page * Render settings form if available (via react-jsonschema-form) * ADB wrapper functionalities to push and pull files
- Loading branch information
Showing
27 changed files
with
526 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import PropTypes from "prop-types"; | ||
import React, { | ||
useCallback, | ||
useEffect, | ||
} from "react"; | ||
import { | ||
useDispatch, | ||
useSelector, | ||
} from "react-redux"; | ||
import { useTranslation } from "react-i18next"; | ||
import { useParams } from "react-router-dom"; | ||
|
||
import validator from "@rjsf/validator-ajv6"; | ||
import Form from "@rjsf/mui"; | ||
|
||
import Alert from "@mui/material/Alert"; | ||
import Box from "@mui/material/Box"; | ||
import Button from "@mui/material/Button"; | ||
import Paper from "@mui/material/Paper"; | ||
import Stack from "@mui/material/Stack"; | ||
import Typography from "@mui/material/Typography"; | ||
|
||
import { | ||
fetchPackage, | ||
fetchConfig, | ||
reset, | ||
selectConfig, | ||
selectDescription, | ||
selectError, | ||
selectFetched, | ||
selectInstalled, | ||
selectLoading, | ||
selectName, | ||
selectSchema, | ||
selectWriting, | ||
writeConfig, | ||
} from "./packageSlice"; | ||
|
||
import { selectPassed } from "../healthcheck/healthcheckSlice"; | ||
import Spinner from "../loading/Spinner"; | ||
|
||
export default function Package({ adb }) { | ||
const { t } = useTranslation("package"); | ||
const dispatch = useDispatch(); | ||
|
||
let { packageSlug } = useParams(); | ||
|
||
const healthchecksPassed = useSelector(selectPassed); | ||
|
||
const packageName = useSelector(selectName); | ||
const description = useSelector(selectDescription); | ||
const installed = useSelector(selectInstalled); | ||
|
||
const fetched = useSelector(selectFetched); | ||
const config = useSelector(selectConfig); | ||
const schema = useSelector(selectSchema); | ||
|
||
const loading = useSelector(selectLoading); | ||
const writing = useSelector(selectWriting); | ||
const error = useSelector(selectError); | ||
|
||
/** | ||
* Fetch package details if healthchecks passed and dtails are not yet | ||
* set for the selected package. | ||
*/ | ||
useEffect(() => { | ||
if (!fetched && healthchecksPassed) { | ||
dispatch(fetchPackage({ | ||
adb, | ||
name: packageSlug, | ||
})); | ||
} | ||
}, [adb, dispatch, fetched, healthchecksPassed, packageSlug]); | ||
|
||
useEffect(() => { | ||
if(packageName !== packageSlug) { | ||
dispatch(reset()); | ||
} | ||
}, [dispatch, packageName, packageSlug]); | ||
|
||
// Fetch config and schema if package is installed | ||
useEffect(() => { | ||
if(installed) { | ||
dispatch(fetchConfig(adb)); | ||
} | ||
}, [adb, dispatch, installed]); | ||
|
||
const saveConfig = useCallback(({ formData }) => { | ||
dispatch(writeConfig({ | ||
adb, | ||
config: formData, | ||
})); | ||
}, [adb, dispatch]); | ||
|
||
return ( | ||
<Paper> | ||
<Box p={2}> | ||
<Stack spacing={2}> | ||
<Typography variant="h4"> | ||
{t("detailsFor", { name: packageSlug })} | ||
</Typography> | ||
|
||
{loading && | ||
<Spinner text={t("loading")} />} | ||
|
||
<Typography variant="body1"> | ||
{description} | ||
</Typography> | ||
|
||
{schema && | ||
<Form | ||
formData={config} | ||
onSubmit={saveConfig} | ||
schema={JSON.parse(JSON.stringify(schema))} | ||
validator={validator} | ||
> | ||
<Button | ||
disabled={writing} | ||
type="submit" | ||
variant="contained" | ||
> | ||
{t("submit")} | ||
</Button> | ||
</Form>} | ||
|
||
{error && | ||
<Alert severity="error"> | ||
{error} | ||
</Alert>} | ||
</Stack> | ||
</Box> | ||
</Paper> | ||
); | ||
} | ||
|
||
Package.propTypes = { adb: PropTypes.shape().isRequired }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { | ||
createAsyncThunk, | ||
createSlice, | ||
} from "@reduxjs/toolkit"; | ||
|
||
const initialState = { | ||
loading: true, | ||
fetched: false, | ||
|
||
name: null, | ||
description: null, | ||
installed: false, | ||
|
||
schema: null, | ||
config: null, | ||
|
||
writing: false, | ||
error: null, | ||
}; | ||
|
||
export const fetchPackage = createAsyncThunk( | ||
"package/fetchPackage", | ||
async ({ | ||
adb, | ||
name, | ||
}) => { | ||
return adb.getPackageDetails(name); | ||
} | ||
); | ||
|
||
export const fetchConfig = createAsyncThunk( | ||
"package/fetchConfig", | ||
async (adb, thunk) => { | ||
const name = thunk.getState().package.name; | ||
return adb.getPackageConfig(name); | ||
} | ||
); | ||
|
||
export const writeConfig = createAsyncThunk( | ||
"package/writeConfig", | ||
async ({ | ||
adb, | ||
config, | ||
}, thunk) => { | ||
const name = thunk.getState().package.name; | ||
const stringified = JSON.stringify(config, null, " "); | ||
await adb.writePackageConfig(name, stringified); | ||
|
||
return config; | ||
} | ||
); | ||
|
||
export const packageSlice = createSlice({ | ||
name: "package", | ||
initialState, | ||
reducers: { reset: () => initialState }, | ||
extraReducers: (builder) => { | ||
builder | ||
.addCase(fetchPackage.pending, (state) => { | ||
state.loading = true; | ||
}) | ||
.addCase(fetchPackage.fulfilled, (state, action) => { | ||
state.loading = false; | ||
state.fetched = true; | ||
|
||
state.name = action.payload.name; | ||
state.description = action.payload.description; | ||
state.installed = action.payload.installed; | ||
}).addCase(fetchConfig.pending, (state, action) => { | ||
state.config = null; | ||
state.schema = null; | ||
}).addCase(fetchConfig.fulfilled, (state, action) => { | ||
state.config = action.payload.config; | ||
state.schema = action.payload.schema; | ||
}).addCase(writeConfig.pending, (state, action) => { | ||
state.writing = true; | ||
}).addCase(writeConfig.fulfilled, (state, action) => { | ||
state.config = action.payload; | ||
state.writing = false; | ||
}).addCase(writeConfig.rejected, (state, action) => { | ||
state.error = action.error.message; | ||
}); | ||
}, | ||
|
||
}); | ||
|
||
export const { reset } = packageSlice.actions; | ||
|
||
export const selectFetched = (state) => state.package.fetched; | ||
|
||
export const selectName = (state) => state.package.name; | ||
export const selectDescription = (state) => state.package.description; | ||
export const selectInstalled = (state) => state.package.installed; | ||
|
||
export const selectWriting = (state) => state.package.writing; | ||
export const selectError = (state) => state.package.error; | ||
export const selectLoading = (state) => state.package.loading; | ||
|
||
export const selectConfig = (state) => state.package.config; | ||
export const selectSchema = (state) => state.package.schema; | ||
|
||
export default packageSlice.reducer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"detailsFor": "Details for:" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"detailsFor": "Details for: {{name}}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"detailsFor": "Details for {{name}}", | ||
"submit": "Save settings", | ||
"loading": "Loading package details..." | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"detailsFor": "Details for: {{name}}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"detailsFor": "Details for: {{name}}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"detailsFor": "Details for: {{name}}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"detailsFor": "Details for: {{name}}" | ||
} |
Oops, something went wrong.