mirror of
https://github.com/ragestudio/relic.git
synced 2025-06-09 10:34: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)
|
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(changes.patches)) {
|
||||||
if (!Array.isArray(pkg.applied_patches)) {
|
if (!Array.isArray(pkg.applied_patches)) {
|
||||||
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) => {
|
pkg.applied_patches = pkg.applied_patches.filter((p) => {
|
||||||
return p !== patch.id
|
return p !== patch.id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
sendToRender(`pkg:update:status`, {
|
||||||
|
id: pkg_id,
|
||||||
|
status: "done",
|
||||||
|
statusText: `Patch [${patch.id}] removed!`,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for await (let patch of installPatches) {
|
for await (let patch of installPatches) {
|
||||||
@ -100,6 +100,12 @@ export default async function apply(pkg_id, changes) {
|
|||||||
|
|
||||||
// add to applied patches
|
// add to applied patches
|
||||||
pkg.applied_patches.push(patch.id)
|
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)
|
await updateInstalledPackage(pkg)
|
||||||
|
|
||||||
sendToRender(`new:notification`, {
|
sendToRender(`new:notification`, {
|
||||||
@ -126,7 +130,6 @@ export default async function apply(pkg_id, changes) {
|
|||||||
|
|
||||||
sendToRender(`pkg:update:status`, {
|
sendToRender(`pkg:update:status`, {
|
||||||
...pkg,
|
...pkg,
|
||||||
status: "installed",
|
|
||||||
statusText: "Changes applied!",
|
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`, {
|
sendToRender(`pkg:update:status`, {
|
||||||
id: pkg_id,
|
id: pkg_id,
|
||||||
status: "installed",
|
status: "installed",
|
||||||
|
@ -7,6 +7,7 @@ import getRootCssVar from "utils/getRootCssVar"
|
|||||||
|
|
||||||
import ManifestInfo from "components/ManifestInfo"
|
import ManifestInfo from "components/ManifestInfo"
|
||||||
import PackageUpdateAvailable from "components/PackageUpdateAvailable"
|
import PackageUpdateAvailable from "components/PackageUpdateAvailable"
|
||||||
|
import InstallConfigAsk from "components/InstallConfigAsk"
|
||||||
|
|
||||||
import AppLayout from "layout"
|
import AppLayout from "layout"
|
||||||
import AppModalDialog from "layout/components/ModalDialog"
|
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: () => {
|
checkUpdates: () => {
|
||||||
ipc.exec("updater:check")
|
ipc.exec("updater:check")
|
||||||
},
|
},
|
||||||
@ -84,6 +93,9 @@ class App extends React.Component {
|
|||||||
"app:update_available": (event, data) => {
|
"app:update_available": (event, data) => {
|
||||||
this.onUpdateAvailable(data)
|
this.onUpdateAvailable(data)
|
||||||
},
|
},
|
||||||
|
"pkg:install:ask": (event, data) => {
|
||||||
|
app.pkgInstallWizard(data)
|
||||||
|
},
|
||||||
"pkg:update_available": (event, data) => {
|
"pkg:update_available": (event, data) => {
|
||||||
app.pkgUpdateAvailable(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
|
isInstalled && !manifest.executable && <antd.Dropdown
|
||||||
menu={MenuProps}
|
menu={MenuProps}
|
||||||
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
<antd.Button
|
<antd.Button
|
||||||
icon={<MdOutlineMoreVert />}
|
icon={<MdOutlineMoreVert />}
|
||||||
type="primary"
|
type="primary"
|
||||||
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
</antd.Dropdown>
|
</antd.Dropdown>
|
||||||
}
|
}
|
||||||
|
@ -3,22 +3,10 @@ import * as antd from "antd"
|
|||||||
import { Icons, Icon } from "components/Icons"
|
import { Icons, Icon } from "components/Icons"
|
||||||
import { useParams } from "react-router-dom"
|
import { useParams } from "react-router-dom"
|
||||||
|
|
||||||
|
import PKGConfigItem from "components/PackageConfigItem"
|
||||||
|
|
||||||
import "./index.less"
|
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 PKGConfigs = (props) => {
|
||||||
const { defaultConfigs = {}, configs = {} } = props
|
const { defaultConfigs = {}, configs = {} } = props
|
||||||
|
|
||||||
@ -30,93 +18,15 @@ const PKGConfigs = (props) => {
|
|||||||
|
|
||||||
return Object.keys(defaultConfigs).map((key, index) => {
|
return Object.keys(defaultConfigs).map((key, index) => {
|
||||||
const config = defaultConfigs[key]
|
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"
|
return <PKGConfigItem
|
||||||
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
|
|
||||||
key={index}
|
key={index}
|
||||||
id={key}
|
storagedValue={configs[key]}
|
||||||
className="package_configs-option"
|
config={config}
|
||||||
>
|
onChange={props.onChange}
|
||||||
<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>
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,17 +225,32 @@ const PackageOptions = (props) => {
|
|||||||
onClick={handleReinstall}
|
onClick={handleReinstall}
|
||||||
icon={<Icons.MdReplay />}
|
icon={<Icons.MdReplay />}
|
||||||
type="default"
|
type="default"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
Reinstall
|
Reinstall
|
||||||
</antd.Button>
|
</antd.Button>
|
||||||
|
|
||||||
<antd.Button
|
{/* <antd.Button
|
||||||
disabled
|
disabled
|
||||||
icon={<Icons.MdCheck />}
|
icon={<Icons.MdCheck />}
|
||||||
type="default"
|
type="default"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
Verify
|
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
|
<antd.Button
|
||||||
type="primary"
|
type="primary"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user