Compare commits

...

2 Commits

Author SHA1 Message Date
Gregory Schier
6a63cc26b9 Fix commit-and-push loading state 2025-02-19 10:35:41 -08:00
Gregory Schier
8ed0fd55c3 Remove environments from synced folder, and stop syncing 2025-02-19 10:35:31 -08:00
5 changed files with 43 additions and 13 deletions

View File

@@ -51,6 +51,14 @@ export function useGit(dir: string) {
mutationFn: (args) => invoke('plugin:yaak-git|commit', { dir, ...args }),
onSuccess,
}),
commitAndPush: useMutation<PushResult, string, { message: string }>({
mutationKey: ['git', 'commitpush', dir],
mutationFn: async (args) => {
await invoke('plugin:yaak-git|commit', { dir, ...args });
return invoke('plugin:yaak-git|push', { dir });
},
onSuccess,
}),
fetchAll: useMutation<string, string, void>({
mutationKey: ['git', 'checkout', dir],
mutationFn: () => invoke('plugin:yaak-git|fetch_all', { dir }),

View File

@@ -1,7 +1,7 @@
use crate::error::Result;
use crate::models::SyncModel;
use chrono::Utc;
use log::{debug, warn};
use log::{debug, info, warn};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
@@ -164,6 +164,13 @@ pub(crate) async fn get_fs_candidates(dir: &Path) -> Result<Vec<FsCandidate>> {
let path = dir_entry.path();
let (model, checksum) = match SyncModel::from_file(&path) {
// TODO: Remove this once we have logic to handle environments. This it to clean
// any existing ones from the sync dir that resulted from the 2025.1 betas.
Ok(Some((SyncModel::Environment(e), _))) => {
fs::remove_file(path).await?;
info!("Cleaned up synced environment {}", e.id);
continue;
}
Ok(Some(m)) => m,
Ok(None) => continue,
Err(e) => {
@@ -205,9 +212,17 @@ pub(crate) fn compute_sync_ops(
let op = match (db_map.get(k), fs_map.get(k)) {
(None, None) => return None, // Can never happen
(None, Some(fs)) => SyncOp::DbCreate { fs: fs.to_owned() },
(Some(DbCandidate::Unmodified(model, sync_state)), None) => SyncOp::DbDelete {
model: model.to_owned(),
state: sync_state.to_owned(),
(Some(DbCandidate::Unmodified(model, sync_state)), None) => {
// TODO: Remove this once we have logic to handle environments. This it to
// ignore the cleaning we did above of any environments that were written
// to disk in the 2025.1 betas.
if let SyncModel::Environment(_) = model {
return None;
}
SyncOp::DbDelete {
model: model.to_owned(),
state: sync_state.to_owned(),
}
},
(Some(DbCandidate::Modified(model, sync_state)), None) => SyncOp::FsUpdate {
model: model.to_owned(),
@@ -318,7 +333,7 @@ pub(crate) async fn apply_sync_ops<R: Runtime>(
);
let mut sync_state_ops = Vec::new();
let mut workspaces_to_upsert = Vec::new();
let mut environments_to_upsert = Vec::new();
let environments_to_upsert = Vec::new();
let mut folders_to_upsert = Vec::new();
let mut http_requests_to_upsert = Vec::new();
let mut grpc_requests_to_upsert = Vec::new();
@@ -380,11 +395,13 @@ pub(crate) async fn apply_sync_ops<R: Runtime>(
// batch upsert to make foreign keys happy
match fs.model {
SyncModel::Workspace(m) => workspaces_to_upsert.push(m),
SyncModel::Environment(m) => environments_to_upsert.push(m),
SyncModel::Folder(m) => folders_to_upsert.push(m),
SyncModel::HttpRequest(m) => http_requests_to_upsert.push(m),
SyncModel::GrpcRequest(m) => grpc_requests_to_upsert.push(m),
SyncModel::WebsocketRequest(m) => websocket_requests_to_upsert.push(m),
// TODO: Handle environments in sync
SyncModel::Environment(_) => {}
};
SyncStateOp::Create {
model_id,
@@ -397,11 +414,13 @@ pub(crate) async fn apply_sync_ops<R: Runtime>(
// batch upsert to make foreign keys happy
match fs.model {
SyncModel::Workspace(m) => workspaces_to_upsert.push(m),
SyncModel::Environment(m) => environments_to_upsert.push(m),
SyncModel::Folder(m) => folders_to_upsert.push(m),
SyncModel::HttpRequest(m) => http_requests_to_upsert.push(m),
SyncModel::GrpcRequest(m) => grpc_requests_to_upsert.push(m),
SyncModel::WebsocketRequest(m) => websocket_requests_to_upsert.push(m),
// TODO: Handle environments in sync
SyncModel::Environment(_) => {}
}
SyncStateOp::Update {
state: state.to_owned(),

View File

@@ -39,7 +39,7 @@ interface TreeNode {
}
export function GitCommitDialog({ syncDir, onDone, workspace }: Props) {
const [{ status }, { commit, add, unstage, push }] = useGit(syncDir);
const [{ status }, { commit, commitAndPush, add, unstage, push }] = useGit(syncDir);
const [message, setMessage] = useState<string>('');
const handleCreateCommit = async () => {
@@ -53,8 +53,7 @@ export function GitCommitDialog({ syncDir, onDone, workspace }: Props) {
const handleCreateCommitAndPush = async () => {
try {
await commit.mutateAsync({ message });
await push.mutateAsync();
await commitAndPush.mutateAsync({ message });
showToast({ id: 'git-push-success', message: 'Pushed changes', color: 'success' });
onDone();
} catch (err) {
@@ -66,10 +65,13 @@ export function GitCommitDialog({ syncDir, onDone, workspace }: Props) {
const allEntries = [];
const yaakEntries = [];
const externalEntries = [];
for (const entry of status.data?.entries ?? []) {
allEntries.push(entry);
if (entry.next == null && entry.prev == null) {
externalEntries.push(entry);
} else if (entry.next?.model === 'environment' || entry.prev?.model === 'environment') {
externalEntries.push(entry);
} else {
yaakEntries.push(entry);
}
@@ -184,7 +186,7 @@ export function GitCommitDialog({ syncDir, onDone, workspace }: Props) {
size="sm"
onClick={handleCreateCommit}
disabled={!hasAddedAnything}
isLoading={push.isPending || commit.isPending}
isLoading={push.isPending || commitAndPush.isPending || commit.isPending}
>
Commit
</Button>
@@ -193,7 +195,7 @@ export function GitCommitDialog({ syncDir, onDone, workspace }: Props) {
size="sm"
disabled={!hasAddedAnything}
onClick={handleCreateCommitAndPush}
isLoading={push.isPending || commit.isPending}
isLoading={push.isPending || commitAndPush.isPending || commit.isPending}
>
Commit and Push
</Button>

View File

@@ -25,6 +25,7 @@ export function SyncToFilesystemSetting({
<VStack className="my-2" space={3}>
<Banner color="info">
Sync workspace data to folder as plain text files, ideal for backup and Git collaboration.
Environments are excluded in order to keep your secrets private.
</Banner>
{error && <div className="text-danger">{error}</div>}

View File

@@ -69,7 +69,7 @@ function isModelRelevant(m: AnyModel) {
if (
m.model !== 'workspace' &&
m.model !== 'folder' &&
m.model !== 'environment' &&
// m.model !== 'environment' && // Not synced anymore
m.model !== 'http_request' &&
m.model !== 'grpc_request' &&
m.model !== 'websocket_request'