Open workspace pref (#44)

Ability to remember workspace window opening selection.
This commit is contained in:
Gregory Schier
2024-06-07 09:04:53 -07:00
committed by GitHub
parent 372588f541
commit f43b38c893
11 changed files with 186 additions and 74 deletions

View File

@@ -1,6 +1,6 @@
{
"db_name": "SQLite",
"query": "\n SELECT\n id, model, created_at, updated_at, theme, appearance,\n theme_dark, theme_light, update_channel,\n interface_font_size, interface_scale, editor_font_size, editor_soft_wrap\n FROM settings\n WHERE id = 'default'\n ",
"query": "\n SELECT\n id, model, created_at, updated_at, theme, appearance,\n theme_dark, theme_light, update_channel,\n interface_font_size, interface_scale, editor_font_size, editor_soft_wrap, \n open_workspace_new_window\n FROM settings\n WHERE id = 'default'\n ",
"describe": {
"columns": [
{
@@ -67,6 +67,11 @@
"name": "editor_soft_wrap",
"ordinal": 12,
"type_info": "Bool"
},
{
"name": "open_workspace_new_window",
"ordinal": 13,
"type_info": "Bool"
}
],
"parameters": {
@@ -85,8 +90,9 @@
false,
false,
false,
false
false,
true
]
},
"hash": "ca3485d87b060cd77c4114d2af544adf18f6f15341d9d5db40865e92a80da4e2"
"hash": "05dca7fe15ab1bf03952e94498ef3130e16f752da72782783696eb2cca4736d5"
}

View File

@@ -1,12 +1,12 @@
{
"db_name": "SQLite",
"query": "\n UPDATE settings SET (\n theme, appearance, theme_dark, theme_light, update_channel,\n interface_font_size, interface_scale, editor_font_size, editor_soft_wrap\n ) = (?, ?, ?, ?, ?, ?, ?, ?, ?) WHERE id = 'default';\n ",
"query": "\n UPDATE settings SET (\n theme, appearance, theme_dark, theme_light, update_channel,\n interface_font_size, interface_scale, editor_font_size, editor_soft_wrap,\n open_workspace_new_window\n ) = (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) WHERE id = 'default';\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 9
"Right": 10
},
"nullable": []
},
"hash": "efd8ba41ea909b18dd520c57c1d464c5ae057b720cbbedcaec1513d43535632c"
"hash": "6b5edf45a6799cd7f87c23a3c7f818ad110d58c601f694a619d9345ae9e8e11d"
}

View File

@@ -30,27 +30,27 @@ base64 = "0.22.0"
boa_engine = { version = "0.18.0", features = ["annex-b"] }
boa_runtime = { version = "0.18.0" }
chrono = { version = "0.4.31", features = ["serde"] }
datetime = "0.5.2"
hex_color = "3.0.0"
http = "0.2.10"
log = "0.4.21"
rand = "0.8.5"
regex = "1.10.2"
reqwest = { version = "0.11.23", features = ["multipart", "cookies", "gzip", "brotli", "deflate", "json"] }
reqwest_cookie_store = "0.6.0"
serde = { version = "1.0.198", features = ["derive"] }
serde_json = { version = "1.0.116", features = ["raw_value"] }
sqlx = { version = "0.7.4", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time"] }
tauri = { version = "2.0.0-beta", features = ["config-toml", "devtools", "protocol-asset"] }
tauri-plugin-clipboard-manager = "2.1.0-beta"
tauri-plugin-deep-link = "2.0.0-beta"
tauri-plugin-dialog = "2.0.0-beta"
tauri-plugin-fs = "2.0.0-beta"
tauri-plugin-log = { version = "2.0.0-beta", features = ["colored"] }
tauri-plugin-shell = "2.0.0-beta"
tauri-plugin-os = "2.0.0-beta"
tauri-plugin-shell = "2.0.0-beta"
tauri-plugin-updater = "2.0.0-beta"
tauri-plugin-window-state = "2.0.0-beta"
tauri-plugin-fs = "2.0.0-beta"
tauri-plugin-deep-link = "2.0.0-beta"
tokio = { version = "1.36.0", features = ["sync"] }
uuid = "1.7.0"
log = "0.4.21"
datetime = "0.5.2"
reqwest_cookie_store = "0.6.0"
tokio-stream = "0.1.15"
regex = "1.10.2"
hex_color = "3.0.0"
uuid = "1.7.0"

View File

@@ -0,0 +1 @@
ALTER TABLE settings ADD COLUMN open_workspace_new_window BOOLEAN NULL DEFAULT NULL;

View File

@@ -59,6 +59,7 @@ pub struct Settings {
pub interface_scale: i64,
pub editor_font_size: i64,
pub editor_soft_wrap: bool,
pub open_workspace_new_window: Option<bool>,
}
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)]
@@ -891,7 +892,8 @@ async fn get_settings(mgr: &impl Manager<Wry>) -> Result<Settings, sqlx::Error>
SELECT
id, model, created_at, updated_at, theme, appearance,
theme_dark, theme_light, update_channel,
interface_font_size, interface_scale, editor_font_size, editor_soft_wrap
interface_font_size, interface_scale, editor_font_size, editor_soft_wrap,
open_workspace_new_window
FROM settings
WHERE id = 'default'
"#,
@@ -928,8 +930,9 @@ pub async fn update_settings(
r#"
UPDATE settings SET (
theme, appearance, theme_dark, theme_light, update_channel,
interface_font_size, interface_scale, editor_font_size, editor_soft_wrap
) = (?, ?, ?, ?, ?, ?, ?, ?, ?) WHERE id = 'default';
interface_font_size, interface_scale, editor_font_size, editor_soft_wrap,
open_workspace_new_window
) = (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) WHERE id = 'default';
"#,
settings.theme,
settings.appearance,
@@ -940,6 +943,7 @@ pub async fn update_settings(
settings.interface_scale,
settings.editor_font_size,
settings.editor_soft_wrap,
settings.open_workspace_new_window,
)
.execute(&db)
.await?;

View File

@@ -0,0 +1,64 @@
import { useState } from 'react';
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
import { useSettings } from '../hooks/useSettings';
import { useUpdateSettings } from '../hooks/useUpdateSettings';
import type { Workspace } from '../lib/models';
import { Button } from './core/Button';
import { Checkbox } from './core/Checkbox';
import { Icon } from './core/Icon';
import { InlineCode } from './core/InlineCode';
import { HStack, VStack } from './core/Stacks';
interface Props {
hide: () => void;
workspace: Workspace;
}
export function OpenWorkspaceDialog({ hide, workspace }: Props) {
const openWorkspace = useOpenWorkspace();
const settings = useSettings();
const updateSettings = useUpdateSettings();
const [remember, setRemember] = useState<boolean>(false);
return (
<VStack space={3}>
<p>
Where would you like to open <InlineCode>{workspace.name}</InlineCode>?
</p>
<HStack space={2} justifyContent="start" className="flex-row-reverse">
<Button
className="focus"
color="primary"
onClick={() => {
hide();
openWorkspace.mutate({ workspace, inNewWindow: false });
if (remember) {
updateSettings.mutate({ openWorkspaceNewWindow: false });
}
}}
>
This Window
</Button>
<Button
className="focus"
color="secondary"
rightSlot={<Icon icon="externalLink" />}
onClick={() => {
hide();
openWorkspace.mutate({ workspace, inNewWindow: true });
if (remember) {
updateSettings.mutate({ openWorkspaceNewWindow: true });
}
}}
>
New Window
</Button>
</HStack>
{settings && (
<HStack justifyContent="end">
<Checkbox checked={remember} title="Remember my choice" onChange={setRemember} />
</HStack>
)}
</VStack>
);
}

View File

@@ -50,6 +50,33 @@ export function SettingsGeneral() {
onClick={() => checkForUpdates.mutateAsync()}
/>
</div>
<Select
name="openWorkspace"
label="Open Workspace"
labelPosition="left"
size="sm"
value={
settings.openWorkspaceNewWindow === true
? 'new'
: settings.openWorkspaceNewWindow === false
? 'current'
: 'ask'
}
onChange={(v) => {
if (v === 'current') {
updateSettings.mutate({ openWorkspaceNewWindow: false });
} else if (v === 'new') {
updateSettings.mutate({ openWorkspaceNewWindow: true });
} else {
updateSettings.mutate({ openWorkspaceNewWindow: null });
}
}}
options={[
{ label: 'Always Ask', value: 'ask' },
{ label: 'Current Window', value: 'current' },
{ label: 'New Window', value: 'new' },
]}
/>
<Separator className="my-4" />
<Heading size={2}>

View File

@@ -1,13 +1,11 @@
import { invoke } from '@tauri-apps/api/core';
import classNames from 'classnames';
import { memo, useMemo } from 'react';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useAppRoutes } from '../hooks/useAppRoutes';
import { useCommand } from '../hooks/useCommands';
import { useDeleteWorkspace } from '../hooks/useDeleteWorkspace';
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
import { usePrompt } from '../hooks/usePrompt';
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
import { getRecentRequests } from '../hooks/useRecentRequests';
import { useSettings } from '../hooks/useSettings';
import { useUpdateWorkspace } from '../hooks/useUpdateWorkspace';
import { useWorkspaces } from '../hooks/useWorkspaces';
import type { ButtonProps } from './core/Button';
@@ -16,8 +14,8 @@ import type { DropdownItem } from './core/Dropdown';
import { Dropdown } from './core/Dropdown';
import { Icon } from './core/Icon';
import { InlineCode } from './core/InlineCode';
import { HStack } from './core/Stacks';
import { useDialog } from './DialogContext';
import { OpenWorkspaceDialog } from './OpenWorkspaceDialog';
type Props = Pick<ButtonProps, 'className' | 'justify' | 'forDropdown' | 'leftSlot'>;
@@ -33,7 +31,9 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
const createWorkspace = useCommand('workspace.create');
const dialog = useDialog();
const prompt = usePrompt();
const routes = useAppRoutes();
const settings = useSettings();
const openWorkspace = useOpenWorkspace();
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
const items: DropdownItem[] = useMemo(() => {
const workspaceItems: DropdownItem[] = workspaces.map((w) => ({
@@ -41,58 +41,16 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
label: w.name,
leftSlot: w.id === activeWorkspaceId ? <Icon icon="check" /> : <Icon icon="empty" />,
onSelect: async () => {
if (typeof openWorkspaceNewWindow === 'boolean') {
openWorkspace.mutate({ workspace: w, inNewWindow: openWorkspaceNewWindow });
return;
}
dialog.show({
id: 'open-workspace',
size: 'sm',
title: 'Open Workspace',
description: (
<>
Where would you like to open <InlineCode>{w.name}</InlineCode>?
</>
),
render: ({ hide }) => {
return (
<HStack space={2} justifyContent="start" className="mt-4 mb-6 flex-row-reverse">
<Button
className="focus"
color="primary"
onClick={async () => {
hide();
const environmentId = (await getRecentEnvironments(w.id))[0];
const requestId = (await getRecentRequests(w.id))[0];
if (requestId != null) {
routes.navigate('request', { workspaceId: w.id, environmentId, requestId });
} else {
routes.navigate('workspace', { workspaceId: w.id, environmentId });
}
}}
>
This Window
</Button>
<Button
className="focus"
color="secondary"
rightSlot={<Icon icon="externalLink" />}
onClick={async () => {
hide();
const environmentId = (await getRecentEnvironments(w.id))[0];
const requestId = (await getRecentRequests(w.id))[0];
const path =
requestId != null
? routes.paths.request({
workspaceId: w.id,
environmentId,
requestId,
})
: routes.paths.workspace({ workspaceId: w.id, environmentId });
await invoke('cmd_new_window', { url: path });
}}
>
New Window
</Button>
</HStack>
);
},
render: ({ hide }) => <OpenWorkspaceDialog workspace={w} hide={hide} />,
});
},
}));
@@ -152,8 +110,9 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
createWorkspace,
deleteWorkspace.mutate,
dialog,
openWorkspace,
prompt,
routes,
openWorkspaceNewWindow,
updateWorkspace,
workspaces,
]);

View File

@@ -67,7 +67,7 @@ export function Dialog({
'rounded-lg',
'border border-background-highlight-secondary shadow-lg shadow-[rgba(0,0,0,0.1)]',
'max-w-[calc(100vw-5rem)] max-h-[calc(100vh-6rem)]',
size === 'sm' && 'w-[25rem] max-h-[80vh]',
size === 'sm' && 'w-[28rem] max-h-[80vh]',
size === 'md' && 'w-[45rem] max-h-[80vh]',
size === 'lg' && 'w-[65rem] max-h-[80vh]',
size === 'full' && 'w-[100vw] h-[100vh]',

View File

@@ -0,0 +1,50 @@
import { useMutation } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api/core';
import type { Workspace } from '../lib/models';
import { useAppRoutes } from './useAppRoutes';
import { getRecentEnvironments } from './useRecentEnvironments';
import { getRecentRequests } from './useRecentRequests';
import { useSettings } from './useSettings';
export function useOpenWorkspace() {
const settings = useSettings();
const routes = useAppRoutes();
return useMutation({
mutationFn: async ({
workspace,
inNewWindow,
}: {
workspace: Workspace;
inNewWindow: boolean;
}) => {
if (settings == null || workspace == null) return;
if (inNewWindow) {
const environmentId = (await getRecentEnvironments(workspace.id))[0];
const requestId = (await getRecentRequests(workspace.id))[0];
const path =
requestId != null
? routes.paths.request({
workspaceId: workspace.id,
environmentId,
requestId,
})
: routes.paths.workspace({ workspaceId: workspace.id, environmentId });
await invoke('cmd_new_window', { url: path });
} else {
const environmentId = (await getRecentEnvironments(workspace.id))[0];
const requestId = (await getRecentRequests(workspace.id))[0];
if (requestId != null) {
routes.navigate('request', {
workspaceId: workspace.id,
environmentId,
requestId,
});
} else {
routes.navigate('workspace', { workspaceId: workspace.id, environmentId });
}
}
},
});
}

View File

@@ -41,6 +41,7 @@ export interface Settings extends BaseModel {
interfaceScale: number;
editorFontSize: number;
editorSoftWrap: boolean;
openWorkspaceNewWindow: boolean | null;
}
export interface Workspace extends BaseModel {