feat: Common delete modal + delete modal when removing accounts + remove default user if the user being removed is the default
This commit is contained in:
parent
ca636e65c0
commit
af1ea68a32
6 changed files with 137 additions and 69 deletions
|
|
@ -1,7 +1,6 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use interpulse::api::minecraft::Version;
|
||||
use onelauncher::constants::{NATIVE_ARCH, TARGET_OS, VERSION};
|
||||
use onelauncher::data::{Loader, ManagedPackage, MinecraftCredentials, PackageData, Settings};
|
||||
use onelauncher::package::content;
|
||||
use onelauncher::store::{Cluster, ClusterPath};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type {
|
|||
Ref,
|
||||
Setter,
|
||||
} from 'solid-js';
|
||||
import { For } from 'solid-js';
|
||||
import { For, createEffect, createSignal, on } from 'solid-js';
|
||||
import { mergeRefs } from '@solid-primitives/refs';
|
||||
import Button from '../base/Button';
|
||||
import FullscreenOverlay from './FullscreenOverlay';
|
||||
|
|
@ -67,6 +67,110 @@ Modal.Simple = function (props: ModalSimpleProps) {
|
|||
);
|
||||
};
|
||||
|
||||
type ModalDeleteProps = MakeOptional<ModalSimpleProps, 'title'> & {
|
||||
onCancel?: () => void;
|
||||
onDelete?: () => void;
|
||||
timeLeft?: number;
|
||||
};
|
||||
|
||||
Modal.Delete = function (props: ModalDeleteProps) {
|
||||
const [timeLeft, setTimeLeft] = createSignal(1);
|
||||
const [intervalId, setIntervalId] = createSignal<NodeJS.Timeout | undefined>(undefined);
|
||||
|
||||
createEffect(on(() => props.visible(), (visible) => {
|
||||
startInterval(visible);
|
||||
if (visible !== true)
|
||||
onCancel();
|
||||
}));
|
||||
|
||||
function clearIntervalId() {
|
||||
if (intervalId())
|
||||
clearInterval(intervalId());
|
||||
}
|
||||
|
||||
function startInterval(visible: boolean) {
|
||||
if (visible !== true)
|
||||
return;
|
||||
|
||||
clearIntervalId();
|
||||
setTimeLeft(props.timeLeft || 3);
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
setTimeLeft((prev) => {
|
||||
const next = prev - 1;
|
||||
|
||||
if (next <= 0)
|
||||
clearIntervalId();
|
||||
|
||||
return next;
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
setIntervalId(intervalId);
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
if (props.visible() === true)
|
||||
props.setVisible(false);
|
||||
|
||||
if (props.onCancel)
|
||||
props.onCancel();
|
||||
}
|
||||
|
||||
function onDelete() {
|
||||
if (props.visible() === true)
|
||||
props.setVisible(false);
|
||||
|
||||
if (props.onDelete)
|
||||
props.onDelete();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal.Simple
|
||||
title={props.title || 'Confirm Delete'}
|
||||
ref={props.ref}
|
||||
setVisible={props.setVisible}
|
||||
visible={props.visible}
|
||||
mount={props.mount}
|
||||
zIndex={props.zIndex}
|
||||
buttons={props.buttons || [
|
||||
<Button
|
||||
buttonStyle="secondary"
|
||||
children="Cancel"
|
||||
onClick={onCancel}
|
||||
/>,
|
||||
<Button
|
||||
buttonStyle="danger"
|
||||
children={`Delete${timeLeft() > 0 ? ` (${timeLeft()}s)` : ''}`}
|
||||
disabled={timeLeft() > 0}
|
||||
onClick={onDelete}
|
||||
/>,
|
||||
]}
|
||||
>
|
||||
{props.children || (
|
||||
<>
|
||||
<div class="flex flex-col justify-center items-center gap-y-3">
|
||||
<p>Are you sure you want to delete this item?</p>
|
||||
<p class="text-danger uppercase w-82 line-height-normal">
|
||||
Doing this will
|
||||
{' '}
|
||||
<span class="underline font-bold">delete</span>
|
||||
{' '}
|
||||
your entire
|
||||
{' '}
|
||||
<br />
|
||||
data
|
||||
{' '}
|
||||
<span class="underline font-bold">FOREVER</span>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Modal.Simple>
|
||||
);
|
||||
};
|
||||
|
||||
function ModalButton(button: { props: ModalButtonProps }) {
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ interface AccountControllerContextFunc {
|
|||
accounts: Resource<MinecraftCredentials[]>;
|
||||
defaultAccount: Resource<MinecraftCredentials | null>;
|
||||
setDefaultAccount: (uuid: string) => Promise<void>;
|
||||
removeAccount: (uuid: string) => Promise<void>;
|
||||
removeAccount: (uuid: string, force?: boolean) => Promise<void>;
|
||||
}
|
||||
|
||||
const AccountControllerContext = createContext<AccountControllerContextFunc>() as Context<AccountControllerContextFunc>;
|
||||
|
|
@ -22,6 +22,9 @@ export function AccountControllerProvider(props: ParentProps) {
|
|||
const [defaultAccount, { refetch: refetchDefaultAccount }] = useCommand(bridge.commands.getDefaultUser);
|
||||
const [visible, setVisible] = createSignal(false);
|
||||
|
||||
const [deleteModalUuid, setDeleteModalUuid] = createSignal<string>();
|
||||
const deleteModalVisible = () => deleteModalUuid() !== undefined;
|
||||
|
||||
function refetch() {
|
||||
refetchAccounts();
|
||||
refetchDefaultAccount();
|
||||
|
|
@ -31,7 +34,17 @@ export function AccountControllerProvider(props: ParentProps) {
|
|||
await tryResult(bridge.commands.setDefaultUser, uuid);
|
||||
}
|
||||
|
||||
async function removeAccount(uuid: string) {
|
||||
async function removeAccount(uuid: string, force?: boolean) {
|
||||
if (force !== true)
|
||||
setDeleteModalUuid(uuid);
|
||||
else
|
||||
await _forceRemoveAccount(uuid);
|
||||
}
|
||||
|
||||
async function _forceRemoveAccount(uuid: string | undefined) {
|
||||
if (uuid === undefined)
|
||||
return;
|
||||
|
||||
await tryResult(bridge.commands.removeUser, uuid);
|
||||
refetch();
|
||||
}
|
||||
|
|
@ -49,6 +62,12 @@ export function AccountControllerProvider(props: ParentProps) {
|
|||
<AccountControllerContext.Provider value={func}>
|
||||
{props.children}
|
||||
<AddAccountModal visible={visible} setVisible={setVisible} refetch={refetch} />
|
||||
|
||||
<Modal.Delete
|
||||
setVisible={value => setDeleteModalUuid(value ? deleteModalUuid() : undefined)}
|
||||
visible={deleteModalVisible}
|
||||
onDelete={() => _forceRemoveAccount(deleteModalUuid())}
|
||||
/>
|
||||
</AccountControllerContext.Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { PlayIcon, Share07Icon, Trash01Icon } from '@untitled-theme/icons-solid';
|
||||
import { type Accessor, type Setter, createEffect, createSignal, on } from 'solid-js';
|
||||
import { createSignal } from 'solid-js';
|
||||
import { useNavigate } from '@solidjs/router';
|
||||
import ClusterCover from '../../components/game/ClusterCover';
|
||||
import LoaderIcon from '../../components/game/LoaderIcon';
|
||||
|
|
@ -30,76 +30,15 @@ function ClusterOverview() {
|
|||
<Banner {...cluster} showDeletePrompt={() => setDeleteVisible(true)} />
|
||||
</ScrollableContainer>
|
||||
|
||||
<DeleteModal
|
||||
<Modal.Delete
|
||||
visible={deleteVisible}
|
||||
setVisible={setDeleteVisible}
|
||||
deleteCluster={deleteCluster}
|
||||
onDelete={deleteCluster}
|
||||
/>
|
||||
</Sidebar.Page>
|
||||
);
|
||||
}
|
||||
|
||||
interface DeleteModalProps {
|
||||
visible: Accessor<boolean>;
|
||||
setVisible: Setter<boolean>;
|
||||
deleteCluster: () => void;
|
||||
};
|
||||
function DeleteModal(props: DeleteModalProps) {
|
||||
const [timeLeft, setTimeLeft] = createSignal(3);
|
||||
|
||||
createEffect(on(() => props.visible(), (visible) => {
|
||||
if (visible !== true)
|
||||
return;
|
||||
|
||||
setTimeLeft(3);
|
||||
const interval = setInterval(() => {
|
||||
setTimeLeft((prev) => {
|
||||
const next = prev - 1;
|
||||
|
||||
if (next <= 0)
|
||||
clearInterval(interval);
|
||||
|
||||
return next;
|
||||
});
|
||||
}, 1000);
|
||||
}));
|
||||
|
||||
return (
|
||||
<Modal.Simple
|
||||
visible={props.visible}
|
||||
setVisible={props.setVisible}
|
||||
title="Delete Cluster"
|
||||
buttons={[
|
||||
<Button
|
||||
buttonStyle="secondary"
|
||||
children="Cancel"
|
||||
onClick={() => props.setVisible(false)}
|
||||
/>,
|
||||
<Button
|
||||
buttonStyle="danger"
|
||||
children={`Delete${timeLeft() > 0 ? ` (${timeLeft()}s)` : ''}`}
|
||||
disabled={timeLeft() > 0}
|
||||
onClick={props.deleteCluster}
|
||||
/>,
|
||||
]}
|
||||
>
|
||||
<div class="flex flex-col justify-center items-center gap-y-3">
|
||||
<p>Are you sure you want to delete this cluster?</p>
|
||||
<p class="text-danger uppercase max-w-82 line-height-normal">
|
||||
Doing this will
|
||||
{' '}
|
||||
<span class="underline font-bold">delete</span>
|
||||
{' '}
|
||||
your entire cluster data
|
||||
{' '}
|
||||
<span class="underline font-bold">FOREVER</span>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</Modal.Simple>
|
||||
);
|
||||
}
|
||||
|
||||
function Banner(props: Cluster & { showDeletePrompt: () => void }) {
|
||||
async function launch() {
|
||||
const [_uuid, _pid] = await tryResult(bridge.commands.runCluster, props.uuid);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ async fn main() -> onelauncher::Result<()> {
|
|||
let _logger = onelauncher::start_logger();
|
||||
let _state = State::get().await?;
|
||||
|
||||
modrinth().await?;
|
||||
// modrinth().await?;
|
||||
// launch_and_authenticate().await?;
|
||||
authenticate_mc().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -305,6 +305,11 @@ impl MinecraftState {
|
|||
#[tracing::instrument(skip(self))]
|
||||
pub async fn remove(&mut self, id: Uuid) -> crate::Result<Option<MinecraftCredentials>> {
|
||||
let val = self.users.remove(&id);
|
||||
|
||||
if self.default_user == Some(id) {
|
||||
self.default_user = None;
|
||||
}
|
||||
|
||||
self.save().await?;
|
||||
Ok(val)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue