Skip to content

Commit

Permalink
feat: rename branches
Browse files Browse the repository at this point in the history
  • Loading branch information
Akryum committed Sep 3, 2024
1 parent 761ae55 commit 1c0ae62
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 12 deletions.
5 changes: 3 additions & 2 deletions packages/app/components/LinkList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const props = defineProps<{
const emit = defineEmits<{
select: [item: TItem]
focusFilter: [focused: boolean]
}>()
const filter = props.id ? useLocalStorage(`link-list.${props.id}.filter`, '') : ref('')
Expand Down Expand Up @@ -102,8 +103,8 @@ function onKeyEnter(event: MouseEvent) {
@keydown.up="hoverIndex = Math.max(hoverIndex - 1, 0)"
@keydown.down="hoverIndex = Math.min(hoverIndex + 1, displayedItems.length - 1)"
@keydown.enter="onKeyEnter"
@focus="showKeyboardNavigationHints = true"
@blur="showKeyboardNavigationHints = false"
@focus="showKeyboardNavigationHints = true; $emit('focusFilter', true)"
@blur="showKeyboardNavigationHints = false; $emit('focusFilter', false)"
>
<template #trailing>
<slot name="trailing">
Expand Down
117 changes: 107 additions & 10 deletions packages/app/pages/db/branches.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ async function switchToBranch(branch: string) {
resourceInstanceStore.refreshInstance()
}
const filterFocused = ref(false)
// Create
const createShown = ref(false)
Expand All @@ -53,6 +55,7 @@ defineShortcuts({
handler: () => {
createBranch(linkList.value?.filter)
},
whenever: [filterFocused],
},
})
Expand Down Expand Up @@ -86,6 +89,51 @@ async function confirmDeleteBranch() {
})
await refreshNuxtData('branches')
}
// Rename branch
const renameShown = ref(false)
const renameBranchName = ref('')
const renameBranchNewName = ref('')
async function renameBranch(branch: string) {
if (branch === currentBranch.value || branch === 'default') {
return
}
renameBranchName.value = branch
renameBranchNewName.value = branch
renameShown.value = true
}
async function confirmRenameBranch() {
renameShown.value = false
await $fetch('/api/branches/rename', {
method: 'POST',
body: {
branch: renameBranchName.value,
newName: renameBranchNewName.value,
},
})
await refreshNuxtData('branches')
}
defineShortcuts({
meta_enter: {
usingInput: true,
handler: () => {
confirmRenameBranch()
},
whenever: [renameShown],
},
escape: {
usingInput: true,
handler: () => {
renameShown.value = false
},
whenever: [renameShown],
},
})
</script>

<template>
Expand All @@ -104,6 +152,7 @@ async function confirmDeleteBranch() {
filter-placeholder="Filter or create branch..."
class="flex-1"
@select="switchToBranch"
@focus-filter="filterFocused = $event"
>
<template #before-items="{ filter }">
<UButton
Expand Down Expand Up @@ -131,23 +180,32 @@ async function confirmDeleteBranch() {
}"
@click="switchToBranch(item)"
>
<div class="flex items-center min-h-8 pl-2">
<div class="flex items-center min-h-8 pl-2 gap-2">
<div class="flex-1">
{{ item }}
</div>

<div v-if="item === currentBranch" class="pr-2 opacity-50">
Current
</div>
<UButton
v-else-if="item !== 'default'"
icon="i-ph-trash"
color="gray"
size="sm"
@click.stop="deleteBranch(item)"
>
Delete
</UButton>
<template v-else-if="item !== 'default'">
<UButton
icon="i-ph-note-pencil"
color="gray"
size="sm"
@click.stop="renameBranch(item)"
>
Rename
</UButton>
<UButton
icon="i-ph-trash"
color="gray"
size="sm"
@click.stop="deleteBranch(item)"
>
Delete
</UButton>
</template>
</div>
</LinkListItem>
</template>
Expand Down Expand Up @@ -186,5 +244,44 @@ async function confirmDeleteBranch() {
@confirm="confirmDeleteBranch()"
@cancel="deleteShown = false"
/>

<UModal
v-model="renameShown"
>
<UCard>
<template #header>
<h2 class="text-lg font-bold flex items-center gap-2">
<UIcon name="i-ph-note-pencil" class="w-6 h-6" />
Rename branch {{ renameBranchName }}
</h2>
</template>

<UFormGroup label="Branch name">
<UInput v-model="renameBranchNewName" autofocus />
</UFormGroup>

<template #footer>
<div class="flex items-center gap-2">
<UButton
color="gray"
@click="renameShown = false"
>
Cancel

<KbShortcut :keys="['escape']" />
</UButton>

<UButton
color="red"
@click="confirmRenameBranch()"
>
Rename

<KbShortcut :keys="['meta', 'enter']" />
</UButton>
</div>
</template>
</UCard>
</UModal>
</div>
</template>
7 changes: 7 additions & 0 deletions packages/app/server/api/branches/rename.post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { renameBranch } from '@moquerie/core'

export default defineEventHandler(async (event) => {
const { branch, newName } = await readBody(event)
const mq = getMq()
await renameBranch(mq, branch, newName)
})
23 changes: 23 additions & 0 deletions packages/core/src/resource/branch.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import fs from 'node:fs'
import path from 'pathe'
import { getLocalDbFolder } from '../storage/path.js'
import type { MoquerieInstance } from '../instance.js'
Expand All @@ -6,3 +7,25 @@ import { getCurrentBranch, resourceInstancesFolders } from './storage.js'
export function getCurrentBranchFolder(mq: MoquerieInstance) {
return path.join(getLocalDbFolder(mq), ...resourceInstancesFolders, getCurrentBranch(mq))
}

export async function renameBranch(mq: MoquerieInstance, branch: string, newName: string) {
if (branch === 'default') {
throw new Error('Cannot rename default branch')
}

if (branch === getCurrentBranch(mq)) {
throw new Error(`Cannot rename current branch (${getCurrentBranch(mq)})`)
}

const branchFolder = path.join(getLocalDbFolder(mq), ...resourceInstancesFolders, branch)
if (!fs.existsSync(branchFolder)) {
throw new Error(`Branch ${branch} does not exist`)
}

const newBranchFolder = path.join(getLocalDbFolder(mq), ...resourceInstancesFolders, newName)
if (fs.existsSync(newBranchFolder)) {
throw new Error(`Branch ${newName} already exists`)
}

await fs.promises.rename(branchFolder, newBranchFolder)
}

0 comments on commit 1c0ae62

Please sign in to comment.