mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-13 04:05:04 +03:00
Improved error screen (#841)
* improve the error screen visuals * comment out placeholder buttons * run formatter * Refactor DeckyErrorBoundary styles and text - Removed gray text class usage - Removed styles reminiscent of Steam BPM - Fixed typos * Further refactor of DeckyErrorBoundary.tsx - Change background/text of buttons to be closer to Steam Deck UI - Make panel background not reliant on transparency and have a neutral gray - Bold "likely occurred" text - Make swipe prompt appear in the center of a horizontal bar, drawing more attention to it - Make "An error occurred" text smaller, as it isn't helpful for troubleshooting - Add text clarifying solutions are in recommended order and how to get more help - Add "Retry the action or restart" to the left of Retry, Restart Steam, and Restart Decky buttons - Move disabling Decky to beneath the Decky update checking * Revert header boldness change * add disable plugin buttons to error screen * Set background to black --------- Co-authored-by: EMERALD <info@eme.wtf>
This commit is contained in:
@@ -82,6 +82,7 @@ class Utilities:
|
|||||||
context.ws.add_route("utilities/_call_legacy_utility", self._call_legacy_utility)
|
context.ws.add_route("utilities/_call_legacy_utility", self._call_legacy_utility)
|
||||||
context.ws.add_route("utilities/enable_plugin", self.enable_plugin)
|
context.ws.add_route("utilities/enable_plugin", self.enable_plugin)
|
||||||
context.ws.add_route("utilities/disable_plugin", self.disable_plugin)
|
context.ws.add_route("utilities/disable_plugin", self.disable_plugin)
|
||||||
|
context.ws.add_route("utilities/set_all_plugins_disabled", self.set_all_plugins_disabled)
|
||||||
|
|
||||||
context.web_app.add_routes([
|
context.web_app.add_routes([
|
||||||
post("/methods/{method_name}", self._handle_legacy_server_method_call)
|
post("/methods/{method_name}", self._handle_legacy_server_method_call)
|
||||||
@@ -503,4 +504,13 @@ class Utilities:
|
|||||||
disabled_plugins.remove(name)
|
disabled_plugins.remove(name)
|
||||||
await self.set_setting("disabled_plugins", disabled_plugins)
|
await self.set_setting("disabled_plugins", disabled_plugins)
|
||||||
|
|
||||||
await self.context.plugin_loader.import_plugin(path.join(plugin_dir, "main.py"), plugin_folder)
|
await self.context.plugin_loader.import_plugin(path.join(plugin_dir, "main.py"), plugin_folder)
|
||||||
|
|
||||||
|
async def set_all_plugins_disabled(self):
|
||||||
|
disabled_plugins: List[str] = await self.get_setting("disabled_plugins", [])
|
||||||
|
|
||||||
|
for name, _ in self.context.plugin_loader.plugins.items():
|
||||||
|
if name not in disabled_plugins:
|
||||||
|
disabled_plugins.append(name)
|
||||||
|
|
||||||
|
await self.set_setting("disabled_plugins", disabled_plugins)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { sleep } from '@decky/ui';
|
import { joinClassNames, sleep } from '@decky/ui';
|
||||||
import { FunctionComponent, useEffect, useReducer, useState } from 'react';
|
import { FunctionComponent, useEffect, useReducer, useState } from 'react';
|
||||||
|
|
||||||
import { uninstallPlugin } from '../plugin';
|
import { disablePlugin, uninstallPlugin } from '../plugin';
|
||||||
import { VerInfo, doRestart, doShutdown } from '../updater';
|
import { VerInfo, doRestart, doShutdown } from '../updater';
|
||||||
import { ValveReactErrorInfo, getLikelyErrorSourceFromValveReactError } from '../utils/errors';
|
import { ValveReactErrorInfo, getLikelyErrorSourceFromValveReactError } from '../utils/errors';
|
||||||
import { useSetting } from '../utils/hooks/useSetting';
|
import { useSetting } from '../utils/hooks/useSetting';
|
||||||
@@ -20,6 +20,26 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const classes = {
|
||||||
|
root: 'deckyErrorBoundary',
|
||||||
|
likelyOccurred: 'likely-occured-msg',
|
||||||
|
panel: 'panel-section',
|
||||||
|
panelHeader: 'panel-header',
|
||||||
|
trace: 'trace',
|
||||||
|
rowList: 'row-list',
|
||||||
|
rowItem: 'row-item',
|
||||||
|
buttonDescRow: 'button-description-row',
|
||||||
|
flexRowWGap: 'flex-row',
|
||||||
|
marginBottom: 'margin-bottom',
|
||||||
|
swipePrompt: 'swipe-prompt',
|
||||||
|
};
|
||||||
|
|
||||||
|
const vars = {
|
||||||
|
scrollBarwidth: '18px',
|
||||||
|
rootMarginLeft: '15px',
|
||||||
|
panelXPadding: '20px',
|
||||||
|
};
|
||||||
|
|
||||||
export const startSSH = DeckyBackend.callable('utilities/start_ssh');
|
export const startSSH = DeckyBackend.callable('utilities/start_ssh');
|
||||||
export const starrCEFForwarding = DeckyBackend.callable('utilities/allow_remote_debugging');
|
export const starrCEFForwarding = DeckyBackend.callable('utilities/allow_remote_debugging');
|
||||||
|
|
||||||
@@ -64,39 +84,131 @@ const DeckyErrorBoundary: FunctionComponent<DeckyErrorBoundaryProps> = ({ error,
|
|||||||
<>
|
<>
|
||||||
<style>
|
<style>
|
||||||
{`
|
{`
|
||||||
*:has(> .deckyErrorBoundary) {
|
*:has(> .${classes.root}) {
|
||||||
|
margin-top: var(--basicui-header-height);
|
||||||
overflow: scroll !important;
|
overflow: scroll !important;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
*:has(> .${classes.root})::-webkit-scrollbar {
|
||||||
|
display: initial !important;
|
||||||
|
width: ${vars.scrollBarwidth};
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
*:has(> .${classes.root})::-webkit-scrollbar-thumb {
|
||||||
|
background: #4349535e;
|
||||||
|
}
|
||||||
|
.${classes.root} {
|
||||||
|
color: #93929e;
|
||||||
|
font-size: 15px;
|
||||||
|
margin: 10px 0px 40px ${vars.rootMarginLeft};
|
||||||
|
width: calc(100vw - ${vars.scrollBarwidth} - ${vars.rootMarginLeft});
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
.${classes.root} button,
|
||||||
|
.${classes.root} select {
|
||||||
|
border: none;
|
||||||
|
padding: 4px 16px !important;
|
||||||
|
background: #333;
|
||||||
|
color: #ddd;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 3px;
|
||||||
|
outline: none;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
.${classes.panel} {
|
||||||
|
background: #080808;
|
||||||
|
padding: 8px ${vars.panelXPadding};
|
||||||
|
border-radius: 3px;
|
||||||
|
/* box-shadow: 9px 9px 20px -5px rgb(0 0 0 / 89%); */
|
||||||
|
}
|
||||||
|
.${classes.panelHeader} {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bolder;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.${classes.likelyOccurred} {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #588fb4;
|
||||||
|
}
|
||||||
|
.${classes.rowItem} {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.${classes.rowItem}:not(:last-child)::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -4.5px;
|
||||||
|
left: 5px;
|
||||||
|
right: 15px;
|
||||||
|
height: 0.5px;
|
||||||
|
background: #3c3c3c47;
|
||||||
|
}
|
||||||
|
.${classes.flexRowWGap},
|
||||||
|
.${classes.buttonDescRow},
|
||||||
|
.${classes.rowList},
|
||||||
|
.${classes.panel} {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${classes.rowList},
|
||||||
|
.${classes.panel} {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.${classes.flexRowWGap},
|
||||||
|
.${classes.rowList} {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.${classes.marginBottom} {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.${classes.buttonDescRow} {
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${classes.swipePrompt} {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: small;
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
.${classes.swipePrompt} span {
|
||||||
|
padding: 0 8px;
|
||||||
|
background-color: #000;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.${classes.swipePrompt}::before,
|
||||||
|
.${classes.swipePrompt}::after {
|
||||||
|
content: "";
|
||||||
|
flex-grow: 1;
|
||||||
|
border-bottom: 1px solid #474752;
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
.${classes.swipePrompt}::before {
|
||||||
|
right: 50%;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.${classes.swipePrompt}::after {
|
||||||
|
left: 50%;
|
||||||
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
<div
|
<div className={classes.root}>
|
||||||
style={{
|
<div className={classes.marginBottom}>An error occurred while rendering this content.</div>
|
||||||
overflow: 'auto',
|
<pre className={joinClassNames(classes.marginBottom)} style={{ marginTop: '0px' }}>
|
||||||
marginLeft: '15px',
|
|
||||||
color: 'white',
|
|
||||||
fontSize: '16px',
|
|
||||||
userSelect: 'auto',
|
|
||||||
backgroundColor: 'black',
|
|
||||||
marginTop: '48px', // Incase this is a page
|
|
||||||
}}
|
|
||||||
className="deckyErrorBoundary"
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
style={{
|
|
||||||
fontSize: '20px',
|
|
||||||
display: 'inline-block',
|
|
||||||
userSelect: 'auto',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
⚠️ An error occured while rendering this content.
|
|
||||||
</h1>
|
|
||||||
<pre style={{}}>
|
|
||||||
<code>
|
<code>
|
||||||
{identifier && `Error Reference: ${identifier}`}
|
{identifier && `Error Reference: ${identifier}`}
|
||||||
{versionInfo?.current && `\nDecky Version: ${versionInfo.current}`}
|
{versionInfo?.current && `\nDecky Version: ${versionInfo.current}`}
|
||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
<p>This error likely occured in {errorSource}.</p>
|
<div className={joinClassNames(classes.likelyOccurred, classes.marginBottom)}>
|
||||||
|
This error likely occurred in {errorSource}.
|
||||||
|
</div>
|
||||||
{actionLog?.length > 0 && (
|
{actionLog?.length > 0 && (
|
||||||
<pre>
|
<pre>
|
||||||
<code>
|
<code>
|
||||||
@@ -106,142 +218,88 @@ const DeckyErrorBoundary: FunctionComponent<DeckyErrorBoundaryProps> = ({ error,
|
|||||||
</pre>
|
</pre>
|
||||||
)}
|
)}
|
||||||
{actionsEnabled && (
|
{actionsEnabled && (
|
||||||
<>
|
<div className={classes.panel}>
|
||||||
<h3>Actions: </h3>
|
<div className={classes.flexRowWGap} style={{ alignItems: 'center', marginBottom: '8px' }}>
|
||||||
<p>Use the touch screen.</p>
|
<div className={classes.panelHeader}>Actions</div>
|
||||||
<div style={{ display: 'block', marginBottom: '5px' }}>
|
<div style={{ fontSize: 'small', fontStyle: 'italic' }}>
|
||||||
<button style={{ marginRight: '5px', padding: '5px' }} onClick={reset}>
|
Use the touch screen. Solutions are listed in the recommended order. If you are still experiencing
|
||||||
Retry
|
issues, please post in the #loader-support channel at decky.xyz/discord.
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
style={{ marginRight: '5px', padding: '5px' }}
|
|
||||||
onClick={() => {
|
|
||||||
addLogLine('Restarting Steam...');
|
|
||||||
SteamClient.User.StartRestart(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Restart Steam
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: 'block', marginBottom: '5px' }}>
|
|
||||||
<button
|
|
||||||
style={{ marginRight: '5px', padding: '5px' }}
|
|
||||||
onClick={async () => {
|
|
||||||
setActionsEnabled(false);
|
|
||||||
addLogLine('Restarting Decky...');
|
|
||||||
doRestart();
|
|
||||||
await sleep(2000);
|
|
||||||
addLogLine('Reloading UI...');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Restart Decky
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
style={{ marginRight: '5px', padding: '5px' }}
|
|
||||||
onClick={async () => {
|
|
||||||
setActionsEnabled(false);
|
|
||||||
addLogLine('Stopping Decky...');
|
|
||||||
doShutdown();
|
|
||||||
await sleep(5000);
|
|
||||||
addLogLine('Restarting Steam...');
|
|
||||||
SteamClient.User.StartRestart(false);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Disable Decky until next boot
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{debugAllowed && (
|
|
||||||
<div style={{ display: 'block', marginBottom: '5px' }}>
|
|
||||||
<button
|
|
||||||
style={{ marginRight: '5px', padding: '5px' }}
|
|
||||||
onClick={async () => {
|
|
||||||
setDebugAllowed(false);
|
|
||||||
addLogLine('Enabling CEF debugger forwarding...');
|
|
||||||
await starrCEFForwarding();
|
|
||||||
addLogLine('Enabling SSH...');
|
|
||||||
await startSSH();
|
|
||||||
addLogLine('Ready for debugging!');
|
|
||||||
if (window?.SystemNetworkStore?.wirelessNetworkDevice?.ip4?.addresses?.[0]?.ip) {
|
|
||||||
const ip = ipToString(window.SystemNetworkStore.wirelessNetworkDevice.ip4.addresses[0].ip);
|
|
||||||
addLogLine(`CEF Debugger: http://${ip}:8081`);
|
|
||||||
addLogLine(`SSH: deck@${ip}`);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Allow remote debugging and SSH until next boot
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
{
|
<div className={classes.rowList}>
|
||||||
<div style={{ display: 'block', marginBottom: '5px' }}>
|
<div className={joinClassNames(classes.rowItem, classes.buttonDescRow)}>
|
||||||
{updateProgress > -1
|
Retry the action or restart
|
||||||
? 'Update in progress... ' + updateProgress + '%'
|
<div className={classes.flexRowWGap}>
|
||||||
: updateProgress == -2
|
<button onClick={reset}>Retry</button>
|
||||||
? 'Update complete. Restarting...'
|
<button
|
||||||
: 'Changing your Decky Loader branch and/or \n checking for updates might help!\n'}
|
onClick={() => {
|
||||||
{updateProgress == -1 && (
|
addLogLine('Restarting Steam...');
|
||||||
<div style={{ height: '30px' }}>
|
SteamClient.User.StartRestart(false);
|
||||||
<select
|
}}
|
||||||
style={{ height: '100%' }}
|
>
|
||||||
onChange={async (e) => {
|
Restart Steam
|
||||||
const branch = parseInt(e.target.value);
|
</button>
|
||||||
setSelectedBranch(branch);
|
<button
|
||||||
setSetVersionToUpdateTo('');
|
onClick={async () => {
|
||||||
}}
|
setActionsEnabled(false);
|
||||||
>
|
addLogLine('Restarting Decky...');
|
||||||
<option value="0" selected={selectedBranch == UpdateBranch.Stable}>
|
doRestart();
|
||||||
Stable
|
await sleep(2000);
|
||||||
</option>
|
addLogLine('Reloading UI...');
|
||||||
<option value="1" selected={selectedBranch == UpdateBranch.Prerelease}>
|
}}
|
||||||
Pre-Release
|
>
|
||||||
</option>
|
Restart Decky
|
||||||
<option value="2" selected={selectedBranch == UpdateBranch.Testing}>
|
</button>
|
||||||
Testing
|
</div>
|
||||||
</option>
|
</div>
|
||||||
</select>
|
{wasCausedByPlugin && (
|
||||||
|
<div className={joinClassNames(classes.rowItem, classes.buttonDescRow)}>
|
||||||
|
Disable or uninstall the suspected plugin
|
||||||
|
<div className={classes.flexRowWGap}>
|
||||||
<button
|
<button
|
||||||
style={{ height: '100%' }}
|
|
||||||
disabled={updateProgress != -1 || isChecking}
|
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (versionToUpdateTo == '') {
|
setActionsEnabled(false);
|
||||||
setIsChecking(true);
|
addLogLine(`Disabling ${errorSource}...`);
|
||||||
const versionInfo = (await DeckyBackend.callable(
|
await disablePlugin(errorSource);
|
||||||
'updater/check_for_updates',
|
await sleep(1000);
|
||||||
)()) as unknown as VerInfo;
|
addLogLine('Restarting Decky...');
|
||||||
setIsChecking(false);
|
doRestart();
|
||||||
if (versionInfo?.remote && versionInfo?.remote?.tag_name != versionInfo?.current) {
|
await sleep(2000);
|
||||||
setSetVersionToUpdateTo(versionInfo.remote.tag_name);
|
addLogLine('Restarting Steam...');
|
||||||
} else {
|
await sleep(500);
|
||||||
setSetVersionToUpdateTo('');
|
SteamClient.User.StartRestart(false);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DeckyBackend.callable('updater/do_update')();
|
|
||||||
setUpdateProgress(0);
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{' '}
|
Disable {errorSource}
|
||||||
{isChecking
|
</button>
|
||||||
? 'Checking for updates...'
|
<button
|
||||||
: versionToUpdateTo != ''
|
onClick={async () => {
|
||||||
? 'Update to ' + versionToUpdateTo
|
setActionsEnabled(false);
|
||||||
: 'Check for updates'}
|
addLogLine(`Uninstalling ${errorSource}...`);
|
||||||
|
await uninstallPlugin(errorSource);
|
||||||
|
await DeckyPluginLoader.frozenPluginsService.invalidate();
|
||||||
|
await DeckyPluginLoader.hiddenPluginsService.invalidate();
|
||||||
|
await sleep(1000);
|
||||||
|
addLogLine('Restarting Decky...');
|
||||||
|
doRestart();
|
||||||
|
await sleep(2000);
|
||||||
|
addLogLine('Restarting Steam...');
|
||||||
|
await sleep(500);
|
||||||
|
SteamClient.User.StartRestart(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Uninstall {errorSource}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
)}
|
||||||
}
|
<div className={joinClassNames(classes.rowItem, classes.buttonDescRow)}>
|
||||||
{wasCausedByPlugin && (
|
Disable all plugins
|
||||||
<div style={{ display: 'block', marginBottom: '5px' }}>
|
|
||||||
{'\n'}
|
|
||||||
<button
|
<button
|
||||||
style={{ marginRight: '5px', padding: '5px' }}
|
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setActionsEnabled(false);
|
setActionsEnabled(false);
|
||||||
addLogLine(`Uninstalling ${errorSource}...`);
|
addLogLine(`Disabling plugins...`);
|
||||||
await uninstallPlugin(errorSource);
|
await DeckyBackend.call('utilities/set_all_plugins_disabled');
|
||||||
await DeckyPluginLoader.frozenPluginsService.invalidate();
|
|
||||||
await DeckyPluginLoader.hiddenPluginsService.invalidate();
|
|
||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
addLogLine('Restarting Decky...');
|
addLogLine('Restarting Decky...');
|
||||||
doRestart();
|
doRestart();
|
||||||
@@ -251,27 +309,134 @@ const DeckyErrorBoundary: FunctionComponent<DeckyErrorBoundaryProps> = ({ error,
|
|||||||
SteamClient.User.StartRestart(false);
|
SteamClient.User.StartRestart(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Uninstall {errorSource} and restart Decky
|
Disable All Plugins
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
{
|
||||||
</>
|
<div className={joinClassNames(classes.rowItem, classes.buttonDescRow)}>
|
||||||
|
{updateProgress > -1
|
||||||
|
? 'Update in progress... ' + updateProgress + '%'
|
||||||
|
: updateProgress == -2
|
||||||
|
? 'Update complete. Restarting...'
|
||||||
|
: 'Check for Decky updates'}
|
||||||
|
{
|
||||||
|
<div className={classes.flexRowWGap}>
|
||||||
|
{updateProgress == -1 && (
|
||||||
|
<>
|
||||||
|
<select
|
||||||
|
onChange={async (e) => {
|
||||||
|
const branch = parseInt(e.target.value);
|
||||||
|
setSelectedBranch(branch);
|
||||||
|
setSetVersionToUpdateTo('');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value="0" selected={selectedBranch == UpdateBranch.Stable}>
|
||||||
|
Stable
|
||||||
|
</option>
|
||||||
|
<option value="1" selected={selectedBranch == UpdateBranch.Prerelease}>
|
||||||
|
Pre-Release
|
||||||
|
</option>
|
||||||
|
<option value="2" selected={selectedBranch == UpdateBranch.Testing}>
|
||||||
|
Testing
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<button
|
||||||
|
disabled={updateProgress != -1 || isChecking}
|
||||||
|
onClick={async () => {
|
||||||
|
if (versionToUpdateTo == '') {
|
||||||
|
setIsChecking(true);
|
||||||
|
const versionInfo = (await DeckyBackend.callable(
|
||||||
|
'updater/check_for_updates',
|
||||||
|
)()) as unknown as VerInfo;
|
||||||
|
setIsChecking(false);
|
||||||
|
if (versionInfo?.remote && versionInfo?.remote?.tag_name != versionInfo?.current) {
|
||||||
|
setSetVersionToUpdateTo(versionInfo.remote.tag_name);
|
||||||
|
} else {
|
||||||
|
setSetVersionToUpdateTo('');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DeckyBackend.callable('updater/do_update')();
|
||||||
|
setUpdateProgress(0);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
{isChecking
|
||||||
|
? 'Checking for updates...'
|
||||||
|
: versionToUpdateTo != ''
|
||||||
|
? 'Update to ' + versionToUpdateTo
|
||||||
|
: 'Check for updates'}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div className={joinClassNames(classes.rowItem, classes.buttonDescRow)}>
|
||||||
|
Disable Decky until next boot
|
||||||
|
<button
|
||||||
|
onClick={async () => {
|
||||||
|
setActionsEnabled(false);
|
||||||
|
addLogLine('Stopping Decky...');
|
||||||
|
doShutdown();
|
||||||
|
await sleep(5000);
|
||||||
|
addLogLine('Restarting Steam...');
|
||||||
|
SteamClient.User.StartRestart(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Disable Decky
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{debugAllowed && (
|
||||||
|
<div className={joinClassNames(classes.rowItem, classes.buttonDescRow)}>
|
||||||
|
Enable remote debugging and SSH until next boot (for developers)
|
||||||
|
<button
|
||||||
|
onClick={async () => {
|
||||||
|
setDebugAllowed(false);
|
||||||
|
addLogLine('Enabling CEF debugger forwarding...');
|
||||||
|
await starrCEFForwarding();
|
||||||
|
addLogLine('Enabling SSH...');
|
||||||
|
await startSSH();
|
||||||
|
addLogLine('Ready for debugging!');
|
||||||
|
if (window?.SystemNetworkStore?.wirelessNetworkDevice?.ip4?.addresses?.[0]?.ip) {
|
||||||
|
const ip = ipToString(window.SystemNetworkStore.wirelessNetworkDevice.ip4.addresses[0].ip);
|
||||||
|
addLogLine(`CEF Debugger: http://${ip}:8081`);
|
||||||
|
addLogLine(`SSH: deck@${ip}`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Enable
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{actionsEnabled && (
|
||||||
<pre
|
<div className={classes.swipePrompt}>
|
||||||
style={{
|
<span>Swipe to scroll</span>
|
||||||
marginTop: '15px',
|
</div>
|
||||||
opacity: 0.7,
|
)}
|
||||||
userSelect: 'auto',
|
<div className={classes.panel}>
|
||||||
}}
|
<div className={classes.panelHeader}>Trace</div>
|
||||||
>
|
<pre
|
||||||
<code>
|
style={{
|
||||||
{error.error.stack}
|
margin: `8px calc(-1 * ${vars.panelXPadding})`,
|
||||||
{'\n\n'}
|
userSelect: 'auto',
|
||||||
Component Stack:
|
overflowX: 'scroll',
|
||||||
{error.info.componentStack}
|
padding: `0px ${vars.panelXPadding}`,
|
||||||
</code>
|
maskImage: `linear-gradient(to right, transparent, black ${vars.panelXPadding}, black calc(100% - ${vars.panelXPadding}), transparent)`,
|
||||||
</pre>
|
}}
|
||||||
|
>
|
||||||
|
<code>
|
||||||
|
{error.error.stack}
|
||||||
|
{'\n\n'}
|
||||||
|
Component Stack:
|
||||||
|
{error.info.componentStack}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user