Skip to content

feat(sync): add sync diff feature and dropdown component #1156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frontend/public/images/icons/sync-diff.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/public/images/icons/sync-remote.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 10 additions & 7 deletions frontend/src/components/shared/RepoClone.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
/>

<!-- multi-source sync button -->
<CsgButton
<SyncDropdown
:syncInprogress="syncInprogress"
:repoType="repoType"
:model-path="namespacePath"
:commitId="commitId"
v-if="showSyncButton"
type="default"
:name="syncInprogress ? $t('repo.source.syncing') : $t('repo.source.syncButton')"
class="btn btn-secondary-gray btn-sm modelBtn"
:disabled="syncInprogress"
svgName="sync"
@click="handleSyncRepo"
@syncRepo="handleSyncRepo"
/>

<!-- evaluation button -->
Expand Down Expand Up @@ -269,6 +268,7 @@
import { computed, ref, onMounted, watch } from 'vue'
import MarkdownViewer from '../shared/viewers/MarkdownViewer.vue'
import DeployDropdown from './DeployDropdown.vue'
import SyncDropdown from './SyncDropdown.vue'
import SvgIcon from './SvgIcon.vue'
import useFetchApi from '../../packs/useFetchApi'
import { ElMessage } from 'element-plus'
Expand All @@ -289,6 +289,9 @@
enableFinetune: Boolean,
enableEvaluation: Boolean,
showAddToCollections: Boolean,
canManage: Boolean,
syncStatus: String,
commitId: String
})

const { actionLimited, isLoggedIn } = storeToRefs(userStore)
Expand Down
19 changes: 18 additions & 1 deletion frontend/src/components/shared/RepoDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
:can-write="repoDetailStore.canWrite"
:tags="tags"
:userName="userName"
:commitId="commitId"
:commitId="commitId || lastCommit?.id"
:repoType="repoType"
:path="`${namespace}/${repoName}`" />
</div>
Expand Down Expand Up @@ -62,6 +62,7 @@

const repoDetailStore = useRepoDetailStore()
const { isInitialized } = storeToRefs(repoDetailStore)
const lastCommit = ref({})

// const repo = ref({})
// const tags = ref({
Expand Down Expand Up @@ -138,10 +139,26 @@
return {}
}

const fetchLastCommit = async () => {
const url = `/${props.repoType}s/${props.namespace}/${props.repoName}/last_commit`
try {
const { data } = await useFetchApi(url).json()

if (data.value) {
const json = data.value
lastCommit.value = json.data
}
} catch (error) {
console.log(error)
}
}

onMounted(() => {
if (!isSameRepo.value || (isSameRepo.value && !isInitialized.value)) {
fetchRepoDetail()
}

fetchLastCommit()
})

provide('fetchRepoDetail', fetchRepoDetail)
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/shared/RepoTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
:enableEndpoint="repoDetail.enableInference"
:enableFinetune="repoDetail.enableFinetune"
:enableEvaluation="repoDetail.enableEvaluation"
:syncStatus="repoDetail.syncStatus"
:canManage="settingsVisibility"
:commitId="commitId"
/>
</div>
<tab-container
Expand Down
130 changes: 130 additions & 0 deletions frontend/src/components/shared/SyncDropdown.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<template>
<div>
<el-dropdown class="h-9">
<el-button plain type="default" class="btn btn-secondary-gray btn-sm !h-full">
<SvgIcon name="sync" class="mr-1" />
<div class="text-gray-700">{{ $t('repo.source.sync') }}</div>
<el-icon class="ml-1 el-icon--right">
<arrow-down />
</el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :disabled="!commitId">
<p class="flex gap-2" @click="showDiff">
<SvgIcon name="sync-diff" class="mr-1" />
{{ $t('repo.source.syncDiff') }}
</p>
</el-dropdown-item>
<el-dropdown-item>
<p class="flex gap-2" @click="emit('syncRepo')">
<SvgIcon name="sync-remote" class="mr-1" />
{{ syncInprogress ? $t('repo.source.syncing') : $t('repo.source.syncButton') }}
</p>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>

<el-dialog
v-model="dialogVisible"
top="200px"
:style="{ borderRadius: '10px' }"
width="450"
class="invite_dialog"
>
<template #header="{ close }">
<div class="flex gap-4">
<div class="border border-gray-200 rounded-[10px] flex justify-center items-center p-3">
<SvgIcon name="sync-diff" width="24" height="24" />
</div>
<div class="flex flex-col gap-1">
<p class="text-gray-900 text-lg font-medium leading-7">{{ $t('repo.source.checkSyncDiff') }}</p>
<p class="text-gray-600 text-sm font-light leading-[22px]"> {{ modelPath }} </p>
</div>
</div>
</template>

<hr class="my-2" />

<div v-if="!hasRemoteChanges">
<p class="py-5">
{{ $t('repo.source.nodiffs') }}
</p>
</div>
<div v-else class="flex flex-col gap-3">
<p v-for="item in diffs.added" :key="item" class="flex justify-between">
<span class="text-gray-600 text-md font-light"> {{ item }} </span>
<span class="border border-success-200 rounded-2xl text-xs bg-success-50 px-2 py-1 text-success-700 leading-4">{{ $t('repo.source.added') }}</span>
</p>
<p v-for="item in diffs.removed" :key="item" class="flex justify-between">
<span class="text-gray-600 text-md font-light"> {{ item }} </span>
<span class="border border-error-200 rounded-2xl text-xs bg-error-50 px-2 py-1 text-error-700 leading-4">{{ $t('repo.source.removed') }}</span>
</p>
<p v-for="item in diffs.modified" :key="item" class="flex justify-between">
<span class="text-gray-600 text-md font-light"> {{ item }} </span>
<span class="border border-brand-200 rounded-2xl text-xs bg-brand-50 px-2 py-1 text-brand-700 leading-4">{{ $t('repo.source.modified') }}</span>
</p>
</div>

<hr class="my-2" />

<template #footer>
<div v-if="hasRemoteChanges" class="flex justify-end gap-3 px-5">
<CsgButton
class="btn btn-secondary-gray btn-sm"
:name="$t('all.cancel')"
@click="dialogVisible = false"
/>
<CsgButton
class="btn btn-primary btn-sm"
:name="$t('repo.source.sync')"
@click="emit('syncRepo')"
/>
</div>
</template>
</el-dialog>
</template>

<script setup>
import { ref, computed } from "vue";
import { useI18n } from "vue-i18n";
import useFetchApi from '@/packs/useFetchApi'
import { ElMessage } from "element-plus";

const { t } = useI18n();
const dialogVisible = ref(false);
const diffs = ref({ "added": [], "removed": [], "modified": [] })

const emit = defineEmits(["syncRepo"]);

const props = defineProps({
syncInprogress: Boolean,
repoType: String,
modelPath: String,
commitId: String,
});

const hasRemoteChanges = computed(() => {
return diffs.value.added.length > 0 || diffs.value.removed.length > 0 || diffs.value.modified.length > 0
})

const showDiff = async () => {
if (!props.commitId) { return }
try {
const url = `/${props.repoType}s/${props.modelPath}/remote_diff?left_commit_id=${props.commitId}`
const { data, error } = await useFetchApi(url).json()
if (error.value) {
ElMessage.warning(error.value.msg || t('repo.source.syncDiffError'))
} else {
dialogVisible.value = true
if (data.value.data) {
diffs.value = data.value.data[0]
}
}
} catch (error) {
console.log(error)
}
}
</script>
10 changes: 9 additions & 1 deletion frontend/src/locales/en_js/repo.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,22 @@ export const repo = {
cancel: "Cancel",
},
source: {
syncButton: "Sync",
sync: "Sync",
syncing: "Syncing",
syncButton: "Sync Now",
syncDiff: "Sync Diff",
all: "All sources",
opencsg: "OpenCSG",
local: "Local",
remoteResource: "OpenCSG Remote Resource",
syncCompleted: "Local version matches remote source version",
needSync: "Remote has pending sync versions",
from: "Mirror from",
checkSyncDiff: "Check Sync Diff",
added: "Added",
removed: "Removed",
modified: "Modified",
syncDiffError: "Sync Diff Error",
nodiffs: "No diffs from remote",
}
}
10 changes: 9 additions & 1 deletion frontend/src/locales/zh_js/repo.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,22 @@ export const repo = {
cancel: "取消",
},
source: {
syncButton: "同步",
sync: "同步",
syncButton: "立即同步",
syncing: "同步中",
syncDiff: "同步差异",
all: "显示所有源",
opencsg: "OpenCSG",
local: "本地",
remoteResource: "OpenCSG 远端资源",
syncCompleted: "本地版本与远端源版本一致",
needSync: "远端有待同步版本",
from: "镜像来自",
checkSyncDiff: "查看同步差异",
added: "新增",
removed: "删除",
modified: "修改",
syncDiffError: "同步差异获取失败",
nodiffs: "远端没有更新",
}
}