feat: cluster logs and ui tweaks
This commit is contained in:
parent
fbf04cba9a
commit
1a099f6c3b
15 changed files with 340 additions and 61 deletions
60
Cargo.lock
generated
60
Cargo.lock
generated
|
|
@ -2512,6 +2512,25 @@ version = "2.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
|
||||
|
||||
[[package]]
|
||||
name = "is-docker"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-wsl"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
|
||||
dependencies = [
|
||||
"is-docker",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
|
|
@ -3482,6 +3501,7 @@ dependencies = [
|
|||
"tauri-plugin-clipboard-manager",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-opener",
|
||||
"tauri-plugin-single-instance",
|
||||
"tauri-plugin-updater",
|
||||
"tauri-plugin-window-state",
|
||||
|
|
@ -3512,6 +3532,18 @@ dependencies = [
|
|||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "5.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"is-wsl",
|
||||
"libc",
|
||||
"pathdiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
|
|
@ -3673,6 +3705,12 @@ version = "1.0.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
|
|
@ -6010,6 +6048,28 @@ dependencies = [
|
|||
"uuid 1.16.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-opener"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c8983f50326d34437142a6d560b5c3426e91324297519b6eeb32ed0a1d1e0f2"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.1",
|
||||
"open",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
"windows 0.61.1",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-single-instance"
|
||||
version = "2.2.3"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ tauri-plugin-dialog = { version = "=2.2.1" }
|
|||
tauri-plugin-single-instance = { version = "=2.2.3" }
|
||||
tauri-plugin-updater = { version = "=2.7.1" }
|
||||
tauri-plugin-window-state = { version = "=2.2.2" }
|
||||
tauri-plugin-opener = { version = "=2.3.0" }
|
||||
|
||||
# code gen
|
||||
strum = { version = "=0.27.1", features = [ "derive" ] }
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ tauri-plugin-updater = { workspace = true }
|
|||
tauri-plugin-clipboard-manager = { workspace = true }
|
||||
tauri-plugin-dialog = { workspace = true }
|
||||
tauri-plugin-deep-link = { workspace = true }
|
||||
tauri-plugin-opener = { workspace = true }
|
||||
|
||||
# code gen
|
||||
taurpc = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
"$schema": "../gen/schemas/desktop-schema.json",
|
||||
"identifier": "default",
|
||||
"description": "capabilities for the main window",
|
||||
"windows": ["*"],
|
||||
"windows": [
|
||||
"*"
|
||||
],
|
||||
"permissions": [
|
||||
"core:app:default",
|
||||
"core:webview:default",
|
||||
|
|
@ -12,7 +14,6 @@
|
|||
"core:resources:default",
|
||||
"core:tray:default",
|
||||
"core:window:default",
|
||||
|
||||
"core:window:allow-close",
|
||||
"core:window:allow-create",
|
||||
"core:window:allow-destroy",
|
||||
|
|
@ -24,13 +25,20 @@
|
|||
"core:window:allow-set-decorations",
|
||||
"core:window:allow-set-title-bar-style",
|
||||
"core:webview:allow-internal-toggle-devtools",
|
||||
|
||||
"core:event:default",
|
||||
"clipboard-manager:allow-write-text",
|
||||
"dialog:allow-open",
|
||||
"dialog:allow-save",
|
||||
"dialog:allow-confirm",
|
||||
"deep-link:default",
|
||||
"updater:default"
|
||||
"updater:default",
|
||||
{
|
||||
"identifier": "opener:allow-open-path",
|
||||
"allow": [
|
||||
{
|
||||
"path": "$DATA/OneLauncher"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ async fn initialize_tauri(builder: tauri::Builder<tauri::Wry>) -> LauncherResult
|
|||
.plugin(tauri_plugin_clipboard_manager::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_deep_link::init())
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.menu(tauri::menu::Menu::new)
|
||||
.invoke_handler(router.into_handler())
|
||||
.setup(move |app| {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"@tauri-apps/api": "^2.5.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.2.2",
|
||||
"@tauri-apps/plugin-dialog": "^2.2.1",
|
||||
"@tauri-apps/plugin-opener": "^2.3.0",
|
||||
"@tauri-apps/plugin-shell": "^2.2.1",
|
||||
"@untitled-theme/icons-react": "^0.14.0",
|
||||
"motion": "^12.10.5",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { IngressPayload, Version, VersionType } from '@/bindings.gen';
|
||||
import type { GameLoader, IngressPayload, Version, VersionType } from '@/bindings.gen';
|
||||
import type { JSX, RefAttributes } from 'react';
|
||||
import DefaultBanner from '@/assets/images/default_banner.png';
|
||||
import DefaultClusterBanner from '@/assets/images/default_instance_cover.jpg';
|
||||
|
|
@ -6,7 +6,7 @@ import LauncherIcon from '@/components/content/LauncherIcon';
|
|||
import Modal from '@/components/overlay/Modal';
|
||||
import ScrollableContainer from '@/components/ScrollableContainer';
|
||||
import { bindings } from '@/main';
|
||||
import { LAUNCHER_IMPORT_TYPES } from '@/utils';
|
||||
import { LAUNCHER_IMPORT_TYPES, LOADERS, upperFirst } from '@/utils';
|
||||
import { useCommand } from '@onelauncher/common';
|
||||
import { Button, Dropdown, SelectList, TextField } from '@onelauncher/common/components';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
|
@ -36,7 +36,7 @@ export function NewClusterCreate() {
|
|||
|
||||
const create = useCommand('createCluster', () => bindings.core.createCluster({
|
||||
icon: DefaultClusterBanner,
|
||||
mc_loader: 'vanilla',
|
||||
mc_loader: formData.loader as GameLoader,
|
||||
mc_loader_version: null,
|
||||
mc_version: formData.clusterVersion,
|
||||
name: formData.clusterName,
|
||||
|
|
@ -91,6 +91,7 @@ export function NewClusterCreate() {
|
|||
<ClusterInformation
|
||||
clusterName={formData.clusterName}
|
||||
clusterVersion={formData.clusterVersion}
|
||||
onClusterLoaderChange={loader => setFormData(prev => ({ ...prev, loader }))}
|
||||
onClusterNameChange={name => setFormData(prev => ({ ...prev, clusterName: name }))}
|
||||
onClusterVersionChange={version =>
|
||||
setFormData(prev => ({ ...prev, clusterVersion: version }))}
|
||||
|
|
@ -231,6 +232,7 @@ interface ClusterInformationProps {
|
|||
onClusterNameChange: (name: string) => void;
|
||||
clusterVersion: string;
|
||||
onClusterVersionChange: (version: string) => void;
|
||||
onClusterLoaderChange: (loader: GameLoader) => void;
|
||||
}
|
||||
|
||||
function ClusterInformation({
|
||||
|
|
@ -238,6 +240,7 @@ function ClusterInformation({
|
|||
onClusterNameChange,
|
||||
clusterVersion,
|
||||
onClusterVersionChange,
|
||||
onClusterLoaderChange,
|
||||
}: ClusterInformationProps) {
|
||||
const versions = useCommand('getGameVersions', bindings.core.getGameVersions);
|
||||
|
||||
|
|
@ -258,35 +261,17 @@ function ClusterInformation({
|
|||
</Option>
|
||||
|
||||
<Option header="Loader">
|
||||
<Dropdown defaultSelectedKey="vanilla">
|
||||
<Dropdown.Item>
|
||||
<div className="flex flex-row">
|
||||
<LoaderIcon className="size-5" loader="vanilla" />
|
||||
{' '}
|
||||
Vanilla
|
||||
</div>
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item>
|
||||
<div className="flex flex-row">
|
||||
<LoaderIcon className="size-5" loader="fabric" />
|
||||
{' '}
|
||||
Fabric
|
||||
</div>
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item>
|
||||
<div className="flex flex-row">
|
||||
<LoaderIcon className="size-5" loader="quilt" />
|
||||
{' '}
|
||||
Quilt
|
||||
</div>
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item>
|
||||
<div className="flex flex-row">
|
||||
<LoaderIcon className="size-5" loader="forge" />
|
||||
{' '}
|
||||
Forge
|
||||
</div>
|
||||
</Dropdown.Item>
|
||||
{/* TODO: fixme */}
|
||||
<Dropdown defaultSelectedKey="vanilla" onSelectionChange={e => onClusterLoaderChange(e)}>
|
||||
{LOADERS.map(loader => (
|
||||
<Dropdown.Item key={loader}>
|
||||
<div className="flex flex-row">
|
||||
<LoaderIcon className="size-5" loader={loader as GameLoader} />
|
||||
{' '}
|
||||
{upperFirst(loader)}
|
||||
</div>
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown>
|
||||
</Option>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import { bindings } from '@/main';
|
|||
import { useCommand } from '@onelauncher/common';
|
||||
import { Button, Show, TextField } from '@onelauncher/common/components';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import { dataDir } from '@tauri-apps/api/path';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { Edit02Icon, FolderIcon, ImagePlusIcon, Share07Icon, Tool02Icon, Trash01Icon } from '@untitled-theme/icons-react';
|
||||
import { useState } from 'react';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
|
@ -20,12 +22,12 @@ export const Route = createFileRoute('/app/cluster/')({
|
|||
|
||||
function RouteComponent() {
|
||||
const { id } = Route.useSearch();
|
||||
const [newCover, setNewCover] = useState<string>('');
|
||||
const [newName, setNewName] = useState<string>('');
|
||||
const [edit, setEdit] = useState<boolean>(false);
|
||||
const cluster = useCommand('getClusterById', () => bindings.core.getClusterById(Number(id.toString()) as unknown as bigint));
|
||||
|
||||
// dumbass fix ik
|
||||
const cluster = useCommand('getClusterById', () => bindings.core.getClusterById(Number(id.toString()) as unknown as bigint));
|
||||
const [newCover, setNewCover] = useState<string>(cluster.data?.icon_url as string);
|
||||
const [newName, setNewName] = useState<string>(cluster.data?.name as string);
|
||||
const [edit, setEdit] = useState<boolean>(false);
|
||||
|
||||
const editing = useCommand('updateClusterById', () => bindings.core.updateClusterById(Number(id.toString()) as unknown as bigint, {
|
||||
icon_url: newCover,
|
||||
|
|
@ -35,6 +37,11 @@ function RouteComponent() {
|
|||
subscribed: false,
|
||||
});
|
||||
|
||||
bindings.events.process.on((e) => {
|
||||
// eslint-disable-next-line no-console -- ok
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
function handleEditMode() {
|
||||
if (edit)
|
||||
editing.refetch();
|
||||
|
|
@ -126,22 +133,24 @@ function Banner({
|
|||
cluster,
|
||||
editMode,
|
||||
setNewName,
|
||||
setNewCover,
|
||||
}: BannerProps) {
|
||||
// async function launchFilePicker() {
|
||||
// const selected = await dialog.open({
|
||||
// multiple: false,
|
||||
// directory: false,
|
||||
// filters: [{
|
||||
// name: 'Image',
|
||||
// extensions: ['png', 'jpg', 'jpeg', 'webp'],
|
||||
// }],
|
||||
// });
|
||||
async function launchFilePicker() {
|
||||
const selected = await open({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [{
|
||||
name: 'Image',
|
||||
extensions: ['png', 'jpg', 'jpeg', 'webp'],
|
||||
}],
|
||||
});
|
||||
|
||||
// if (selected === null)
|
||||
// return;
|
||||
if (selected === null)
|
||||
return;
|
||||
|
||||
setNewCover(selected);
|
||||
}
|
||||
|
||||
// props.setNewCover(selected);
|
||||
// }
|
||||
const launch = useCommand('launchCluster', () => bindings.core.launchCluster(cluster?.id as bigint, null), {
|
||||
enabled: false,
|
||||
subscribed: false,
|
||||
|
|
@ -161,20 +170,29 @@ function Banner({
|
|||
setNewName(name);
|
||||
}
|
||||
|
||||
const image = () => {
|
||||
const url = cluster?.icon_url;
|
||||
|
||||
if (url === undefined || url === null)
|
||||
return DefaultInstancePhoto;
|
||||
|
||||
return convertFileSrc(url);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-37 flex flex-row gap-x-2.5 rounded-xl bg-page-elevated p-2.5">
|
||||
<div className="relative aspect-ratio-video h-full min-w-57 w-57 overflow-hidden border border-component-bg/10 rounded-lg">
|
||||
<Show when={editMode}>
|
||||
<div
|
||||
className="absolute z-1 h-full w-full flex items-center justify-center bg-black/50 opacity-50 hover:opacity-100"
|
||||
// onClick={launchFilePicker}
|
||||
onClick={launchFilePicker}
|
||||
>
|
||||
<ImagePlusIcon className="h-12 w-12" />
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
{/* <ClusterCover class="h-full w-full object-cover" cluster={props.cluster} override={props.newCover()} /> */}
|
||||
<img src={cluster?.icon_url || DefaultInstancePhoto} />
|
||||
<img src={image()} />
|
||||
</div>
|
||||
|
||||
<div className="w-full flex flex-col justify-between gap-y-.5 overflow-hidden text-fg-primary">
|
||||
|
|
@ -222,8 +240,7 @@ function Banner({
|
|||
<Button
|
||||
children={<Share07Icon />}
|
||||
color="secondary"
|
||||
// disabled={props.editMode()}
|
||||
isDisabled
|
||||
isDisabled={editMode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
150
apps/onelauncher/frontend/src/routes/app/cluster/logs.tsx
Normal file
150
apps/onelauncher/frontend/src/routes/app/cluster/logs.tsx
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
import type { ProcessPayload } from '@/bindings.gen';
|
||||
import ScrollableContainer from '@/components/ScrollableContainer';
|
||||
import { bindings } from '@/main';
|
||||
import { Button, Show } from '@onelauncher/common/components';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { LinkExternal01Icon, Upload01Icon } from '@untitled-theme/icons-react';
|
||||
import { useCallback, useEffect, useReducer } from 'react';
|
||||
import {
|
||||
ListBox,
|
||||
ListBoxItem,
|
||||
ListLayout,
|
||||
Virtualizer,
|
||||
} from 'react-aria-components';
|
||||
import Sidebar from '../settings/route';
|
||||
|
||||
export const Route = createFileRoute('/app/cluster/logs')({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
enum LoggerActionType {
|
||||
ADD,
|
||||
}
|
||||
|
||||
interface LoggerAction {
|
||||
type: LoggerActionType;
|
||||
payload: ProcessPayload;
|
||||
}
|
||||
|
||||
function reducer(state: Array<ProcessPayload>, action: LoggerAction) {
|
||||
const { type, payload } = action;
|
||||
switch (type) {
|
||||
// eslint-disable-next-line ts/no-unnecessary-condition -- oh please shut the fuck up i dont want to listen your yapping anymore
|
||||
case LoggerActionType.ADD:
|
||||
return [...state, payload];
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function RouteComponent() {
|
||||
const { id: _id } = Route.useSearch();
|
||||
const [logs, dispatch] = useReducer(reducer, []);
|
||||
|
||||
const addLog = useCallback((newLog: ProcessPayload) => {
|
||||
dispatch({ type: LoggerActionType.ADD, payload: newLog });
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
bindings.events.process.on(addLog);
|
||||
}, [addLog]);
|
||||
|
||||
return (
|
||||
<Sidebar.Page>
|
||||
<h1>Overview</h1>
|
||||
<ScrollableContainer>
|
||||
<div className="h-full">
|
||||
<div className="flex flex-1 flex-col">
|
||||
<div className="flex flex-1 flex-col gap-y-2">
|
||||
<div className="h-10 flex flex-row items-center justify-between gap-x-1">
|
||||
<h1>Logs</h1>
|
||||
<div className="flex flex-row gap-x-2">
|
||||
<Button
|
||||
color="secondary"
|
||||
// isDisabled={missingLogs()}
|
||||
// onClick={uploadAndOpenLog}
|
||||
>
|
||||
<Upload01Icon />
|
||||
{' '}
|
||||
Upload
|
||||
</Button>
|
||||
|
||||
{/* <Dropdown
|
||||
class="min-w-50"
|
||||
disabled={missingLogs()}
|
||||
onChange={changeLog}
|
||||
>
|
||||
<For each={logs() || ['None']}>
|
||||
{(log) => {
|
||||
const pretty = log.split('/').pop();
|
||||
return (
|
||||
<Dropdown.Row>
|
||||
<div>
|
||||
{pretty}
|
||||
</div>
|
||||
</Dropdown.Row>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</Dropdown> */}
|
||||
|
||||
<Button
|
||||
color="primary"
|
||||
// onClick={openFolder}
|
||||
>
|
||||
<LinkExternal01Icon />
|
||||
{' '}
|
||||
Open Folder
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Show
|
||||
fallback={<span>No logs were found.</span>}
|
||||
when={logs.length > 0}
|
||||
>
|
||||
<FormattedLog log={logs} />
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollableContainer>
|
||||
</Sidebar.Page>
|
||||
);
|
||||
}
|
||||
|
||||
interface FormattedLogProps {
|
||||
log: Array<ProcessPayload>;
|
||||
}
|
||||
|
||||
function FormattedLog(props: FormattedLogProps) {
|
||||
const { log } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Virtualizer
|
||||
layout={ListLayout}
|
||||
layoutOptions={{
|
||||
rowHeight: 32,
|
||||
padding: 4,
|
||||
gap: 4,
|
||||
}}
|
||||
>
|
||||
<ListBox
|
||||
aria-label="Virtualized ListBox"
|
||||
items={log}
|
||||
selectionMode="none"
|
||||
>
|
||||
{(item) => {
|
||||
if (item.type === 'Output')
|
||||
return (
|
||||
<ListBoxItem key={item.output}>
|
||||
{item.output}
|
||||
</ListBoxItem>
|
||||
);
|
||||
}}
|
||||
</ListBox>
|
||||
</Virtualizer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import type { ClusterModel } from '@/bindings.gen';
|
||||
import type { ClusterModel, IngressType } from '@/bindings.gen';
|
||||
import DefaultBanner from '@/assets/images/default_banner.png';
|
||||
import DefaultInstancePhoto from '@/assets/images/default_instance_cover.jpg';
|
||||
import { NewClusterCreate } from '@/components/launcher/cluster/ClusterCreation';
|
||||
|
|
@ -7,7 +7,8 @@ import { bindings } from '@/main';
|
|||
import { upperFirst } from '@/utils';
|
||||
import { useCommand } from '@onelauncher/common';
|
||||
import { Button, Show, TextField } from '@onelauncher/common/components';
|
||||
import { createFileRoute, Link } from '@tanstack/react-router';
|
||||
import { createFileRoute, Link, useNavigate } from '@tanstack/react-router';
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import { PlayIcon, Server01Icon } from '@untitled-theme/icons-react';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
|
||||
|
|
@ -26,6 +27,13 @@ hey future sassan here i guess the issue is solved idk
|
|||
function RouteComponent() {
|
||||
const result = useCommand('getClusters', bindings.core.getClusters);
|
||||
|
||||
bindings.events.ingress.on((e) => {
|
||||
if (typeof e.ingress_type === 'object')
|
||||
if ('PrepareCluster' in e.ingress_type)
|
||||
// eslint-disable-next-line no-console -- ok
|
||||
console.log(`Preparing cluster: ${e.ingress_type.PrepareCluster.cluster_name} %${e.percent}`);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col gap-y-4 text-fg-primary">
|
||||
<Banner />
|
||||
|
|
@ -149,6 +157,7 @@ function ClusterCard({
|
|||
name,
|
||||
mc_loader,
|
||||
mc_version,
|
||||
icon_url,
|
||||
}: ClusterModel) {
|
||||
const launch = useCommand('launchCluster', () => bindings.core.launchCluster(id, null), {
|
||||
enabled: false,
|
||||
|
|
@ -162,6 +171,15 @@ function ClusterCard({
|
|||
console.error(launch.error.message);
|
||||
};
|
||||
|
||||
const image = () => {
|
||||
const url = icon_url;
|
||||
|
||||
if (url === null)
|
||||
return DefaultInstancePhoto;
|
||||
|
||||
return convertFileSrc(url);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Link
|
||||
|
|
@ -178,7 +196,7 @@ function ClusterCard({
|
|||
>
|
||||
<img
|
||||
className="h-full w-full object-cover"
|
||||
src={DefaultInstancePhoto}
|
||||
src={image()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { bindings } from '@/main';
|
|||
import { useCommand } from '@onelauncher/common';
|
||||
import { Button, Switch } from '@onelauncher/common/components';
|
||||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { dataDir } from '@tauri-apps/api/path';
|
||||
import { openPath as open } from '@tauri-apps/plugin-opener';
|
||||
import { FolderIcon, LinkExternal01Icon, XIcon } from '@untitled-theme/icons-react';
|
||||
import Sidebar from './route';
|
||||
|
||||
|
|
@ -14,6 +16,12 @@ export const Route = createFileRoute('/app/settings/')({
|
|||
function RouteComponent() {
|
||||
const _result = useCommand('getGlobalProfile', bindings.core.getGlobalProfile);
|
||||
|
||||
const openLauncherDir = async () => {
|
||||
const dir = await dataDir();
|
||||
|
||||
open(`${dir}/OneLauncher`);
|
||||
};
|
||||
|
||||
return (
|
||||
<Sidebar.Page>
|
||||
<div className="h-full">
|
||||
|
|
@ -52,7 +60,7 @@ function RouteComponent() {
|
|||
icon={<FolderIcon />}
|
||||
title="Launcher Folder"
|
||||
>
|
||||
<Button size="normal">
|
||||
<Button onClick={openLauncherDir} size="normal">
|
||||
<LinkExternal01Icon />
|
||||
{' '}
|
||||
Open
|
||||
|
|
|
|||
|
|
@ -10,6 +10,15 @@ export const LAUNCHER_IMPORT_TYPES: Array<string> = [
|
|||
// 'Technic'
|
||||
] as const;
|
||||
|
||||
export const LOADERS: Array<string> = [
|
||||
'vanilla',
|
||||
'forge',
|
||||
'neoforge',
|
||||
'quilt',
|
||||
'fabric',
|
||||
'legacyfabric',
|
||||
] as const;
|
||||
|
||||
export function pluralize(n: number, word: string, locale: string = 'en'): string {
|
||||
const pluralRules = new Intl.PluralRules(locale);
|
||||
const pluralForm = pluralRules.select(n);
|
||||
|
|
|
|||
|
|
@ -105,6 +105,15 @@ impl TauriLauncherApi for TauriLauncherApiImpl {
|
|||
async fn create_cluster(self, options: CreateCluster) -> LauncherResult<Cluster> {
|
||||
let cluster = api::cluster::create_cluster(&options.name, &options.mc_version, options.mc_loader, options.mc_loader_version.as_deref(), options.icon).await?;
|
||||
|
||||
api::setting_profiles::create_profile(&options.name, |mut active_model: SettingsProfilePartial| async move {
|
||||
active_model.force_fullscreen = Set(Some(false));
|
||||
|
||||
active_model.mem_max = Set(Some(2048));
|
||||
|
||||
Ok(active_model)
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(cluster)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ const dropdownStyles = tv({
|
|||
triggerCustomIcon: 'w-4 h-4',
|
||||
|
||||
popover: [
|
||||
// width is not full instead it behaves like w-screen for some fucking reason
|
||||
'mt-1 rounded-lg shadow-md',
|
||||
'bg-component-bg border border-component-border',
|
||||
'data-[entering]:animate-in data-[entering]:fade-in data-[entering]:zoom-in-95',
|
||||
|
|
|
|||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
|
|
@ -246,6 +246,9 @@ importers:
|
|||
'@tauri-apps/plugin-dialog':
|
||||
specifier: ^2.2.1
|
||||
version: 2.2.1
|
||||
'@tauri-apps/plugin-opener':
|
||||
specifier: ^2.3.0
|
||||
version: 2.3.0
|
||||
'@tauri-apps/plugin-shell':
|
||||
specifier: ^2.2.1
|
||||
version: 2.2.1
|
||||
|
|
@ -2811,6 +2814,9 @@ packages:
|
|||
'@tauri-apps/plugin-dialog@2.2.1':
|
||||
resolution: {integrity: sha512-wZmCouo4PgTosh/UoejPw9DPs6RllS5Pp3fuOV2JobCu36mR5AXU2MzU9NZiVaFi/5Zfc8RN0IhcZHnksJ1o8A==}
|
||||
|
||||
'@tauri-apps/plugin-opener@2.3.0':
|
||||
resolution: {integrity: sha512-yAbauwp8BCHIhhA48NN8rEf6OtfZBPCgTOCa10gmtoVCpmic5Bq+1Ba7C+NZOjogedkSiV7hAotjYnnbUVmYrw==}
|
||||
|
||||
'@tauri-apps/plugin-shell@2.2.1':
|
||||
resolution: {integrity: sha512-G1GFYyWe/KlCsymuLiNImUgC8zGY0tI0Y3p8JgBCWduR5IEXlIJS+JuG1qtveitwYXlfJrsExt3enhv5l2/yhA==}
|
||||
|
||||
|
|
@ -8504,6 +8510,10 @@ snapshots:
|
|||
dependencies:
|
||||
'@tauri-apps/api': 2.5.0
|
||||
|
||||
'@tauri-apps/plugin-opener@2.3.0':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.5.0
|
||||
|
||||
'@tauri-apps/plugin-shell@2.2.1':
|
||||
dependencies:
|
||||
'@tauri-apps/api': 2.5.0
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue