mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-03-17 23:13:51 +01:00
Add the ability to duplicate folders (#144)
This commit is contained in:
@@ -55,9 +55,9 @@ use yaak_models::queries::{
|
||||
delete_all_http_responses_for_request, delete_all_http_responses_for_workspace,
|
||||
delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection,
|
||||
delete_grpc_request, delete_http_request, delete_http_response, delete_plugin,
|
||||
delete_workspace, duplicate_grpc_request, duplicate_http_request, generate_id,
|
||||
generate_model_id, get_cookie_jar, get_environment, get_folder, get_grpc_connection,
|
||||
get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
|
||||
delete_workspace, duplicate_folder, duplicate_grpc_request, duplicate_http_request,
|
||||
generate_id, generate_model_id, get_cookie_jar, get_environment, get_folder,
|
||||
get_grpc_connection, get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
|
||||
get_or_create_settings, get_plugin, get_workspace, list_cookie_jars, list_environments,
|
||||
list_folders, list_grpc_connections_for_workspace, list_grpc_events, list_grpc_requests,
|
||||
list_http_requests, list_http_responses_for_request, list_http_responses_for_workspace,
|
||||
@@ -1242,6 +1242,15 @@ async fn cmd_duplicate_grpc_request(id: &str, w: WebviewWindow) -> Result<GrpcRe
|
||||
duplicate_grpc_request(&w, id).await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_duplicate_folder<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
id: &str,
|
||||
) -> Result<(), String> {
|
||||
let folder = get_folder(&window, id).await.map_err(|e| e.to_string())?;
|
||||
duplicate_folder(&window, &folder).await.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_create_http_request(
|
||||
request: HttpRequest,
|
||||
@@ -1738,6 +1747,7 @@ pub fn run() {
|
||||
cmd_delete_send_history,
|
||||
cmd_delete_workspace,
|
||||
cmd_dismiss_notification,
|
||||
cmd_duplicate_folder,
|
||||
cmd_duplicate_grpc_request,
|
||||
cmd_duplicate_http_request,
|
||||
cmd_export_data,
|
||||
|
||||
@@ -306,6 +306,7 @@ pub async fn duplicate_grpc_request<R: Runtime>(
|
||||
return Err(ModelNotFound(id.to_string()));
|
||||
}
|
||||
};
|
||||
request.sort_priority = request.sort_priority + 0.001;
|
||||
request.id = "".to_string();
|
||||
upsert_grpc_request(window, request).await
|
||||
}
|
||||
@@ -1108,9 +1109,79 @@ pub async fn duplicate_http_request<R: Runtime>(
|
||||
Some(r) => r,
|
||||
};
|
||||
request.id = "".to_string();
|
||||
request.sort_priority = request.sort_priority + 0.001;
|
||||
upsert_http_request(window, request).await
|
||||
}
|
||||
|
||||
pub async fn duplicate_folder<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
src_folder: &Folder,
|
||||
) -> Result<()> {
|
||||
let workspace_id = src_folder.workspace_id.as_str();
|
||||
|
||||
let http_requests = list_http_requests(window, workspace_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|m| m.folder_id.as_ref() == Some(&src_folder.id));
|
||||
|
||||
let grpc_requests = list_grpc_requests(window, workspace_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|m| m.folder_id.as_ref() == Some(&src_folder.id));
|
||||
|
||||
let folders = list_folders(window, workspace_id)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|m| m.folder_id.as_ref() == Some(&src_folder.id));
|
||||
|
||||
let new_folder = upsert_folder(
|
||||
window,
|
||||
Folder {
|
||||
id: "".into(),
|
||||
sort_priority: src_folder.sort_priority + 0.001,
|
||||
..src_folder.clone()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
for m in http_requests {
|
||||
upsert_http_request(
|
||||
window,
|
||||
HttpRequest {
|
||||
id: "".into(),
|
||||
folder_id: Some(new_folder.id.clone()),
|
||||
sort_priority: m.sort_priority + 0.001,
|
||||
..m
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
for m in grpc_requests {
|
||||
upsert_grpc_request(
|
||||
window,
|
||||
GrpcRequest {
|
||||
id: "".into(),
|
||||
folder_id: Some(new_folder.id.clone()),
|
||||
sort_priority: m.sort_priority + 0.001,
|
||||
..m
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
for m in folders {
|
||||
// Recurse down
|
||||
Box::pin(duplicate_folder(
|
||||
window,
|
||||
&Folder {
|
||||
folder_id: Some(new_folder.id.clone()),
|
||||
..m
|
||||
},
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn upsert_http_request<R: Runtime>(
|
||||
window: &WebviewWindow<R>,
|
||||
r: HttpRequest,
|
||||
|
||||
@@ -64,8 +64,7 @@ export function ExportDataDialog({
|
||||
<tr>
|
||||
<th className="w-6 min-w-0 py-2 text-left pl-1">
|
||||
<Checkbox
|
||||
checked={allSelected}
|
||||
indeterminate={!allSelected && !noneSelected}
|
||||
checked={!allSelected && !noneSelected ? 'indeterminate' : allSelected}
|
||||
hideLabel
|
||||
title="All workspaces"
|
||||
onChange={handleToggleAll}
|
||||
|
||||
@@ -138,7 +138,7 @@ export function GrpcConnectionSetupPane({
|
||||
value: TAB_DESCRIPTION,
|
||||
label: (
|
||||
<div className="flex items-center">
|
||||
Docs
|
||||
Info
|
||||
{activeRequest.description && <CountBadge count={true} />}
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -129,7 +129,7 @@ export const RequestPane = memo(function RequestPane({
|
||||
value: TAB_DESCRIPTION,
|
||||
label: (
|
||||
<div className="flex items-center">
|
||||
Docs
|
||||
Info
|
||||
{activeRequest.description && <CountBadge count={true} />}
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -22,6 +22,7 @@ import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||
import { useCreateDropdownItems } from '../hooks/useCreateDropdownItems';
|
||||
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||
import { useDuplicateFolder } from '../hooks/useDuplicateFolder';
|
||||
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
||||
import { useDuplicateHttpRequest } from '../hooks/useDuplicateHttpRequest';
|
||||
import { useFolders } from '../hooks/useFolders';
|
||||
@@ -699,6 +700,7 @@ function SidebarItem({
|
||||
const deleteFolder = useDeleteFolder(itemId);
|
||||
const deleteRequest = useDeleteRequest(itemId);
|
||||
const renameRequest = useRenameRequest(itemId);
|
||||
const duplicateFolder = useDuplicateFolder(itemId);
|
||||
const duplicateHttpRequest = useDuplicateHttpRequest({ id: itemId, navigateAfter: true });
|
||||
const duplicateGrpcRequest = useDuplicateGrpcRequest({ id: itemId, navigateAfter: true });
|
||||
const sendRequest = useSendAnyHttpRequest();
|
||||
@@ -802,6 +804,12 @@ function SidebarItem({
|
||||
render: () => <FolderSettingsDialog folderId={itemId} />,
|
||||
}),
|
||||
},
|
||||
{
|
||||
key: 'duplicateFolder',
|
||||
label: 'Duplicate',
|
||||
leftSlot: <Icon icon="copy" />,
|
||||
onSelect: () => duplicateFolder.mutate(),
|
||||
},
|
||||
{
|
||||
key: 'delete-folder',
|
||||
label: 'Delete',
|
||||
@@ -877,7 +885,7 @@ function SidebarItem({
|
||||
createDropdownItems,
|
||||
deleteFolder,
|
||||
deleteRequest,
|
||||
dialog,
|
||||
duplicateFolder,
|
||||
duplicateGrpcRequest,
|
||||
duplicateHttpRequest,
|
||||
httpRequestActions,
|
||||
|
||||
11
src-web/hooks/useDuplicateFolder.ts
Normal file
11
src-web/hooks/useDuplicateFolder.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { invokeCmd } from '../lib/tauri';
|
||||
|
||||
export function useDuplicateFolder(id: string) {
|
||||
return useMutation<void, string>({
|
||||
mutationKey: ['duplicate_folder', id],
|
||||
mutationFn: () => invokeCmd('cmd_duplicate_folder', { id }),
|
||||
onSettled: () => trackEvent('folder', 'duplicate'),
|
||||
});
|
||||
}
|
||||
@@ -24,6 +24,7 @@ type TauriCmd =
|
||||
| 'cmd_delete_http_response'
|
||||
| 'cmd_delete_workspace'
|
||||
| 'cmd_dismiss_notification'
|
||||
| 'cmd_duplicate_folder'
|
||||
| 'cmd_duplicate_grpc_request'
|
||||
| 'cmd_duplicate_http_request'
|
||||
| 'cmd_export_data'
|
||||
|
||||
Reference in New Issue
Block a user