mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-07-06 21:05:24 +02:00
Add the ability to duplicate folders (#144)
This commit is contained in:
+13
-3
@@ -55,9 +55,9 @@ use yaak_models::queries::{
|
|||||||
delete_all_http_responses_for_request, delete_all_http_responses_for_workspace,
|
delete_all_http_responses_for_request, delete_all_http_responses_for_workspace,
|
||||||
delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection,
|
delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection,
|
||||||
delete_grpc_request, delete_http_request, delete_http_response, delete_plugin,
|
delete_grpc_request, delete_http_request, delete_http_response, delete_plugin,
|
||||||
delete_workspace, duplicate_grpc_request, duplicate_http_request, generate_id,
|
delete_workspace, duplicate_folder, duplicate_grpc_request, duplicate_http_request,
|
||||||
generate_model_id, get_cookie_jar, get_environment, get_folder, get_grpc_connection,
|
generate_id, generate_model_id, get_cookie_jar, get_environment, get_folder,
|
||||||
get_grpc_request, get_http_request, get_http_response, get_key_value_raw,
|
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,
|
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_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,
|
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())
|
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]
|
#[tauri::command]
|
||||||
async fn cmd_create_http_request(
|
async fn cmd_create_http_request(
|
||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
@@ -1738,6 +1747,7 @@ pub fn run() {
|
|||||||
cmd_delete_send_history,
|
cmd_delete_send_history,
|
||||||
cmd_delete_workspace,
|
cmd_delete_workspace,
|
||||||
cmd_dismiss_notification,
|
cmd_dismiss_notification,
|
||||||
|
cmd_duplicate_folder,
|
||||||
cmd_duplicate_grpc_request,
|
cmd_duplicate_grpc_request,
|
||||||
cmd_duplicate_http_request,
|
cmd_duplicate_http_request,
|
||||||
cmd_export_data,
|
cmd_export_data,
|
||||||
|
|||||||
@@ -306,6 +306,7 @@ pub async fn duplicate_grpc_request<R: Runtime>(
|
|||||||
return Err(ModelNotFound(id.to_string()));
|
return Err(ModelNotFound(id.to_string()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
request.sort_priority = request.sort_priority + 0.001;
|
||||||
request.id = "".to_string();
|
request.id = "".to_string();
|
||||||
upsert_grpc_request(window, request).await
|
upsert_grpc_request(window, request).await
|
||||||
}
|
}
|
||||||
@@ -1108,9 +1109,79 @@ pub async fn duplicate_http_request<R: Runtime>(
|
|||||||
Some(r) => r,
|
Some(r) => r,
|
||||||
};
|
};
|
||||||
request.id = "".to_string();
|
request.id = "".to_string();
|
||||||
|
request.sort_priority = request.sort_priority + 0.001;
|
||||||
upsert_http_request(window, request).await
|
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>(
|
pub async fn upsert_http_request<R: Runtime>(
|
||||||
window: &WebviewWindow<R>,
|
window: &WebviewWindow<R>,
|
||||||
r: HttpRequest,
|
r: HttpRequest,
|
||||||
|
|||||||
@@ -64,8 +64,7 @@ export function ExportDataDialog({
|
|||||||
<tr>
|
<tr>
|
||||||
<th className="w-6 min-w-0 py-2 text-left pl-1">
|
<th className="w-6 min-w-0 py-2 text-left pl-1">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={allSelected}
|
checked={!allSelected && !noneSelected ? 'indeterminate' : allSelected}
|
||||||
indeterminate={!allSelected && !noneSelected}
|
|
||||||
hideLabel
|
hideLabel
|
||||||
title="All workspaces"
|
title="All workspaces"
|
||||||
onChange={handleToggleAll}
|
onChange={handleToggleAll}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ export function GrpcConnectionSetupPane({
|
|||||||
value: TAB_DESCRIPTION,
|
value: TAB_DESCRIPTION,
|
||||||
label: (
|
label: (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
Docs
|
Info
|
||||||
{activeRequest.description && <CountBadge count={true} />}
|
{activeRequest.description && <CountBadge count={true} />}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ export const RequestPane = memo(function RequestPane({
|
|||||||
value: TAB_DESCRIPTION,
|
value: TAB_DESCRIPTION,
|
||||||
label: (
|
label: (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
Docs
|
Info
|
||||||
{activeRequest.description && <CountBadge count={true} />}
|
{activeRequest.description && <CountBadge count={true} />}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import { useAppRoutes } from '../hooks/useAppRoutes';
|
|||||||
import { useCreateDropdownItems } from '../hooks/useCreateDropdownItems';
|
import { useCreateDropdownItems } from '../hooks/useCreateDropdownItems';
|
||||||
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
||||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||||
|
import { useDuplicateFolder } from '../hooks/useDuplicateFolder';
|
||||||
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
||||||
import { useDuplicateHttpRequest } from '../hooks/useDuplicateHttpRequest';
|
import { useDuplicateHttpRequest } from '../hooks/useDuplicateHttpRequest';
|
||||||
import { useFolders } from '../hooks/useFolders';
|
import { useFolders } from '../hooks/useFolders';
|
||||||
@@ -699,6 +700,7 @@ function SidebarItem({
|
|||||||
const deleteFolder = useDeleteFolder(itemId);
|
const deleteFolder = useDeleteFolder(itemId);
|
||||||
const deleteRequest = useDeleteRequest(itemId);
|
const deleteRequest = useDeleteRequest(itemId);
|
||||||
const renameRequest = useRenameRequest(itemId);
|
const renameRequest = useRenameRequest(itemId);
|
||||||
|
const duplicateFolder = useDuplicateFolder(itemId);
|
||||||
const duplicateHttpRequest = useDuplicateHttpRequest({ id: itemId, navigateAfter: true });
|
const duplicateHttpRequest = useDuplicateHttpRequest({ id: itemId, navigateAfter: true });
|
||||||
const duplicateGrpcRequest = useDuplicateGrpcRequest({ id: itemId, navigateAfter: true });
|
const duplicateGrpcRequest = useDuplicateGrpcRequest({ id: itemId, navigateAfter: true });
|
||||||
const sendRequest = useSendAnyHttpRequest();
|
const sendRequest = useSendAnyHttpRequest();
|
||||||
@@ -802,6 +804,12 @@ function SidebarItem({
|
|||||||
render: () => <FolderSettingsDialog folderId={itemId} />,
|
render: () => <FolderSettingsDialog folderId={itemId} />,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'duplicateFolder',
|
||||||
|
label: 'Duplicate',
|
||||||
|
leftSlot: <Icon icon="copy" />,
|
||||||
|
onSelect: () => duplicateFolder.mutate(),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'delete-folder',
|
key: 'delete-folder',
|
||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
@@ -877,7 +885,7 @@ function SidebarItem({
|
|||||||
createDropdownItems,
|
createDropdownItems,
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
deleteRequest,
|
deleteRequest,
|
||||||
dialog,
|
duplicateFolder,
|
||||||
duplicateGrpcRequest,
|
duplicateGrpcRequest,
|
||||||
duplicateHttpRequest,
|
duplicateHttpRequest,
|
||||||
httpRequestActions,
|
httpRequestActions,
|
||||||
|
|||||||
@@ -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_http_response'
|
||||||
| 'cmd_delete_workspace'
|
| 'cmd_delete_workspace'
|
||||||
| 'cmd_dismiss_notification'
|
| 'cmd_dismiss_notification'
|
||||||
|
| 'cmd_duplicate_folder'
|
||||||
| 'cmd_duplicate_grpc_request'
|
| 'cmd_duplicate_grpc_request'
|
||||||
| 'cmd_duplicate_http_request'
|
| 'cmd_duplicate_http_request'
|
||||||
| 'cmd_export_data'
|
| 'cmd_export_data'
|
||||||
|
|||||||
Reference in New Issue
Block a user