mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-23 01:22:12 +03:00
Added unstaged changes event
This commit is contained in:
parent
7199105561
commit
d2d3afbf2b
48
apps/desktop/src/lib/uncommitedFiles/watcher.ts
Normal file
48
apps/desktop/src/lib/uncommitedFiles/watcher.ts
Normal 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));
|
||||
});
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
};
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)?)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
},
|
||||
}
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user