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 e326405f4f
commit 993d4dc65d
11 changed files with 186 additions and 74 deletions
@@ -1,6 +1,6 @@
{ {
"db_name": "SQLite", "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": { "describe": {
"columns": [ "columns": [
{ {
@@ -67,6 +67,11 @@
"name": "editor_soft_wrap", "name": "editor_soft_wrap",
"ordinal": 12, "ordinal": 12,
"type_info": "Bool" "type_info": "Bool"
},
{
"name": "open_workspace_new_window",
"ordinal": 13,
"type_info": "Bool"
} }
], ],
"parameters": { "parameters": {
@@ -85,8 +90,9 @@
false, false,
false, false,
false, false,
false false,
true
] ]
}, },
"hash": "ca3485d87b060cd77c4114d2af544adf18f6f15341d9d5db40865e92a80da4e2" "hash": "05dca7fe15ab1bf03952e94498ef3130e16f752da72782783696eb2cca4736d5"
} }
@@ -1,12 +1,12 @@
{ {
"db_name": "SQLite", "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": { "describe": {
"columns": [], "columns": [],
"parameters": { "parameters": {
"Right": 9 "Right": 10
}, },
"nullable": [] "nullable": []
}, },
"hash": "efd8ba41ea909b18dd520c57c1d464c5ae057b720cbbedcaec1513d43535632c" "hash": "6b5edf45a6799cd7f87c23a3c7f818ad110d58c601f694a619d9345ae9e8e11d"
} }
+9 -9
View File
@@ -30,27 +30,27 @@ base64 = "0.22.0"
boa_engine = { version = "0.18.0", features = ["annex-b"] } boa_engine = { version = "0.18.0", features = ["annex-b"] }
boa_runtime = { version = "0.18.0" } boa_runtime = { version = "0.18.0" }
chrono = { version = "0.4.31", features = ["serde"] } chrono = { version = "0.4.31", features = ["serde"] }
datetime = "0.5.2"
hex_color = "3.0.0"
http = "0.2.10" http = "0.2.10"
log = "0.4.21"
rand = "0.8.5" rand = "0.8.5"
regex = "1.10.2"
reqwest = { version = "0.11.23", features = ["multipart", "cookies", "gzip", "brotli", "deflate", "json"] } 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 = { version = "1.0.198", features = ["derive"] }
serde_json = { version = "1.0.116", features = ["raw_value"] } serde_json = { version = "1.0.116", features = ["raw_value"] }
sqlx = { version = "0.7.4", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time"] } 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 = { version = "2.0.0-beta", features = ["config-toml", "devtools", "protocol-asset"] }
tauri-plugin-clipboard-manager = "2.1.0-beta" 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-dialog = "2.0.0-beta"
tauri-plugin-fs = "2.0.0-beta"
tauri-plugin-log = { version = "2.0.0-beta", features = ["colored"] } 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-os = "2.0.0-beta"
tauri-plugin-shell = "2.0.0-beta"
tauri-plugin-updater = "2.0.0-beta" tauri-plugin-updater = "2.0.0-beta"
tauri-plugin-window-state = "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"] } 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" tokio-stream = "0.1.15"
regex = "1.10.2" uuid = "1.7.0"
hex_color = "3.0.0"
@@ -0,0 +1 @@
ALTER TABLE settings ADD COLUMN open_workspace_new_window BOOLEAN NULL DEFAULT NULL;
+7 -3
View File
@@ -59,6 +59,7 @@ pub struct Settings {
pub interface_scale: i64, pub interface_scale: i64,
pub editor_font_size: i64, pub editor_font_size: i64,
pub editor_soft_wrap: bool, pub editor_soft_wrap: bool,
pub open_workspace_new_window: Option<bool>,
} }
#[derive(sqlx::FromRow, Debug, Clone, Serialize, Deserialize, Default)] #[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 SELECT
id, model, created_at, updated_at, theme, appearance, id, model, created_at, updated_at, theme, appearance,
theme_dark, theme_light, update_channel, 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 FROM settings
WHERE id = 'default' WHERE id = 'default'
"#, "#,
@@ -928,8 +930,9 @@ pub async fn update_settings(
r#" r#"
UPDATE settings SET ( UPDATE settings SET (
theme, appearance, theme_dark, theme_light, update_channel, 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,
) = (?, ?, ?, ?, ?, ?, ?, ?, ?) WHERE id = 'default'; open_workspace_new_window
) = (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) WHERE id = 'default';
"#, "#,
settings.theme, settings.theme,
settings.appearance, settings.appearance,
@@ -940,6 +943,7 @@ pub async fn update_settings(
settings.interface_scale, settings.interface_scale,
settings.editor_font_size, settings.editor_font_size,
settings.editor_soft_wrap, settings.editor_soft_wrap,
settings.open_workspace_new_window,
) )
.execute(&db) .execute(&db)
.await?; .await?;
@@ -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>
);
}
@@ -50,6 +50,33 @@ export function SettingsGeneral() {
onClick={() => checkForUpdates.mutateAsync()} onClick={() => checkForUpdates.mutateAsync()}
/> />
</div> </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" /> <Separator className="my-4" />
<Heading size={2}> <Heading size={2}>
+14 -55
View File
@@ -1,13 +1,11 @@
import { invoke } from '@tauri-apps/api/core';
import classNames from 'classnames'; import classNames from 'classnames';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace'; import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useAppRoutes } from '../hooks/useAppRoutes';
import { useCommand } from '../hooks/useCommands'; import { useCommand } from '../hooks/useCommands';
import { useDeleteWorkspace } from '../hooks/useDeleteWorkspace'; import { useDeleteWorkspace } from '../hooks/useDeleteWorkspace';
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
import { usePrompt } from '../hooks/usePrompt'; import { usePrompt } from '../hooks/usePrompt';
import { getRecentEnvironments } from '../hooks/useRecentEnvironments'; import { useSettings } from '../hooks/useSettings';
import { getRecentRequests } from '../hooks/useRecentRequests';
import { useUpdateWorkspace } from '../hooks/useUpdateWorkspace'; import { useUpdateWorkspace } from '../hooks/useUpdateWorkspace';
import { useWorkspaces } from '../hooks/useWorkspaces'; import { useWorkspaces } from '../hooks/useWorkspaces';
import type { ButtonProps } from './core/Button'; import type { ButtonProps } from './core/Button';
@@ -16,8 +14,8 @@ import type { DropdownItem } from './core/Dropdown';
import { Dropdown } from './core/Dropdown'; import { Dropdown } from './core/Dropdown';
import { Icon } from './core/Icon'; import { Icon } from './core/Icon';
import { InlineCode } from './core/InlineCode'; import { InlineCode } from './core/InlineCode';
import { HStack } from './core/Stacks';
import { useDialog } from './DialogContext'; import { useDialog } from './DialogContext';
import { OpenWorkspaceDialog } from './OpenWorkspaceDialog';
type Props = Pick<ButtonProps, 'className' | 'justify' | 'forDropdown' | 'leftSlot'>; type Props = Pick<ButtonProps, 'className' | 'justify' | 'forDropdown' | 'leftSlot'>;
@@ -33,7 +31,9 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
const createWorkspace = useCommand('workspace.create'); const createWorkspace = useCommand('workspace.create');
const dialog = useDialog(); const dialog = useDialog();
const prompt = usePrompt(); const prompt = usePrompt();
const routes = useAppRoutes(); const settings = useSettings();
const openWorkspace = useOpenWorkspace();
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
const items: DropdownItem[] = useMemo(() => { const items: DropdownItem[] = useMemo(() => {
const workspaceItems: DropdownItem[] = workspaces.map((w) => ({ const workspaceItems: DropdownItem[] = workspaces.map((w) => ({
@@ -41,58 +41,16 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
label: w.name, label: w.name,
leftSlot: w.id === activeWorkspaceId ? <Icon icon="check" /> : <Icon icon="empty" />, leftSlot: w.id === activeWorkspaceId ? <Icon icon="check" /> : <Icon icon="empty" />,
onSelect: async () => { onSelect: async () => {
if (typeof openWorkspaceNewWindow === 'boolean') {
openWorkspace.mutate({ workspace: w, inNewWindow: openWorkspaceNewWindow });
return;
}
dialog.show({ dialog.show({
id: 'open-workspace', id: 'open-workspace',
size: 'sm', size: 'sm',
title: 'Open Workspace', title: 'Open Workspace',
description: ( render: ({ hide }) => <OpenWorkspaceDialog workspace={w} hide={hide} />,
<>
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>
);
},
}); });
}, },
})); }));
@@ -152,8 +110,9 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
createWorkspace, createWorkspace,
deleteWorkspace.mutate, deleteWorkspace.mutate,
dialog, dialog,
openWorkspace,
prompt, prompt,
routes, openWorkspaceNewWindow,
updateWorkspace, updateWorkspace,
workspaces, workspaces,
]); ]);
+1 -1
View File
@@ -67,7 +67,7 @@ export function Dialog({
'rounded-lg', 'rounded-lg',
'border border-background-highlight-secondary shadow-lg shadow-[rgba(0,0,0,0.1)]', 'border border-background-highlight-secondary shadow-lg shadow-[rgba(0,0,0,0.1)]',
'max-w-[calc(100vw-5rem)] max-h-[calc(100vh-6rem)]', '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 === 'md' && 'w-[45rem] max-h-[80vh]',
size === 'lg' && 'w-[65rem] max-h-[80vh]', size === 'lg' && 'w-[65rem] max-h-[80vh]',
size === 'full' && 'w-[100vw] h-[100vh]', size === 'full' && 'w-[100vw] h-[100vh]',
+50
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 });
}
}
},
});
}
+1
View File
@@ -41,6 +41,7 @@ export interface Settings extends BaseModel {
interfaceScale: number; interfaceScale: number;
editorFontSize: number; editorFontSize: number;
editorSoftWrap: boolean; editorSoftWrap: boolean;
openWorkspaceNewWindow: boolean | null;
} }
export interface Workspace extends BaseModel { export interface Workspace extends BaseModel {