specify order on create request

This commit is contained in:
Nikita Galaiko 2023-07-07 09:33:51 +02:00
parent 57f5f7dee0
commit 32fcc9ea43
11 changed files with 203 additions and 101 deletions

View File

@ -7,12 +7,7 @@ use tokio_util::sync::CancellationToken;
use crate::{ use crate::{
bookmarks, database, deltas, events, files, gb_repository, bookmarks, database, deltas, events, files, gb_repository,
project_repository::{self, activity}, project_repository::{self, activity},
projects, pty, reader, search, sessions, storage, users, projects, pty, search, sessions, storage, users, virtual_branches, watcher,
virtual_branches::{
self,
branch::{BranchUpdateRequest, Ownership},
},
watcher,
}; };
#[derive(Clone)] #[derive(Clone)]
@ -353,8 +348,7 @@ impl App {
pub async fn create_virtual_branch( pub async fn create_virtual_branch(
&self, &self,
project_id: &str, project_id: &str,
name: &str, create: &virtual_branches::branch::BranchCreateRequest,
ownership: &Ownership,
) -> Result<()> { ) -> Result<()> {
let gb_repository = self.gb_repository(project_id)?; let gb_repository = self.gb_repository(project_id)?;
@ -364,17 +358,7 @@ impl App {
.or_insert_with(|| Semaphore::new(1)); .or_insert_with(|| Semaphore::new(1));
let _permit = semaphore.acquire().await?; let _permit = semaphore.acquire().await?;
let branch_id = virtual_branches::create_virtual_branch(&gb_repository, name)?.id; virtual_branches::create_virtual_branch(&gb_repository, create)?;
virtual_branches::update_branch(
&gb_repository,
BranchUpdateRequest {
id: branch_id,
name: None,
order: None,
ownership: Some(ownership.clone()),
},
)
.context("failed to update branch")?;
Ok(()) Ok(())
} }

View File

@ -186,8 +186,14 @@ fn run_new(butler: ButlerCli) {
.interact_text() .interact_text()
.unwrap(); .unwrap();
virtual_branches::create_virtual_branch(&butler.gb_repository, &input) virtual_branches::create_virtual_branch(
.expect("failed to create virtual branch"); &butler.gb_repository,
&virtual_branches::branch::BranchCreateRequest {
name: Some(input),
..Default::default()
},
)
.expect("failed to create virtual branch");
} }
fn run_move(butler: ButlerCli) { fn run_move(butler: ButlerCli) {

View File

@ -17,7 +17,6 @@ impl Sender {
self.app_handle self.app_handle
.emit_all(&event.name, Some(&event.payload)) .emit_all(&event.name, Some(&event.payload))
.context("emit event")?; .context("emit event")?;
log::debug!("sent event: {}", event.name);
Ok(()) Ok(())
} }
} }

View File

@ -598,11 +598,10 @@ async fn list_virtual_branches(
async fn create_virtual_branch( async fn create_virtual_branch(
handle: tauri::AppHandle, handle: tauri::AppHandle,
project_id: &str, project_id: &str,
name: &str, branch: virtual_branches::branch::BranchCreateRequest,
ownership: virtual_branches::branch::Ownership,
) -> Result<(), Error> { ) -> Result<(), Error> {
let app = handle.state::<app::App>(); let app = handle.state::<app::App>();
app.create_virtual_branch(project_id, name, &ownership) app.create_virtual_branch(project_id, &branch)
.await .await
.context("failed to create virtual branch")?; .context("failed to create virtual branch")?;
Ok(()) Ok(())

View File

@ -42,6 +42,13 @@ pub struct BranchUpdateRequest {
pub order: Option<usize>, pub order: Option<usize>,
} }
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct BranchCreateRequest {
pub name: Option<String>,
pub ownership: Option<Ownership>,
pub order: Option<usize>,
}
impl TryFrom<&dyn crate::reader::Reader> for Branch { impl TryFrom<&dyn crate::reader::Reader> for Branch {
type Error = crate::reader::Error; type Error = crate::reader::Error;

View File

@ -17,7 +17,7 @@ use uuid::Uuid;
use crate::{gb_repository, project_repository, reader, sessions}; use crate::{gb_repository, project_repository, reader, sessions};
use self::branch::{FileOwnership, Hunk, Ownership}; use self::branch::{BranchCreateRequest, FileOwnership, Hunk, Ownership};
// this struct is a mapping to the view `Branch` type in Typescript // this struct is a mapping to the view `Branch` type in Typescript
// found in src-tauri/src/routes/repo/[project_id]/types.ts // found in src-tauri/src/routes/repo/[project_id]/types.ts
@ -870,11 +870,8 @@ pub fn create_virtual_branch_from_branch(
.context("failed to create branch iterator")? .context("failed to create branch iterator")?
.collect::<Result<Vec<branch::Branch>, reader::Error>>() .collect::<Result<Vec<branch::Branch>, reader::Error>>()
.context("failed to read virtual branches")?; .context("failed to read virtual branches")?;
let max_order = virtual_branches
.iter() let order = virtual_branches.len();
.map(|branch| branch.order)
.max()
.unwrap_or(0);
let now = time::UNIX_EPOCH let now = time::UNIX_EPOCH
.elapsed() .elapsed()
@ -892,7 +889,7 @@ pub fn create_virtual_branch_from_branch(
created_timestamp_ms: now, created_timestamp_ms: now,
updated_timestamp_ms: now, updated_timestamp_ms: now,
ownership: Ownership::default(), ownership: Ownership::default(),
order: max_order + 1, order,
}; };
// add file ownership based off the diff // add file ownership based off the diff
@ -918,8 +915,10 @@ pub fn create_virtual_branch_from_branch(
pub fn create_virtual_branch( pub fn create_virtual_branch(
gb_repository: &gb_repository::Repository, gb_repository: &gb_repository::Repository,
name: &str, create: &BranchCreateRequest,
) -> Result<branch::Branch> { ) -> Result<branch::Branch> {
println!("create virtual branch: {:?}", create);
let current_session = gb_repository let current_session = gb_repository
.get_or_create_current_session() .get_or_create_current_session()
.context("failed to get or create currnt session")?; .context("failed to get or create currnt session")?;
@ -937,24 +936,49 @@ pub fn create_virtual_branch(
.context("failed to find commit")?; .context("failed to find commit")?;
let tree = commit.tree().context("failed to find tree")?; let tree = commit.tree().context("failed to find tree")?;
let virtual_branches = Iterator::new(&current_session_reader) let mut virtual_branches = Iterator::new(&current_session_reader)
.context("failed to create branch iterator")? .context("failed to create branch iterator")?
.collect::<Result<Vec<branch::Branch>, reader::Error>>() .collect::<Result<Vec<branch::Branch>, reader::Error>>()
.context("failed to read virtual branches")?; .context("failed to read virtual branches")?
let max_order = virtual_branches .into_iter()
.iter() .filter(|branch| branch.applied)
.map(|branch| branch.order) .collect::<Vec<branch::Branch>>();
.max() virtual_branches.sort_by_key(|branch| branch.order);
.unwrap_or(0);
let order = if let Some(order) = create.order {
if order > virtual_branches.len() {
virtual_branches.len()
} else {
order
}
} else {
virtual_branches.len()
};
let branch_writer = branch::Writer::new(gb_repository);
// make space for the new branch
for branch in virtual_branches.iter().skip(order) {
let mut branch = branch.clone();
branch.order += 1;
branch_writer
.write(&branch)
.context("failed to write branch")?;
}
let now = time::UNIX_EPOCH let now = time::UNIX_EPOCH
.elapsed() .elapsed()
.context("failed to get elapsed time")? .context("failed to get elapsed time")?
.as_millis(); .as_millis();
let branch = Branch { let name: String = create
.name
.as_ref()
.map(|name| name.to_string())
.unwrap_or_else(|| format!("Branch {}", virtual_branches.len() + 1));
let mut branch = Branch {
id: Uuid::new_v4().to_string(), id: Uuid::new_v4().to_string(),
name: name.to_string(), name,
applied: true, applied: true,
upstream: "".to_string(), upstream: "".to_string(),
tree: tree.id(), tree: tree.id(),
@ -962,11 +986,19 @@ pub fn create_virtual_branch(
created_timestamp_ms: now, created_timestamp_ms: now,
updated_timestamp_ms: now, updated_timestamp_ms: now,
ownership: Ownership::default(), ownership: Ownership::default(),
order: max_order + 1, order,
}; };
let writer = branch::Writer::new(gb_repository); branch_writer
writer.write(&branch).context("failed to write branch")?; .write(&branch)
.context("failed to write branch")?;
if let Some(ownership) = &create.ownership {
let branch_reader = branch::Reader::new(&current_session_reader);
set_ownership(&branch_reader, &branch_writer, &mut branch, ownership)
.context("failed to set ownership")?;
}
Ok(branch) Ok(branch)
} }
@ -1261,8 +1293,11 @@ pub fn get_status_by_branch(
if virtual_branches.is_empty() { if virtual_branches.is_empty() {
// create an empty virtual branch // create an empty virtual branch
virtual_branches = vec![create_virtual_branch(gb_repository, "default branch") virtual_branches =
.context("failed to default branch")?]; vec![
create_virtual_branch(gb_repository, &BranchCreateRequest::default())
.context("failed to default branch")?,
];
} }
// sort by order, so that the default branch is first (left in the ui) // sort by order, so that the default branch is first (left in the ui)
@ -1970,7 +2005,7 @@ mod tests {
behind: 0, behind: 0,
})?; })?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2014,7 +2049,7 @@ mod tests {
} }
#[test] #[test]
fn test_create_branch() -> Result<()> { fn test_create_branch_in_the_middle() -> Result<()> {
let repository = test_repository()?; let repository = test_repository()?;
let project = projects::Project::try_from(&repository)?; let project = projects::Project::try_from(&repository)?;
let gb_repo_path = tempdir()?.path().to_str().unwrap().to_string(); let gb_repo_path = tempdir()?.path().to_str().unwrap().to_string();
@ -2032,7 +2067,55 @@ mod tests {
behind: 0, behind: 0,
})?; })?;
create_virtual_branch(&gb_repo, "test_branch").expect("failed to create virtual branch"); create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch");
create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch");
create_virtual_branch(
&gb_repo,
&BranchCreateRequest {
order: Some(1),
..Default::default()
},
)
.expect("failed to create virtual branch");
let current_session = gb_repo.get_or_create_current_session()?;
let current_session_reader = sessions::Reader::open(&gb_repo, &current_session)?;
let mut branches = iterator::BranchIterator::new(&current_session_reader)?
.collect::<Result<Vec<branch::Branch>, reader::Error>>()
.expect("failed to read branches");
branches.sort_by_key(|b| b.order);
assert_eq!(branches.len(), 3);
assert_eq!(branches[0].name, "Branch 1");
assert_eq!(branches[1].name, "Branch 3");
assert_eq!(branches[2].name, "Branch 2");
Ok(())
}
#[test]
fn test_create_branch_no_arguments() -> Result<()> {
let repository = test_repository()?;
let project = projects::Project::try_from(&repository)?;
let gb_repo_path = tempdir()?.path().to_str().unwrap().to_string();
let storage = storage::Storage::from_path(tempdir()?.path());
let user_store = users::Storage::new(storage.clone());
let project_store = projects::Storage::new(storage);
project_store.add_project(&project)?;
let gb_repo =
gb_repository::Repository::open(gb_repo_path, project.id, project_store, user_store)?;
target::Writer::new(&gb_repo).write_default(&target::Target {
name: "origin".to_string(),
remote: "origin".to_string(),
sha: repository.head().unwrap().target().unwrap(),
behind: 0,
})?;
create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch");
let current_session = gb_repo.get_or_create_current_session()?; let current_session = gb_repo.get_or_create_current_session()?;
let current_session_reader = sessions::Reader::open(&gb_repo, &current_session)?; let current_session_reader = sessions::Reader::open(&gb_repo, &current_session)?;
@ -2041,7 +2124,10 @@ mod tests {
.collect::<Result<Vec<branch::Branch>, reader::Error>>() .collect::<Result<Vec<branch::Branch>, reader::Error>>()
.expect("failed to read branches"); .expect("failed to read branches");
assert_eq!(branches.len(), 1); assert_eq!(branches.len(), 1);
assert_eq!(branches[0].name, "test_branch"); assert_eq!(branches[0].name, "Branch 1");
assert!(branches[0].applied);
assert_eq!(branches[0].ownership, Ownership::default());
assert_eq!(branches[0].order, 0);
Ok(()) Ok(())
} }
@ -2076,10 +2162,10 @@ mod tests {
"line1\nline2\n", "line1\nline2\n",
)?; )?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch2_id = create_virtual_branch(&gb_repo, "test_branch2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2163,10 +2249,10 @@ mod tests {
"line1\nline2\n", "line1\nline2\n",
)?; )?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch2_id = create_virtual_branch(&gb_repo, "test_branch2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2220,7 +2306,7 @@ mod tests {
let current_session_reader = sessions::Reader::open(&gb_repo, &current_session)?; let current_session_reader = sessions::Reader::open(&gb_repo, &current_session)?;
let branch_reader = branch::Reader::new(&current_session_reader); let branch_reader = branch::Reader::new(&current_session_reader);
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2337,13 +2423,13 @@ mod tests {
behind: 0, behind: 0,
})?; })?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch2_id = create_virtual_branch(&gb_repo, "test_branch2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch3_id = create_virtual_branch(&gb_repo, "test_branch3") let branch3_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2457,10 +2543,10 @@ mod tests {
"line0\nline1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\nline11\nline12\nline13\nline14\n", "line0\nline1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\nline11\nline12\nline13\nline14\n",
)?; )?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch2_id = create_virtual_branch(&gb_repo, "test_branch2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2552,7 +2638,8 @@ mod tests {
"line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\nline11\nline12\nline13\nline14\nline15\n", "line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\nline11\nline12\nline13\nline14\nline15\n",
)?; )?;
create_virtual_branch(&gb_repo, "test_branch").expect("failed to create virtual branch"); create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch");
let statuses = let statuses =
get_status_by_branch(&gb_repo, &project_repository).expect("failed to get status"); get_status_by_branch(&gb_repo, &project_repository).expect("failed to get status");
@ -2612,7 +2699,7 @@ mod tests {
})?; })?;
// create a vbranch // create a vbranch
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2719,7 +2806,7 @@ mod tests {
})?; })?;
// create a vbranch // create a vbranch
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2798,7 +2885,7 @@ mod tests {
})?; })?;
// create a vbranch // create a vbranch
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2892,10 +2979,10 @@ mod tests {
"line5\nline6\n", "line5\nline6\n",
)?; )?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch2_id = create_virtual_branch(&gb_repo, "test_branch2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -2995,10 +3082,10 @@ mod tests {
"file3\n", "file3\n",
)?; )?;
let branch2_id = create_virtual_branch(&gb_repo, "branch_rm_2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch3_id = create_virtual_branch(&gb_repo, "branch_add_3") let branch3_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -3086,10 +3173,10 @@ mod tests {
"line5\nline6\n", "line5\nline6\n",
)?; )?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch2_id = create_virtual_branch(&gb_repo, "test_branch2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -3148,8 +3235,9 @@ mod tests {
std::fs::remove_file(std::path::Path::new(&project.path).join(file_path3))?; std::fs::remove_file(std::path::Path::new(&project.path).join(file_path3))?;
// create branches that conflict with our earlier branches // create branches that conflict with our earlier branches
create_virtual_branch(&gb_repo, "test_branch3").expect("failed to create virtual branch"); create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
let branch4_id = create_virtual_branch(&gb_repo, "test_branch4") .expect("failed to create virtual branch");
let branch4_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -3248,7 +3336,7 @@ mod tests {
let repo = &project_repository.git_repository; let repo = &project_repository.git_repository;
repo.remote("origin", "http://origin.com/project")?; repo.remote("origin", "http://origin.com/project")?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -3375,7 +3463,7 @@ mod tests {
)?; )?;
// create a default branch. there should not be anything on this // create a default branch. there should not be anything on this
let branch1_id = create_virtual_branch(&gb_repo, "default branch") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -3485,10 +3573,10 @@ mod tests {
behind: 0, behind: 0,
})?; })?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch_1") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
let branch2_id = create_virtual_branch(&gb_repo, "test_branch_2") let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;
@ -3650,7 +3738,7 @@ mod tests {
"file3\n", "file3\n",
)?; )?;
let branch1_id = create_virtual_branch(&gb_repo, "test_branch_1") let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
.expect("failed to create virtual branch") .expect("failed to create virtual branch")
.id; .id;

View File

@ -50,7 +50,14 @@ export async function list(params: { projectId: string }): Promise<Branch[]> {
return plainToInstance(Branch, result); return plainToInstance(Branch, result);
} }
export async function create(params: { projectId: string; name: string; ownership: string }) { export async function create(params: {
projectId: string;
branch: {
name?: string;
ownership?: string;
order?: number;
};
}) {
return await invoke<void>('create_virtual_branch', params); return await invoke<void>('create_virtual_branch', params);
} }

View File

@ -13,18 +13,20 @@
const newBranchClass = 'new-branch-active'; const newBranchClass = 'new-branch-active';
function ensureBranchOrder() {
branches.forEach((branch, i) => {
if (branch.order !== i) {
virtualBranches.updateBranchOrder(branch.id, i);
}
});
}
function handleDndEvent(e: CustomEvent<DndEvent<Branch>>) { function handleDndEvent(e: CustomEvent<DndEvent<Branch>>) {
branches = e.detail.items; branches = e.detail.items;
if (e.type == 'finalize') { if (e.type == 'finalize') {
branches = branches.filter((branch) => branch.active); branches = branches.filter((branch) => branch.active);
// ensure branch.order is sorted in ascending order ensureBranchOrder();
// if not, send update requests
branches.forEach((branch, i) => {
if (branch.order !== i) {
virtualBranches.updateBranchOrder(branch.id, i);
}
});
} }
} }
@ -52,13 +54,14 @@
on:consider={handleDndEvent} on:consider={handleDndEvent}
on:finalize={handleDndEvent} on:finalize={handleDndEvent}
> >
{#each branches.filter((c) => c.active) as { id, name, files, commits, upstream, description } (id)} {#each branches.filter((c) => c.active) as { id, name, files, commits, upstream, description, order } (id)}
<Lane <Lane
{name} {name}
commitMessage={description} commitMessage={description}
{files} {files}
{commits} {commits}
on:empty={handleEmpty} on:empty={handleEmpty}
{order}
{projectId} {projectId}
{upstream} {upstream}
branchId={id} branchId={id}
@ -66,7 +69,7 @@
{projectPath} {projectPath}
/> />
{/each} {/each}
<NewBranchDropZone {branches} {virtualBranches} /> <NewBranchDropZone {virtualBranches} />
</div> </div>
<style lang="postcss"> <style lang="postcss">

View File

@ -27,6 +27,7 @@
export let files: File[]; export let files: File[];
export let commits: Commit[]; export let commits: Commit[];
export let projectId: string; export let projectId: string;
export let order: number;
export let virtualBranches: VirtualBranchOperations; export let virtualBranches: VirtualBranchOperations;
$: remoteCommits = commits.filter((c) => c.isRemote); $: remoteCommits = commits.filter((c) => c.isRemote);
@ -160,16 +161,18 @@
<button <button
bind:this={meatballButton} bind:this={meatballButton}
class="flex-grow-0 p-2 text-light-600 dark:text-dark-200" class="flex-grow-0 p-2 text-light-600 dark:text-dark-200"
on:keydown={(e) => popupMenu.openByElement(meatballButton, branchId)} on:keydown={() => popupMenu.openByElement(meatballButton, branchId)}
on:click={(e) => popupMenu.openByElement(meatballButton, branchId)} on:click={() => popupMenu.openByElement(meatballButton, branchId)}
> >
<IconMeatballMenu /> <IconMeatballMenu />
</button> </button>
</div> </div>
<PopupMenu bind:this={popupMenu} let:item={branchId}> <PopupMenu bind:this={popupMenu} let:item={branchId}>
<PopupMenuItem on:click={() => branchId && virtualBranches.unapplyBranch(branchId)}> <PopupMenuItem on:click={() => branchId && virtualBranches.unapplyBranch(branchId)}>
Unapply Unapply
</PopupMenuItem> </PopupMenuItem>
<PopupMenuItem on:click={handleToggleExpandAll}> <PopupMenuItem on:click={handleToggleExpandAll}>
{#if allExpanded} {#if allExpanded}
Collapse all Collapse all
@ -177,6 +180,14 @@
Expand all Expand all
{/if} {/if}
</PopupMenuItem> </PopupMenuItem>
<PopupMenuItem on:click={() => virtualBranches.createBranch({ order: order + 1 })}>
Create branch after
</PopupMenuItem>
<PopupMenuItem on:click={() => virtualBranches.createBranch({ order })}>
Create branch before
</PopupMenuItem>
</PopupMenu> </PopupMenu>
<div <div

View File

@ -6,17 +6,11 @@
import { Button } from '$lib/components'; import { Button } from '$lib/components';
import type { VirtualBranchOperations } from './vbranches'; import type { VirtualBranchOperations } from './vbranches';
export let branches: Branch[];
export let virtualBranches: VirtualBranchOperations; export let virtualBranches: VirtualBranchOperations;
let items: Branch[] = []; let items: Branch[] = [];
function newBranchName() {
const nextNumber = branches.filter((b) => b.name.startsWith('new branch')).length + 1;
return `new branch ${nextNumber}`;
}
function handleNewVirtualBranch() { function handleNewVirtualBranch() {
virtualBranches.createBranch(newBranchName(), ''); virtualBranches.createBranch({});
} }
function handleDndFinalize(e: CustomEvent<DndEvent<Branch | File | Hunk>>) { function handleDndFinalize(e: CustomEvent<DndEvent<Branch | File | Hunk>>) {
@ -39,7 +33,7 @@
.map((file) => file.id + ':' + file.hunks.map((hunk) => hunk.id).join(',')) .map((file) => file.id + ':' + file.hunks.map((hunk) => hunk.id).join(','))
.join('\n'); .join('\n');
virtualBranches.createBranch(newBranchName(), ownership); virtualBranches.createBranch({ ownership });
items = []; items = [];
return; return;
} }

View File

@ -10,7 +10,11 @@ const cache: Map<string, VirtualBranchOperations & Readable<Loadable<api.vbranch
export interface VirtualBranchOperations { export interface VirtualBranchOperations {
setTarget(branch: string): Promise<void | Target>; setTarget(branch: string): Promise<void | Target>;
createBranch(name: string, path: string): Promise<void | object>; createBranch(branch: {
name?: string;
ownership?: string;
order?: number;
}): Promise<void | object>;
commitBranch(branch: string, message: string): Promise<void | object>; commitBranch(branch: string, message: string): Promise<void | object>;
updateBranchName(branchId: string, name: string): Promise<void | object>; updateBranchName(branchId: string, name: string): Promise<void | object>;
updateBranchOrder(branchId: string, order: number): Promise<void | object>; updateBranchOrder(branchId: string, order: number): Promise<void | object>;
@ -42,9 +46,9 @@ export function getVirtualBranches(
console.error(err); console.error(err);
toasts.error('Failed to set target'); toasts.error('Failed to set target');
}), }),
createBranch: (name, path) => createBranch: (branch: { name?: string; ownership?: string; order?: number }) =>
api.vbranches api.vbranches
.create({ projectId, name, ownership: path }) .create({ projectId, branch })
.then(() => refresh(projectId, writeable)) .then(() => refresh(projectId, writeable))
.catch((err) => { .catch((err) => {
console.error(err); console.error(err);