LAUNCHER-5 feat: Disable mod buttons when the cluster is running
LAUNCHER-16 feat: Running cluster indicator on home page
This commit is contained in:
parent
d4a33ad348
commit
de70230645
4 changed files with 73 additions and 32 deletions
40
apps/frontend/src/ui/hooks/useProcessor.tsx
Normal file
40
apps/frontend/src/ui/hooks/useProcessor.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import type { Cluster, DetailedProcess } from '@onelauncher/client/bindings';
|
||||
import type { UnlistenFn } from '@tauri-apps/api/event';
|
||||
import { bridge } from '~imports';
|
||||
import { type Accessor, createEffect, createSignal, onCleanup, onMount, type Resource } from 'solid-js';
|
||||
import useCommand, { tryResult } from './useCommand';
|
||||
|
||||
interface ProcessorHookType {
|
||||
running: Resource<DetailedProcess[]>;
|
||||
stop: (id: string) => Promise<unknown>;
|
||||
isRunning: Accessor<boolean>;
|
||||
};
|
||||
|
||||
export default function useProcessor(cluster: Cluster): ProcessorHookType {
|
||||
const [runningProcesses, { refetch: refetchProcesses }] = useCommand(() => bridge.commands.getProcessesDetailedByPath(cluster.path!));
|
||||
const [unlisten, setUnlisten] = createSignal<UnlistenFn>();
|
||||
const [isRunning, setIsRunning] = createSignal<boolean>(false);
|
||||
|
||||
onMount(async () => {
|
||||
const unlisten = await bridge.events.processPayload.listen((e) => {
|
||||
if (e.payload.event === 'started' || e.payload.event === 'finished')
|
||||
refetchProcesses();
|
||||
});
|
||||
|
||||
setUnlisten(() => unlisten);
|
||||
});
|
||||
|
||||
onCleanup(() => {
|
||||
unlisten()?.();
|
||||
});
|
||||
|
||||
createEffect(() => {
|
||||
setIsRunning((runningProcesses()?.length ?? 0) > 0);
|
||||
});
|
||||
|
||||
return {
|
||||
running: runningProcesses,
|
||||
stop: async id => await tryResult(() => bridge.commands.killProcess(id)),
|
||||
isRunning,
|
||||
};
|
||||
}
|
||||
|
|
@ -8,11 +8,13 @@ import {
|
|||
} from '@untitled-theme/icons-solid';
|
||||
import { bridge } from '~imports';
|
||||
import ClusterCover from '~ui/components/game/ClusterCover';
|
||||
import PlayerHead from '~ui/components/game/PlayerHead';
|
||||
import { useClusterCreator } from '~ui/components/overlay/cluster/ClusterCreationModal';
|
||||
import { useLaunchCluster, useRecentCluster } from '~ui/hooks/useCluster';
|
||||
import useCommand from '~ui/hooks/useCommand';
|
||||
import { formatAsDuration, upperFirst } from '~utils';
|
||||
|
||||
import useProcessor from '~ui/hooks/useProcessor';
|
||||
import { formatAsDuration, upperFirst } from '~utils';
|
||||
import { For, onMount, Show } from 'solid-js';
|
||||
import BannerBackground from '../../assets/images/header.png';
|
||||
import Button from '../components/base/Button';
|
||||
|
|
@ -170,6 +172,7 @@ function Banner() {
|
|||
|
||||
function ClusterCard(props: Cluster) {
|
||||
const navigate = useNavigate();
|
||||
const { running, isRunning } = useProcessor(props);
|
||||
|
||||
function openClusterPage(_e: MouseEvent) {
|
||||
navigate(`/clusters/?id=${props.uuid}`);
|
||||
|
|
@ -180,7 +183,11 @@ function ClusterCard(props: Cluster) {
|
|||
return (
|
||||
<>
|
||||
<div
|
||||
class="group relative h-[152px] flex flex-col border border-border/05 rounded-xl bg-component-bg active:bg-component-bg-pressed hover:bg-component-bg-hover"
|
||||
class="group relative h-[152px] flex flex-col border rounded-xl"
|
||||
classList={{
|
||||
'border-brand bg-brand/20 active:bg-brand/30 hover:bg-brand/10': isRunning(),
|
||||
'border-border/05 bg-component-bg active:bg-component-bg-pressed hover:bg-component-bg-hover': !isRunning(),
|
||||
}}
|
||||
onClick={e => openClusterPage(e)}
|
||||
>
|
||||
<div class="relative flex-1 overflow-hidden rounded-t-xl">
|
||||
|
|
@ -193,6 +200,16 @@ function ClusterCard(props: Cluster) {
|
|||
cluster={props}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Show when={isRunning()}>
|
||||
<div class="absolute left-1 top-1 flex flex-row gap-1 rounded-md bg-brand/70 p-1">
|
||||
<For each={running()}>
|
||||
{process => (
|
||||
<PlayerHead class="h-4 w-4 rounded-[4px]" uuid={process.user} />
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<div class="z-10 flex flex-row items-center justify-between gap-x-3 p-3">
|
||||
<div class="h-8 flex flex-col gap-1.5 overflow-hidden">
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ import Sidebar from '~ui/components/Sidebar';
|
|||
import useBrowser from '~ui/hooks/useBrowser';
|
||||
import useClusterContext from '~ui/hooks/useCluster';
|
||||
import useCommand from '~ui/hooks/useCommand';
|
||||
import { createEffect, createSignal, For, Match, Show, Switch } from 'solid-js';
|
||||
import useProcessor from '~ui/hooks/useProcessor';
|
||||
import { type Accessor, createEffect, createSignal, For, Match, Show, Switch } from 'solid-js';
|
||||
|
||||
// TODO: This needs a rewrite.
|
||||
function ClusterMods() {
|
||||
const [cluster] = useClusterContext();
|
||||
const { isRunning } = useProcessor(cluster()!);
|
||||
const [mods, { refetch: refetchMods }] = useCommand(cluster, () => bridge.commands.getClusterPackages(cluster()?.path || '', 'mod'));
|
||||
|
||||
// Mods to display, should be a clone of the mods array but sorted
|
||||
|
|
@ -101,7 +103,7 @@ function ClusterMods() {
|
|||
<Match when={displayedMods().length > 0}>
|
||||
<For each={displayedMods()}>
|
||||
{mod => (
|
||||
<ModEntry pkg={mod} refetch={refetchMods} />
|
||||
<ModEntry isRunning={isRunning} pkg={mod} refetch={refetchMods} />
|
||||
)}
|
||||
</For>
|
||||
</Match>
|
||||
|
|
@ -120,6 +122,7 @@ export default ClusterMods;
|
|||
interface ModEntryProps {
|
||||
pkg: Package;
|
||||
refetch: () => void;
|
||||
isRunning: Accessor<boolean>;
|
||||
};
|
||||
|
||||
function ModEntry(props: ModEntryProps) {
|
||||
|
|
@ -241,9 +244,12 @@ function ModEntry(props: ModEntryProps) {
|
|||
<Edit02Icon />
|
||||
</Button> */}
|
||||
|
||||
<Button buttonStyle="iconDanger" onClick={deletePackage}>
|
||||
<Trash03Icon />
|
||||
</Button>
|
||||
<Button
|
||||
buttonStyle="iconDanger"
|
||||
children={<Trash03Icon />}
|
||||
disabled={props.isRunning()}
|
||||
onClick={deletePackage}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
import type { UnlistenFn } from '@tauri-apps/api/event';
|
||||
import { type Navigator, Route, useIsRouting, useSearchParams } from '@solidjs/router';
|
||||
import { EyeIcon, File06Icon, Globe04Icon, Image03Icon, PackagePlusIcon, Settings04Icon } from '@untitled-theme/icons-solid';
|
||||
import { bridge } from '~imports';
|
||||
import PlayerHead from '~ui/components/game/PlayerHead';
|
||||
import useClusterContext, { ClusterProvider } from '~ui/hooks/useCluster';
|
||||
import { tryResult } from '~ui/hooks/useCommand';
|
||||
import useProcessor from '~ui/hooks/useProcessor';
|
||||
import { supportsMods } from '~utils';
|
||||
import { createEffect, createResource, createSignal, onCleanup, onMount, type ParentProps, Show } from 'solid-js';
|
||||
import { createEffect, type ParentProps, Show } from 'solid-js';
|
||||
import AnimatedRoutes from '../../components/AnimatedRoutes';
|
||||
import ErrorBoundary from '../../components/ErrorBoundary';
|
||||
import Sidebar from '../../components/Sidebar';
|
||||
|
|
@ -71,14 +69,7 @@ ClusterRoot.open = function (navigate: Navigator, uuid: string) {
|
|||
|
||||
function ClusterSidebar() {
|
||||
const [cluster, { refetch: refetchCluster }] = useClusterContext();
|
||||
const [listener, setListener] = createSignal<UnlistenFn>();
|
||||
const [runningProcesses, { refetch: refetchProcesses }] = createResource([], async () => {
|
||||
const c = cluster();
|
||||
if (!c || typeof c.path !== 'string')
|
||||
return [];
|
||||
|
||||
return tryResult(() => bridge.commands.getProcessesDetailedByPath(c.path!));
|
||||
});
|
||||
const { running: runningProcesses } = useProcessor(cluster()!);
|
||||
|
||||
const isRouting = useIsRouting();
|
||||
|
||||
|
|
@ -87,19 +78,6 @@ function ClusterSidebar() {
|
|||
refetchCluster();
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
const unlisten = await bridge.events.processPayload.listen(({ payload }) => {
|
||||
if (payload.event === 'started' || payload.event === 'finished')
|
||||
refetchProcesses();
|
||||
});
|
||||
|
||||
setListener(() => unlisten);
|
||||
});
|
||||
|
||||
onCleanup(() => {
|
||||
listener?.()?.();
|
||||
});
|
||||
|
||||
return (
|
||||
<Sidebar
|
||||
base="/clusters"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue