mirror of
https://github.com/ragestudio/relic.git
synced 2025-06-09 02:24:18 +00:00
support config wizard
This commit is contained in:
parent
bdc0f6fbbd
commit
7c410f0a45
@ -22,12 +22,6 @@ export default async function apply(pkg_id, changes) {
|
||||
|
||||
console.log(`[${pkg_id}] apply() | Applying changes... >`, changes)
|
||||
|
||||
sendToRender(`pkg:update:status`, {
|
||||
id: pkg_id,
|
||||
status: "loading",
|
||||
statusText: "Applying changes...",
|
||||
})
|
||||
|
||||
if (Array.isArray(changes.patches)) {
|
||||
if (!Array.isArray(pkg.applied_patches)) {
|
||||
pkg.applied_patches = []
|
||||
@ -70,6 +64,12 @@ export default async function apply(pkg_id, changes) {
|
||||
pkg.applied_patches = pkg.applied_patches.filter((p) => {
|
||||
return p !== patch.id
|
||||
})
|
||||
|
||||
sendToRender(`pkg:update:status`, {
|
||||
id: pkg_id,
|
||||
status: "done",
|
||||
statusText: `Patch [${patch.id}] removed!`,
|
||||
})
|
||||
}
|
||||
|
||||
for await (let patch of installPatches) {
|
||||
@ -100,6 +100,12 @@ export default async function apply(pkg_id, changes) {
|
||||
|
||||
// add to applied patches
|
||||
pkg.applied_patches.push(patch.id)
|
||||
|
||||
sendToRender(`pkg:update:status`, {
|
||||
id: pkg_id,
|
||||
status: "done",
|
||||
statusText: `Patch [${patch.id}] applied!`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,8 +121,6 @@ export default async function apply(pkg_id, changes) {
|
||||
}
|
||||
}
|
||||
|
||||
pkg.status = "installed"
|
||||
|
||||
await updateInstalledPackage(pkg)
|
||||
|
||||
sendToRender(`new:notification`, {
|
||||
@ -126,7 +130,6 @@ export default async function apply(pkg_id, changes) {
|
||||
|
||||
sendToRender(`pkg:update:status`, {
|
||||
...pkg,
|
||||
status: "installed",
|
||||
statusText: "Changes applied!",
|
||||
})
|
||||
|
||||
|
@ -98,6 +98,10 @@ export default async function install(manifest) {
|
||||
})
|
||||
}
|
||||
|
||||
if (Array.isArray(pkg.install_ask_configs)) {
|
||||
sendToRender("pkg:install:ask", pkg)
|
||||
}
|
||||
|
||||
sendToRender(`pkg:update:status`, {
|
||||
id: pkg_id,
|
||||
status: "installed",
|
||||
|
@ -7,6 +7,7 @@ import getRootCssVar from "utils/getRootCssVar"
|
||||
|
||||
import ManifestInfo from "components/ManifestInfo"
|
||||
import PackageUpdateAvailable from "components/PackageUpdateAvailable"
|
||||
import InstallConfigAsk from "components/InstallConfigAsk"
|
||||
|
||||
import AppLayout from "layout"
|
||||
import AppModalDialog from "layout/components/ModalDialog"
|
||||
@ -42,6 +43,14 @@ window.app = {
|
||||
}
|
||||
})
|
||||
},
|
||||
pkgInstallWizard: (manifest) => {
|
||||
app.modal.open(InstallConfigAsk, {
|
||||
manifest: manifest,
|
||||
close: () => {
|
||||
app.modal.close()
|
||||
}
|
||||
})
|
||||
},
|
||||
checkUpdates: () => {
|
||||
ipc.exec("updater:check")
|
||||
},
|
||||
@ -84,6 +93,9 @@ class App extends React.Component {
|
||||
"app:update_available": (event, data) => {
|
||||
this.onUpdateAvailable(data)
|
||||
},
|
||||
"pkg:install:ask": (event, data) => {
|
||||
app.pkgInstallWizard(data)
|
||||
},
|
||||
"pkg:update_available": (event, data) => {
|
||||
app.pkgUpdateAvailable(data)
|
||||
},
|
||||
|
121
src/renderer/src/components/InstallConfigAsk/index.jsx
Normal file
121
src/renderer/src/components/InstallConfigAsk/index.jsx
Normal file
@ -0,0 +1,121 @@
|
||||
import React from "react"
|
||||
import { Icons, Icon } from "components/Icons"
|
||||
|
||||
import * as antd from "antd"
|
||||
|
||||
import PKGConfigItem from "../PackageConfigItem"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const InstallConfigAsk = (props) => {
|
||||
const { manifest } = props
|
||||
|
||||
const [values, setValues] = React.useState({
|
||||
...manifest.storaged_configs,
|
||||
...Object.keys(manifest.configs).reduce((prev, key) => {
|
||||
prev[key] = manifest.configs[key].default
|
||||
|
||||
return prev
|
||||
}, {})
|
||||
})
|
||||
|
||||
const [currentStep, setCurrentStep] = React.useState(0)
|
||||
|
||||
function handleChanges(key, value) {
|
||||
setValues((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[key]: value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleNextStep() {
|
||||
setCurrentStep(currentStep + 1)
|
||||
}
|
||||
|
||||
function handleFinish() {
|
||||
console.log(`Finish config wizard, with values >`, values)
|
||||
|
||||
if (typeof props.onFinish === "function") {
|
||||
props.onFinish(values)
|
||||
}
|
||||
|
||||
if (typeof props.close === "function") {
|
||||
props.close()
|
||||
}
|
||||
|
||||
if (typeof props.onClose === "function") {
|
||||
props.onClose()
|
||||
}
|
||||
|
||||
ipc.exec("pkg:apply", manifest.id, {
|
||||
configs: values
|
||||
})
|
||||
|
||||
app.location.push("/")
|
||||
}
|
||||
|
||||
const stepsItems = React.useMemo(() => {
|
||||
const steps = manifest.install_ask_configs.map((key, index) => {
|
||||
return {
|
||||
key: index,
|
||||
title: manifest.configs[key].label
|
||||
}
|
||||
})
|
||||
|
||||
return [...steps, {
|
||||
key: manifest.install_ask_configs.length,
|
||||
title: "Finish"
|
||||
}]
|
||||
}, [])
|
||||
|
||||
const stepsContent = React.useMemo(() => {
|
||||
const steps = manifest.install_ask_configs.map((key, index) => {
|
||||
const config = manifest.configs[key]
|
||||
|
||||
return <PKGConfigItem
|
||||
key={index}
|
||||
config={config}
|
||||
storagedValue={manifest.storaged_configs[key]}
|
||||
onChange={handleChanges}
|
||||
/>
|
||||
})
|
||||
|
||||
return steps
|
||||
}, [])
|
||||
|
||||
return <div className="install_config_ask">
|
||||
<antd.Steps
|
||||
size="small"
|
||||
direction="horizontal"
|
||||
items={stepsItems}
|
||||
current={currentStep}
|
||||
responsive={false}
|
||||
onChange={(e) => {
|
||||
setCurrentStep(currentStep)
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="install_config_ask-content">
|
||||
{stepsContent[currentStep]}
|
||||
</div>
|
||||
|
||||
<div className="install_config_ask-actions">
|
||||
<antd.Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
if (currentStep === stepsItems.length - 2) {
|
||||
handleFinish()
|
||||
} else {
|
||||
handleNextStep()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{currentStep === stepsItems.length - 2 ? "Finish" : "Next"}
|
||||
</antd.Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default InstallConfigAsk
|
32
src/renderer/src/components/InstallConfigAsk/index.less
Normal file
32
src/renderer/src/components/InstallConfigAsk/index.less
Normal file
@ -0,0 +1,32 @@
|
||||
.install_config_ask {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
gap: 20px;
|
||||
|
||||
h1 {
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
|
||||
gap: 6px;
|
||||
|
||||
font-size: 1rem;
|
||||
|
||||
svg {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-steps {
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
.install_config_ask-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
gap: 10px;
|
||||
|
||||
padding: 0 15px;
|
||||
}
|
||||
}
|
110
src/renderer/src/components/PackageConfigItem/index.jsx
Normal file
110
src/renderer/src/components/PackageConfigItem/index.jsx
Normal file
@ -0,0 +1,110 @@
|
||||
import React from "react"
|
||||
import * as antd from "antd"
|
||||
import { Icon } from "components/Icons"
|
||||
|
||||
const PKGConfigsComponents = {
|
||||
switch: antd.Switch,
|
||||
button: antd.Button,
|
||||
input: antd.Input,
|
||||
slider: antd.Slider,
|
||||
}
|
||||
|
||||
const PKGConfigsComponentByTypes = {
|
||||
string: "input",
|
||||
action: "button",
|
||||
bool: "switch",
|
||||
number: "slider",
|
||||
}
|
||||
|
||||
const PKGConfigItem = (props) => {
|
||||
const { config, storagedValue } = props
|
||||
|
||||
const key = config.id
|
||||
|
||||
const [localValue, setLocalValue] = React.useState(storagedValue ?? config.default)
|
||||
|
||||
const ComponentType = config.ui_component ?? PKGConfigsComponentByTypes[config.type] ?? "input"
|
||||
const ConfigComponent = PKGConfigsComponents[ComponentType]
|
||||
|
||||
function handleOnChange(value) {
|
||||
if (typeof value === "string" && config.string_trim === true) {
|
||||
value = value.trim()
|
||||
}
|
||||
|
||||
setLocalValue(value)
|
||||
|
||||
return props.onChange(key, value)
|
||||
}
|
||||
|
||||
if (ConfigComponent == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const ComponentsProps = {
|
||||
...config.ui_component_props,
|
||||
defaultValue: storagedValue ?? config.default,
|
||||
value: localValue
|
||||
}
|
||||
|
||||
switch (ComponentType) {
|
||||
case "input": {
|
||||
ComponentsProps.onChange = (e) => {
|
||||
handleOnChange(e.target.value)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "slider": {
|
||||
ComponentsProps.onChange = (value) => {
|
||||
handleOnChange(value)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "switch": {
|
||||
ComponentsProps.onChange = (checked) => {
|
||||
handleOnChange(checked)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
ComponentsProps.onChange = (value) => {
|
||||
handleOnChange(value)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return <div
|
||||
id={key}
|
||||
className="package_configs-option"
|
||||
>
|
||||
<div className="package_configs-option-header">
|
||||
<span className="package_configs-option-label">
|
||||
{
|
||||
config.icon && <Icon
|
||||
icon={config.icon}
|
||||
/>
|
||||
}
|
||||
{
|
||||
config.label ?? key
|
||||
}
|
||||
</span>
|
||||
|
||||
{
|
||||
config.description && <p className="package_configs-option-description">
|
||||
{key}
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="package_configs-option-content">
|
||||
{
|
||||
React.createElement(ConfigComponent, ComponentsProps)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default PKGConfigItem
|
@ -170,10 +170,12 @@ const PackageItem = (props) => {
|
||||
{
|
||||
isInstalled && !manifest.executable && <antd.Dropdown
|
||||
menu={MenuProps}
|
||||
disabled={isLoading}
|
||||
>
|
||||
<antd.Button
|
||||
icon={<MdOutlineMoreVert />}
|
||||
type="primary"
|
||||
disabled={isLoading}
|
||||
/>
|
||||
</antd.Dropdown>
|
||||
}
|
||||
|
@ -3,22 +3,10 @@ import * as antd from "antd"
|
||||
import { Icons, Icon } from "components/Icons"
|
||||
import { useParams } from "react-router-dom"
|
||||
|
||||
import PKGConfigItem from "components/PackageConfigItem"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const PKGConfigsComponents = {
|
||||
switch: antd.Switch,
|
||||
button: antd.Button,
|
||||
input: antd.Input,
|
||||
slider: antd.Slider,
|
||||
}
|
||||
|
||||
const PKGConfigsComponentByTypes = {
|
||||
string: "input",
|
||||
action: "button",
|
||||
bool: "switch",
|
||||
number: "slider",
|
||||
}
|
||||
|
||||
const PKGConfigs = (props) => {
|
||||
const { defaultConfigs = {}, configs = {} } = props
|
||||
|
||||
@ -30,93 +18,15 @@ const PKGConfigs = (props) => {
|
||||
|
||||
return Object.keys(defaultConfigs).map((key, index) => {
|
||||
const config = defaultConfigs[key]
|
||||
const storagedValue = configs[key]
|
||||
|
||||
const [localValue, setLocalValue] = React.useState(storagedValue ?? config.default)
|
||||
config.id = key
|
||||
|
||||
const ComponentType = config.ui_component ?? PKGConfigsComponentByTypes[config.type] ?? "input"
|
||||
const ConfigComponent = PKGConfigsComponents[ComponentType]
|
||||
|
||||
function handleOnChange(value) {
|
||||
if (typeof value === "string" && config.string_trim === true) {
|
||||
value = value.trim()
|
||||
}
|
||||
|
||||
setLocalValue(value)
|
||||
|
||||
return props.onChange(key, value)
|
||||
}
|
||||
|
||||
if (ConfigComponent == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
const ComponentsProps = {
|
||||
...config.ui_component_props,
|
||||
defaultValue: storagedValue ?? config.default,
|
||||
value: localValue
|
||||
}
|
||||
|
||||
switch (ComponentType) {
|
||||
case "input": {
|
||||
ComponentsProps.onChange = (e) => {
|
||||
handleOnChange(e.target.value)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "slider": {
|
||||
ComponentsProps.onChange = (value) => {
|
||||
handleOnChange(value)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "switch": {
|
||||
ComponentsProps.onChange = (checked) => {
|
||||
handleOnChange(checked)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
ComponentsProps.onChange = (value) => {
|
||||
handleOnChange(value)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return <div
|
||||
return <PKGConfigItem
|
||||
key={index}
|
||||
id={key}
|
||||
className="package_configs-option"
|
||||
>
|
||||
<div className="package_configs-option-header">
|
||||
<span className="package_configs-option-label">
|
||||
{
|
||||
config.icon && <Icon
|
||||
icon={config.icon}
|
||||
/>
|
||||
}
|
||||
{
|
||||
config.label ?? key
|
||||
}
|
||||
</span>
|
||||
|
||||
{
|
||||
config.description && <p className="package_configs-option-description">
|
||||
{key}
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="package_configs-option-content">
|
||||
{
|
||||
React.createElement(ConfigComponent, ComponentsProps)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
storagedValue={configs[key]}
|
||||
config={config}
|
||||
onChange={props.onChange}
|
||||
/>
|
||||
})
|
||||
}
|
||||
|
||||
@ -315,17 +225,32 @@ const PackageOptions = (props) => {
|
||||
onClick={handleReinstall}
|
||||
icon={<Icons.MdReplay />}
|
||||
type="default"
|
||||
size="small"
|
||||
>
|
||||
Reinstall
|
||||
</antd.Button>
|
||||
|
||||
<antd.Button
|
||||
{/* <antd.Button
|
||||
disabled
|
||||
icon={<Icons.MdCheck />}
|
||||
type="default"
|
||||
size="small"
|
||||
>
|
||||
Verify
|
||||
</antd.Button>
|
||||
</antd.Button> */}
|
||||
|
||||
{
|
||||
manifest.install_ask_configs && <antd.Button
|
||||
onClick={() => {
|
||||
app.pkgInstallWizard(manifest)
|
||||
}}
|
||||
icon={<Icons.MdSettings />}
|
||||
type="default"
|
||||
size="small"
|
||||
>
|
||||
Wizard
|
||||
</antd.Button>
|
||||
}
|
||||
|
||||
<antd.Button
|
||||
type="primary"
|
||||
|
Loading…
x
Reference in New Issue
Block a user