mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-19 22:09:03 +08:00
feat: Support batch operations for image tags (#10597)
This commit is contained in:
parent
02c002bda6
commit
222181baff
14 changed files with 101 additions and 43 deletions
|
|
@ -37,7 +37,7 @@ type ImagePull struct {
|
||||||
|
|
||||||
type ImageTag struct {
|
type ImageTag struct {
|
||||||
SourceID string `json:"sourceID" validate:"required"`
|
SourceID string `json:"sourceID" validate:"required"`
|
||||||
TargetName string `json:"targetName" validate:"required"`
|
Tags []string `json:"tags" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImagePush struct {
|
type ImagePush struct {
|
||||||
|
|
|
||||||
|
|
@ -363,9 +363,39 @@ func (u *ImageService) ImageTag(req dto.ImageTag) error {
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
if err := client.ImageTag(context.TODO(), req.SourceID, req.TargetName); err != nil {
|
imageItem, err := client.ImageInspect(context.Background(), req.SourceID)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, tag := range req.Tags {
|
||||||
|
isNew := true
|
||||||
|
for _, tagOld := range imageItem.RepoTags {
|
||||||
|
if tag == tagOld {
|
||||||
|
isNew = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isNew {
|
||||||
|
if err := client.ImageTag(context.TODO(), req.SourceID, tag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, tagOld := range imageItem.RepoTags {
|
||||||
|
isDel := true
|
||||||
|
for _, tag := range req.Tags {
|
||||||
|
if tag == tagOld {
|
||||||
|
isDel = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isDel {
|
||||||
|
if _, err := client.ImageRemove(context.TODO(), tagOld, image.RemoveOptions{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ export namespace Container {
|
||||||
}
|
}
|
||||||
export interface ImageTag {
|
export interface ImageTag {
|
||||||
sourceID: string;
|
sourceID: string;
|
||||||
targetName: string;
|
tags: Array<string>;
|
||||||
}
|
}
|
||||||
export interface ImagePush {
|
export interface ImagePush {
|
||||||
taskID: string;
|
taskID: string;
|
||||||
|
|
|
||||||
|
|
@ -882,7 +882,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'Detected that this image has multiple tags. Please confirm that the image name used for pushing is: {0}',
|
'Detected that this image has multiple tags. Please confirm that the image name used for pushing is: {0}',
|
||||||
imageDelete: 'Image delete',
|
imageDelete: 'Image delete',
|
||||||
imageTagDeleteHelper: 'Remove other tags associated with this image ID',
|
|
||||||
repoName: 'Container registry',
|
repoName: 'Container registry',
|
||||||
imageName: 'Image name',
|
imageName: 'Image name',
|
||||||
pull: 'Pull',
|
pull: 'Pull',
|
||||||
|
|
@ -893,6 +892,7 @@ const message = {
|
||||||
pathSelect: 'Path',
|
pathSelect: 'Path',
|
||||||
label: 'Label',
|
label: 'Label',
|
||||||
imageTag: 'Image tag',
|
imageTag: 'Image tag',
|
||||||
|
imageTagHelper: 'Supports setting multiple image tags, press Enter after entering each tag to continue',
|
||||||
push: 'Push',
|
push: 'Push',
|
||||||
fileName: 'Filename',
|
fileName: 'Filename',
|
||||||
export: 'Export',
|
export: 'Export',
|
||||||
|
|
|
||||||
|
|
@ -884,7 +884,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'Detected that this image has multiple tags. Please confirm that the image name used for pushing is: {0}',
|
'Detected that this image has multiple tags. Please confirm that the image name used for pushing is: {0}',
|
||||||
imageDelete: 'Eliminar imagen',
|
imageDelete: 'Eliminar imagen',
|
||||||
imageTagDeleteHelper: 'Eliminar otras etiquetas asociadas con este ID de imagen',
|
|
||||||
repoName: 'Repositorio de contenedores',
|
repoName: 'Repositorio de contenedores',
|
||||||
imageName: 'Nombre de la imagen',
|
imageName: 'Nombre de la imagen',
|
||||||
pull: 'Descargar',
|
pull: 'Descargar',
|
||||||
|
|
@ -895,6 +894,8 @@ const message = {
|
||||||
pathSelect: 'Ruta',
|
pathSelect: 'Ruta',
|
||||||
label: 'Etiqueta',
|
label: 'Etiqueta',
|
||||||
imageTag: 'Etiqueta de imagen',
|
imageTag: 'Etiqueta de imagen',
|
||||||
|
imageTagHelper:
|
||||||
|
'Admite configurar múltiples etiquetas de imagen, presione Enter después de ingresar cada etiqueta para continuar',
|
||||||
push: 'Subir',
|
push: 'Subir',
|
||||||
fileName: 'Nombre de archivo',
|
fileName: 'Nombre de archivo',
|
||||||
export: 'Exportar',
|
export: 'Exportar',
|
||||||
|
|
|
||||||
|
|
@ -858,7 +858,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'このイメージに複数のタグが存在することが検出されました。プッシュ時に使用するイメージ名が以下であることを確認してください:{0}',
|
'このイメージに複数のタグが存在することが検出されました。プッシュ時に使用するイメージ名が以下であることを確認してください:{0}',
|
||||||
imageDelete: '画像削除',
|
imageDelete: '画像削除',
|
||||||
imageTagDeleteHelper: 'この画像IDに関連付けられた他のタグを削除します',
|
|
||||||
repoName: 'コンテナレジストリ',
|
repoName: 'コンテナレジストリ',
|
||||||
imageName: '画像名',
|
imageName: '画像名',
|
||||||
pull: '引く',
|
pull: '引く',
|
||||||
|
|
@ -869,6 +868,7 @@ const message = {
|
||||||
pathSelect: 'パス',
|
pathSelect: 'パス',
|
||||||
label: 'ラベル',
|
label: 'ラベル',
|
||||||
imageTag: '画像タグ',
|
imageTag: '画像タグ',
|
||||||
|
imageTagHelper: '複数のイメージタグの設定をサポートし、各タグ入力後にEnterキーを押して続行します',
|
||||||
push: '押す',
|
push: '押す',
|
||||||
fileName: 'ファイル名',
|
fileName: 'ファイル名',
|
||||||
export: '輸出',
|
export: '輸出',
|
||||||
|
|
|
||||||
|
|
@ -850,7 +850,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'이 이미지에 여러 태그가 있는 것으로 감지되었습니다. 푸시 시 사용할 이미지 이름이 다음인지 확인하세요: {0}',
|
'이 이미지에 여러 태그가 있는 것으로 감지되었습니다. 푸시 시 사용할 이미지 이름이 다음인지 확인하세요: {0}',
|
||||||
imageDelete: '이미지 삭제',
|
imageDelete: '이미지 삭제',
|
||||||
imageTagDeleteHelper: '이 이미지 ID와 관련된 다른 태그를 제거합니다.',
|
|
||||||
repoName: '컨테이너 저장소 이름',
|
repoName: '컨테이너 저장소 이름',
|
||||||
imageName: '이미지 이름',
|
imageName: '이미지 이름',
|
||||||
pull: '풀',
|
pull: '풀',
|
||||||
|
|
@ -861,6 +860,7 @@ const message = {
|
||||||
pathSelect: '경로',
|
pathSelect: '경로',
|
||||||
label: '레이블',
|
label: '레이블',
|
||||||
imageTag: '이미지 태그',
|
imageTag: '이미지 태그',
|
||||||
|
imageTagHelper: '여러 이미지 태그 설정을 지원하며, 각 태그 입력 후 Enter 키를 눌러 계속합니다',
|
||||||
push: '푸시',
|
push: '푸시',
|
||||||
fileName: '파일 이름',
|
fileName: '파일 이름',
|
||||||
export: '내보내기',
|
export: '내보내기',
|
||||||
|
|
|
||||||
|
|
@ -875,7 +875,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'Terdapat pengesahan bahawa imej ini mempunyai beberapa tag. Sila pastikan nama imej yang digunakan untuk menolak adalah: {0}',
|
'Terdapat pengesahan bahawa imej ini mempunyai beberapa tag. Sila pastikan nama imej yang digunakan untuk menolak adalah: {0}',
|
||||||
imageDelete: 'Padam imej',
|
imageDelete: 'Padam imej',
|
||||||
imageTagDeleteHelper: 'Buang tag lain yang berkaitan dengan ID imej ini',
|
|
||||||
repoName: 'Pendaftaran kontena',
|
repoName: 'Pendaftaran kontena',
|
||||||
imageName: 'Nama imej',
|
imageName: 'Nama imej',
|
||||||
pull: 'Tarik',
|
pull: 'Tarik',
|
||||||
|
|
@ -886,6 +885,8 @@ const message = {
|
||||||
pathSelect: 'Laluan',
|
pathSelect: 'Laluan',
|
||||||
label: 'Label',
|
label: 'Label',
|
||||||
imageTag: 'Tag imej',
|
imageTag: 'Tag imej',
|
||||||
|
imageTagHelper:
|
||||||
|
'Menyokong penetapan berbilang tag imej, tekan Enter selepas memasukkan setiap tag untuk teruskan',
|
||||||
push: 'Tekan',
|
push: 'Tekan',
|
||||||
fileName: 'Nama fail',
|
fileName: 'Nama fail',
|
||||||
export: 'Eksport',
|
export: 'Eksport',
|
||||||
|
|
|
||||||
|
|
@ -870,7 +870,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'Detectado que esta imagem possui múltiplas tags. Por favor, confirme que o nome da imagem usada para push é: {0}',
|
'Detectado que esta imagem possui múltiplas tags. Por favor, confirme que o nome da imagem usada para push é: {0}',
|
||||||
imageDelete: 'Excluir imagem',
|
imageDelete: 'Excluir imagem',
|
||||||
imageTagDeleteHelper: 'Remover outras tags associadas a este ID de imagem',
|
|
||||||
repoName: 'Registro de contêiner',
|
repoName: 'Registro de contêiner',
|
||||||
imageName: 'Nome da imagem',
|
imageName: 'Nome da imagem',
|
||||||
pull: 'Puxar',
|
pull: 'Puxar',
|
||||||
|
|
@ -881,6 +880,8 @@ const message = {
|
||||||
pathSelect: 'Caminho',
|
pathSelect: 'Caminho',
|
||||||
label: 'Etiqueta',
|
label: 'Etiqueta',
|
||||||
imageTag: 'Tag de imagem',
|
imageTag: 'Tag de imagem',
|
||||||
|
imageTagHelper:
|
||||||
|
'Suporta definir múltiplas tags de imagem, pressione Enter após inserir cada tag para continuar',
|
||||||
push: 'Enviar',
|
push: 'Enviar',
|
||||||
fileName: 'Nome do arquivo',
|
fileName: 'Nome do arquivo',
|
||||||
export: 'Exportar',
|
export: 'Exportar',
|
||||||
|
|
|
||||||
|
|
@ -873,7 +873,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'Обнаружено, что у этого образа несколько тегов. Подтвердите, что имя образа, используемое для отправки: {0}',
|
'Обнаружено, что у этого образа несколько тегов. Подтвердите, что имя образа, используемое для отправки: {0}',
|
||||||
imageDelete: 'Удалить образ',
|
imageDelete: 'Удалить образ',
|
||||||
imageTagDeleteHelper: 'Удалить другие теги, связанные с этим ID образа',
|
|
||||||
repoName: 'Реестр контейнеров',
|
repoName: 'Реестр контейнеров',
|
||||||
imageName: 'Имя образа',
|
imageName: 'Имя образа',
|
||||||
pull: 'Загрузить',
|
pull: 'Загрузить',
|
||||||
|
|
@ -884,6 +883,8 @@ const message = {
|
||||||
pathSelect: 'Путь',
|
pathSelect: 'Путь',
|
||||||
label: 'Метка',
|
label: 'Метка',
|
||||||
imageTag: 'Тег образа',
|
imageTag: 'Тег образа',
|
||||||
|
imageTagHelper:
|
||||||
|
'Поддерживает установку нескольких тегов образов, нажмите Enter после ввода каждого тега для продолжения',
|
||||||
push: 'Отправить',
|
push: 'Отправить',
|
||||||
fileName: 'Имя файла',
|
fileName: 'Имя файла',
|
||||||
export: 'Экспорт',
|
export: 'Экспорт',
|
||||||
|
|
|
||||||
|
|
@ -891,7 +891,6 @@ const message = {
|
||||||
imagePushHelper:
|
imagePushHelper:
|
||||||
'Bu imgenin birden fazla etiketi olduğu tespit edildi. Lütfen gönderimde kullanılan imge adının şu olduğunu onaylayın: {0}',
|
'Bu imgenin birden fazla etiketi olduğu tespit edildi. Lütfen gönderimde kullanılan imge adının şu olduğunu onaylayın: {0}',
|
||||||
imageDelete: 'İmaj sil',
|
imageDelete: 'İmaj sil',
|
||||||
imageTagDeleteHelper: 'Bu imaj IDsi ile ilişkili diğer etiketleri kaldır',
|
|
||||||
repoName: 'Konteyner kayıt defteri',
|
repoName: 'Konteyner kayıt defteri',
|
||||||
imageName: 'İmaj adı',
|
imageName: 'İmaj adı',
|
||||||
pull: 'Çek',
|
pull: 'Çek',
|
||||||
|
|
@ -902,6 +901,8 @@ const message = {
|
||||||
pathSelect: 'Yol',
|
pathSelect: 'Yol',
|
||||||
label: 'Etiket',
|
label: 'Etiket',
|
||||||
imageTag: 'İmaj etiketi',
|
imageTag: 'İmaj etiketi',
|
||||||
|
imageTagHelper:
|
||||||
|
"Birden fazla görüntü etiketi ayarlamayı destekler, her etiket girdikten sonra Enter'a basarak devam edin",
|
||||||
push: 'Gönder',
|
push: 'Gönder',
|
||||||
fileName: 'Dosya adı',
|
fileName: 'Dosya adı',
|
||||||
export: 'Dışa aktar',
|
export: 'Dışa aktar',
|
||||||
|
|
|
||||||
|
|
@ -845,7 +845,6 @@ const message = {
|
||||||
imagePush: '推送鏡像',
|
imagePush: '推送鏡像',
|
||||||
imagePushHelper: '檢測到該映像存在多個標籤,請確認推送時使用的映像名稱為:{0}',
|
imagePushHelper: '檢測到該映像存在多個標籤,請確認推送時使用的映像名稱為:{0}',
|
||||||
imageDelete: '刪除鏡像',
|
imageDelete: '刪除鏡像',
|
||||||
imageTagDeleteHelper: '移除與該映像 ID 相關聯的其他標籤',
|
|
||||||
repoName: '倉庫名',
|
repoName: '倉庫名',
|
||||||
imageName: '鏡像名',
|
imageName: '鏡像名',
|
||||||
httpRepo: 'http 倉庫新增授信需要重啟 docker 服務',
|
httpRepo: 'http 倉庫新增授信需要重啟 docker 服務',
|
||||||
|
|
@ -859,6 +858,7 @@ const message = {
|
||||||
pathSelect: '路徑選擇',
|
pathSelect: '路徑選擇',
|
||||||
label: '標籤',
|
label: '標籤',
|
||||||
imageTag: '鏡像標籤',
|
imageTag: '鏡像標籤',
|
||||||
|
imageTagHelper: '支援設定多個映像標籤,輸入一個標籤後回車繼續',
|
||||||
push: '推送',
|
push: '推送',
|
||||||
fileName: '檔案名',
|
fileName: '檔案名',
|
||||||
export: '匯出',
|
export: '匯出',
|
||||||
|
|
|
||||||
|
|
@ -844,7 +844,6 @@ const message = {
|
||||||
imagePush: '推送镜像',
|
imagePush: '推送镜像',
|
||||||
imagePushHelper: '检测到该镜像存在多个标签,请确认推送时使用的镜像名称为:{0}',
|
imagePushHelper: '检测到该镜像存在多个标签,请确认推送时使用的镜像名称为:{0}',
|
||||||
imageDelete: '删除镜像',
|
imageDelete: '删除镜像',
|
||||||
imageTagDeleteHelper: '移除与该镜像 ID 相关联的其他标签',
|
|
||||||
repoName: '仓库名',
|
repoName: '仓库名',
|
||||||
imageName: '镜像名',
|
imageName: '镜像名',
|
||||||
httpRepo: 'http 仓库添加授信需要重启 docker 服务',
|
httpRepo: 'http 仓库添加授信需要重启 docker 服务',
|
||||||
|
|
@ -858,6 +857,7 @@ const message = {
|
||||||
pathSelect: '路径选择',
|
pathSelect: '路径选择',
|
||||||
label: '标签',
|
label: '标签',
|
||||||
imageTag: '镜像标签',
|
imageTag: '镜像标签',
|
||||||
|
imageTagHelper: '支持设置多个镜像 tag,输入一个 tag 后回车继续',
|
||||||
push: '推送',
|
push: '推送',
|
||||||
fileName: '文件名',
|
fileName: '文件名',
|
||||||
export: '导出',
|
export: '导出',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<DrawerPro v-model="drawerVisible" :header="$t('container.imageTag')" @close="handleClose" size="large">
|
<DrawerPro v-model="drawerVisible" :header="$t('container.imageTag')" @close="handleClose" size="large">
|
||||||
<el-form v-loading="loading" label-position="top" ref="formRef" :model="form" label-width="80px">
|
<el-form v-loading="loading" label-position="top" ref="formRef" :model="form" :rules="rules" label-width="80px">
|
||||||
<el-form-item :label="$t('app.source')">
|
<el-form-item :label="$t('app.source')">
|
||||||
<el-checkbox v-model="form.fromRepo">{{ $t('container.imageRepo') }}</el-checkbox>
|
<el-checkbox v-model="form.fromRepo">{{ $t('container.imageRepo') }}</el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -14,19 +14,15 @@
|
||||||
<el-option v-for="item in repos" :key="item.id" :value="item.name" :label="item.name" />
|
<el-option v-for="item in repos" :key="item.id" :value="item.name" :label="item.name" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('container.imageTag')" :rules="Rules.imageName" prop="targetName">
|
<el-form-item :label="$t('container.imageTag')" prop="tags">
|
||||||
<el-input v-model="form.targetName" />
|
<el-input-tag ref="inputTagRef" @add-tag="handleAdd" v-model="form.tags">
|
||||||
</el-form-item>
|
<template #tag="{ value }">
|
||||||
|
<el-button @click="setInputValue(value)" size="small" link type="info">
|
||||||
<el-form-item>
|
{{ value }}
|
||||||
<div class="w-full">
|
</el-button>
|
||||||
<el-checkbox v-model="form.deleteTag">
|
</template>
|
||||||
{{ $t('container.imageTagDeleteHelper') }}
|
</el-input-tag>
|
||||||
</el-checkbox>
|
<span class="input-help">{{ $t('container.imageTagHelper') }}</span>
|
||||||
</div>
|
|
||||||
<el-checkbox-group v-if="form.deleteTag" v-model="form.deleteTags">
|
|
||||||
<el-checkbox v-for="item in tags" :key="item" :value="item" :label="item" />
|
|
||||||
</el-checkbox-group>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
|
@ -48,25 +44,44 @@ import { reactive, ref } from 'vue';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElForm } from 'element-plus';
|
import { ElForm } from 'element-plus';
|
||||||
import { imageRemove, imageTag } from '@/api/modules/container';
|
import { imageTag } from '@/api/modules/container';
|
||||||
import { Container } from '@/api/interface/container';
|
import { Container } from '@/api/interface/container';
|
||||||
import { MsgSuccess } from '@/utils/message';
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const inputTagRef = ref();
|
||||||
|
|
||||||
const drawerVisible = ref(false);
|
const drawerVisible = ref(false);
|
||||||
const repos = ref();
|
const repos = ref();
|
||||||
const tags = ref();
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
imageID: '',
|
imageID: '',
|
||||||
fromRepo: false,
|
fromRepo: false,
|
||||||
repo: '',
|
repo: '',
|
||||||
originName: '',
|
originName: '',
|
||||||
targetName: '',
|
|
||||||
|
|
||||||
deleteTag: false,
|
tags: [],
|
||||||
deleteTags: [],
|
|
||||||
});
|
});
|
||||||
|
const rules = reactive({
|
||||||
|
tags: [{ validator: checkTags, trigger: 'blur', required: true }],
|
||||||
|
});
|
||||||
|
function checkTags(rule: any, value: any, callback: any) {
|
||||||
|
if (value.length === 0) {
|
||||||
|
return callback(new Error(i18n.global.t('commons.rule.requiredInput')));
|
||||||
|
}
|
||||||
|
for (const item of value) {
|
||||||
|
if (item === '' || typeof item === 'undefined' || item == null) {
|
||||||
|
return callback(new Error(i18n.global.t('commons.rule.imageName')));
|
||||||
|
} else {
|
||||||
|
const reg = /^[a-zA-Z0-9]{1}[a-z:@A-Z0-9_/.-]{0,255}$/;
|
||||||
|
if (!reg.test(item) && item !== '') {
|
||||||
|
return callback(new Error(i18n.global.t('commons.rule.imageName')));
|
||||||
|
} else {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
interface DialogProps {
|
interface DialogProps {
|
||||||
repos: Array<Container.RepoOptions>;
|
repos: Array<Container.RepoOptions>;
|
||||||
|
|
@ -78,13 +93,10 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||||
drawerVisible.value = true;
|
drawerVisible.value = true;
|
||||||
form.imageID = params.imageID;
|
form.imageID = params.imageID;
|
||||||
form.originName = params.tags?.length !== 0 ? params.tags[0] : '';
|
form.originName = params.tags?.length !== 0 ? params.tags[0] : '';
|
||||||
form.targetName = params.tags?.length !== 0 ? params.tags[0] : '';
|
form.tags = params.tags || [];
|
||||||
form.fromRepo = false;
|
form.fromRepo = false;
|
||||||
form.repo = '';
|
form.repo = '';
|
||||||
form.deleteTag = false;
|
|
||||||
form.deleteTags = [];
|
|
||||||
repos.value = params.repos;
|
repos.value = params.repos;
|
||||||
tags.value = params.tags;
|
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
|
|
@ -95,21 +107,33 @@ const handleClose = () => {
|
||||||
type FormInstance = InstanceType<typeof ElForm>;
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
const handleAdd = (val: string) => {
|
||||||
|
form.tags = form.tags?.filter((item) => item !== val);
|
||||||
|
form.tags.push(val);
|
||||||
|
};
|
||||||
|
const setInputValue = async (text) => {
|
||||||
|
await nextTick();
|
||||||
|
const inputEl = inputTagRef.value?.$el?.querySelector('input');
|
||||||
|
if (!inputEl) return;
|
||||||
|
|
||||||
|
inputEl.value = text;
|
||||||
|
inputEl.dispatchEvent(new Event('input', { bubbles: true }));
|
||||||
|
inputEl.dispatchEvent(new Event('change', { bubbles: true }));
|
||||||
|
inputEl.setSelectionRange(text.length, text.length);
|
||||||
|
};
|
||||||
|
|
||||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(async (valid) => {
|
formEl.validate(async (valid) => {
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
let params = {
|
let params = {
|
||||||
sourceID: form.imageID,
|
sourceID: form.imageID,
|
||||||
targetName: form.targetName,
|
tags: form.tags,
|
||||||
};
|
};
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await imageTag(params)
|
await imageTag(params)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
if (form.deleteTag && form.deleteTags.length !== 0) {
|
|
||||||
await imageRemove({ names: form.deleteTags });
|
|
||||||
}
|
|
||||||
drawerVisible.value = false;
|
drawerVisible.value = false;
|
||||||
emit('search');
|
emit('search');
|
||||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
|
@ -122,12 +146,11 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
|
|
||||||
const changeRepo = (val) => {
|
const changeRepo = (val) => {
|
||||||
if (val === 'Docker Hub') {
|
if (val === 'Docker Hub') {
|
||||||
form.targetName = form.originName;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const item of repos.value) {
|
for (const item of repos.value) {
|
||||||
if (item.name == val) {
|
if (item.name == val) {
|
||||||
form.targetName = item.downloadUrl + '/' + form.originName;
|
form.tags.push(item.downloadUrl + '/' + form.originName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue