Added unstaged changes event

This commit is contained in:
Caleb Owens 2024-08-26 15:17:50 +02:00
parent 7199105561
commit d2d3afbf2b
No known key found for this signature in database
10 changed files with 134 additions and 9 deletions

View File

@ -0,0 +1,48 @@
import { listen } from '$lib/backend/ipc';
import { parseRemoteFiles } from '$lib/vbranches/remoteCommits';
import { RemoteFile } from '$lib/vbranches/types';
import { invoke } from '@tauri-apps/api/tauri';
import { plainToInstance } from 'class-transformer';
import { readable, type Readable } from 'svelte/store';
import type { Project } from '$lib/backend/projects';
import type { ContentSection, HunkSection } from '$lib/utils/fileSections';
type ParsedFiles = [RemoteFile, (ContentSection | HunkSection)[]][];
export class UncommitedFilesWatcher {
uncommitedFiles: Readable<ParsedFiles>;
constructor(private project: Project) {
this.uncommitedFiles = readable([] as ParsedFiles, (set) => {
this.getUncommitedFiles().then((files) => {
set(files);
});
const unsubscribe = this.listen(set);
return unsubscribe;
});
}
private async getUncommitedFiles() {
const uncommitedFiles = await invoke<unknown[]>('get_uncommited_files', {
id: this.project.id
});
const orderedFiles = plainToInstance(RemoteFile, uncommitedFiles).sort((a, b) =>
a.path?.localeCompare(b.path)
);
return parseRemoteFiles(orderedFiles);
}
private listen(callback: (files: ParsedFiles) => void) {
return listen<unknown[]>(`project://${this.project.id}/uncommited-files`, (event) => {
const orderedFiles = plainToInstance(RemoteFile, event.payload).sort((a, b) =>
a.path?.localeCompare(b.path)
);
callback(parseRemoteFiles(orderedFiles));
});
}
}

View File

@ -26,6 +26,7 @@
import Navigation from '$lib/navigation/Navigation.svelte';
import { persisted } from '$lib/persisted/persisted';
import { RemoteBranchService } from '$lib/stores/remoteBranches';
import { UncommitedFilesWatcher } from '$lib/uncommitedFiles/watcher';
import { parseRemoteUrl } from '$lib/url/gitUrl';
import { debounce } from '$lib/utils/debounce';
import { BranchController } from '$lib/vbranches/branchController';
@ -73,6 +74,7 @@
setContext(RemoteBranchService, data.remoteBranchService);
setContext(BranchListingService, data.branchListingService);
setContext(ModeService, data.modeService);
setContext(UncommitedFilesWatcher, data.uncommitedFileWatcher);
});
let intervalId: any;

View File

@ -9,6 +9,7 @@ import { HistoryService } from '$lib/history/history';
import { ProjectMetrics } from '$lib/metrics/projectMetrics';
import { ModeService } from '$lib/modes/service';
import { RemoteBranchService } from '$lib/stores/remoteBranches';
import { UncommitedFilesWatcher } from '$lib/uncommitedFiles/watcher';
import { BranchController } from '$lib/vbranches/branchController';
import { VirtualBranchService } from '$lib/vbranches/virtualBranch';
import { error } from '@sveltejs/kit';
@ -76,6 +77,8 @@ export const load: LayoutLoad = async ({ params, parent }) => {
const commitDragActionsFactory = new CommitDragActionsFactory(branchController, project);
const reorderDropzoneManagerFactory = new ReorderDropzoneManagerFactory(branchController);
const uncommitedFileWatcher = new UncommitedFilesWatcher(project);
return {
authService,
baseBranchService,
@ -93,6 +96,7 @@ export const load: LayoutLoad = async ({ params, parent }) => {
branchDragActionsFactory,
commitDragActionsFactory,
reorderDropzoneManagerFactory,
branchListingService
branchListingService,
uncommitedFileWatcher
};
};

View File

@ -17,6 +17,7 @@ use crate::{
get_base_branch_data, set_base_branch, set_target_push_remote, update_base_branch,
BaseBranch,
},
branch::get_uncommited_files,
branch_manager::BranchManagerExt,
file::RemoteBranchFile,
remote::{get_branch_data, list_remote_branches, RemoteBranch, RemoteBranchData},
@ -539,6 +540,14 @@ impl VirtualBranchActions {
.create_virtual_branch_from_branch(branch, remote, guard.write_permission())
.map_err(Into::into)
}
pub fn get_uncommited_files(&self, project: &Project) -> Result<Vec<RemoteBranchFile>> {
let context = CommandContext::open(project)?;
let guard = project.exclusive_worktree_access();
get_uncommited_files(&context, guard.read_permission())
}
}
fn open_with_verify(project: &Project) -> Result<CommandContext> {

View File

@ -1,4 +1,4 @@
use crate::VirtualBranchesExt;
use crate::{RemoteBranchFile, VirtualBranchesExt};
use anyhow::{bail, Context, Result};
use bstr::{BStr, ByteSlice};
use core::fmt;
@ -6,6 +6,7 @@ use gitbutler_branch::{
Branch as GitButlerBranch, BranchId, BranchIdentity, ReferenceExtGix, Target,
};
use gitbutler_command_context::{CommandContext, GixRepositoryExt};
use gitbutler_project::access::WorktreeReadPermission;
use gitbutler_reference::normalize_branch_name;
use gitbutler_serde::BStringForFrontend;
use gix::object::tree::diff::Action;
@ -21,6 +22,33 @@ use std::{
vec,
};
pub(crate) fn get_uncommited_files(
context: &CommandContext,
_permission: &WorktreeReadPermission,
) -> Result<Vec<RemoteBranchFile>> {
let repository = context.repository();
let head_commit = repository
.head()
.context("Failed to get head")?
.peel_to_commit()
.context("Failed to get head commit")?;
let files = gitbutler_diff::workdir(repository, &head_commit.id())
.context("Failed to list uncommited files")?
.into_iter()
.map(|(path, file)| {
let binary = file.hunks.iter().any(|h| h.binary);
RemoteBranchFile {
path,
hunks: file.hunks,
binary,
}
})
.collect();
Ok(files)
}
/// Returns a list of branches associated with this project.
pub fn list_branches(
ctx: &CommandContext,

View File

@ -148,6 +148,7 @@ fn main() {
repo::commands::git_set_local_config,
repo::commands::check_signing_settings,
repo::commands::git_clone_repository,
repo::commands::get_uncommited_files,
virtual_branches::commands::list_virtual_branches,
virtual_branches::commands::create_virtual_branch,
virtual_branches::commands::delete_local_branch,

View File

@ -1,5 +1,6 @@
pub mod commands {
use anyhow::{Context, Result};
use gitbutler_branch_actions::{RemoteBranchFile, VirtualBranchActions};
use gitbutler_project as projects;
use gitbutler_project::ProjectId;
use gitbutler_repo::RepoCommands;
@ -60,4 +61,14 @@ pub mod commands {
.context("Failed to checkout main worktree")?;
Ok(())
}
#[tauri::command(async)]
pub fn get_uncommited_files(
projects: State<'_, projects::Controller>,
id: ProjectId,
) -> Result<Vec<RemoteBranchFile>, Error> {
let project = projects.get(id)?;
Ok(VirtualBranchActions.get_uncommited_files(&project)?)
}
}

View File

@ -52,6 +52,11 @@ pub(super) mod state {
payload: serde_json::json!(virtual_branches),
project_id,
},
Change::UncommitedFiles { project_id, files } => ChangeForFrontend {
name: format!("project://{}/uncommited-files", project_id),
payload: serde_json::json!(files),
project_id,
},
}
}
}

View File

@ -1,6 +1,6 @@
use std::{fmt::Display, path::PathBuf};
use gitbutler_branch_actions::VirtualBranches;
use gitbutler_branch_actions::{RemoteBranchFile, VirtualBranches};
use gitbutler_operating_modes::OperatingMode;
use gitbutler_project::ProjectId;
@ -101,4 +101,8 @@ pub enum Change {
project_id: ProjectId,
virtual_branches: VirtualBranches,
},
UncommitedFiles {
project_id: ProjectId,
files: Vec<RemoteBranchFile>,
},
}

View File

@ -11,8 +11,8 @@ use gitbutler_oplog::{
entry::{OperationKind, SnapshotDetails},
OplogExt,
};
use gitbutler_project as projects;
use gitbutler_project::ProjectId;
use gitbutler_project::{self as projects, Project};
use gitbutler_reference::{LocalRefname, Refname};
use gitbutler_sync::cloud::{push_oplog, push_repo};
use gitbutler_user as users;
@ -125,16 +125,29 @@ impl Handler {
#[instrument(skip(self, paths, project_id), fields(paths = paths.len()))]
fn recalculate_everything(&self, paths: Vec<PathBuf>, project_id: ProjectId) -> Result<()> {
let ctx = self.open_command_context(project_id)?;
// Skip if we're not on the open workspace mode
if !in_open_workspace_mode(&ctx) {
return Ok(());
}
self.emit_uncommited_files(ctx.project());
if in_open_workspace_mode(&ctx) {
self.maybe_create_snapshot(project_id).ok();
self.calculate_virtual_branches(project_id)?;
}
Ok(())
}
/// Try to emit uncommited files. Swollow errors if they arrise.
fn emit_uncommited_files(&self, project: &Project) {
let Ok(files) = VirtualBranchActions.get_uncommited_files(project) else {
return;
};
let _ = self.emit_app_event(Change::UncommitedFiles {
project_id: project.id,
files,
});
}
fn maybe_create_snapshot(&self, project_id: ProjectId) -> anyhow::Result<()> {
let project = self
.projects