88 @close =" visible = false"
99 >
1010 <template #content >
11- <el-form label-position =" top" >
11+ <el-form label-position =" top" @submit.prevent >
1212 <el-form-item >
13- <div class =" path-breadcrumb" >
13+ <div v-if = " !pathEditing " class =" path-breadcrumb" @click = " enablePathEditing " >
1414 <el-breadcrumb separator =" /" >
1515 <el-breadcrumb-item >
16- <el-link type =" primary" @click =" navigateToPath('/')" >
16+ <el-link type =" primary" @click.stop =" navigateToPath('/')" >
1717 <el-icon ><HomeFilled /></el-icon >
1818 </el-link >
1919 </el-breadcrumb-item >
2020 <el-breadcrumb-item v-for =" item in pathSegments" :key =" item.path" >
21- <el-link type =" primary" @click =" navigateToPath(item.path)" >
21+ <el-link type =" primary" @click.stop =" navigateToPath(item.path)" >
2222 {{ item.name }}
2323 </el-link >
2424 </el-breadcrumb-item >
2525 </el-breadcrumb >
2626 </div >
27+ <el-input
28+ v-else
29+ ref =" pathInputRef"
30+ v-model =" pathInput"
31+ class =" path-breadcrumb path-input"
32+ @blur =" cancelPathEditing"
33+ @keyup.enter.prevent =" submitPathInput"
34+ />
2735 <el-upload ref =" uploadRef" :auto-upload =" false" :show-file-list =" false" :on-change =" onUploadChange" >
2836 <el-button class =" mt-2" :loading =" uploading" type =" primary" plain >
2937 {{ $t('commons.button.upload') }}
103111</template >
104112
105113<script lang="ts" setup>
106- import { computed , ref } from ' vue' ;
114+ import { computed , nextTick , ref } from ' vue' ;
107115import {
108116 deleteContainerFile ,
109117 downloadContainerFile ,
@@ -114,7 +122,7 @@ import {
114122} from ' @/api/modules/container' ;
115123import { MsgError , MsgSuccess , MsgWarning } from ' @/utils/message' ;
116124import i18n from ' @/lang' ;
117- import { ElMessageBox , UploadFile , UploadInstance } from ' element-plus' ;
125+ import { ElInput , ElMessageBox , UploadFile , UploadInstance } from ' element-plus' ;
118126import { Document , FolderOpened , HomeFilled } from ' @element-plus/icons-vue' ;
119127import { computeSize2 } from ' @/utils/util' ;
120128
@@ -124,12 +132,15 @@ const containerID = ref('');
124132const filePath = ref (' /' );
125133const containerFiles = ref <any []>([]);
126134const uploadRef = ref <UploadInstance >();
135+ const pathInputRef = ref <InstanceType <typeof ElInput >>();
127136const uploading = ref (false );
128137const previewVisible = ref (false );
129138const previewTitle = ref (' ' );
130139const previewContent = ref (' ' );
131140const previewTruncated = ref (false );
132141const selectedRows = ref <any []>([]);
142+ const pathEditing = ref (false );
143+ const pathInput = ref (' /' );
133144const pathSegments = computed (() => {
134145 const parts = filePath .value .split (' /' ).filter ((item ) => item );
135146 return parts .map ((name , index ) => ({
@@ -149,16 +160,18 @@ const acceptParams = async (params: DrawerProps): Promise<void> => {
149160 containerID .value = params .containerID ;
150161 title .value = params .title ;
151162 filePath .value = params .workingDir || ' /' ;
163+ pathInput .value = filePath .value ;
164+ pathEditing .value = false ;
152165 await loadContainerFiles ();
153166};
154167
155- const loadContainerFiles = async () => {
156- if (! containerID .value || ! filePath . value ) {
157- return ;
168+ const fetchContainerFiles = async (path : string ) => {
169+ if (! containerID .value || ! path ) {
170+ return false ;
158171 }
159- await listContainerFiles ({
172+ return await listContainerFiles ({
160173 containerID: containerID .value ,
161- path: filePath . value ,
174+ path ,
162175 })
163176 .then ((res ) => {
164177 containerFiles .value = (res .data || []).map ((item ) => ({
@@ -167,22 +180,80 @@ const loadContainerFiles = async () => {
167180 sizeLoading: false ,
168181 }));
169182 selectedRows .value = [];
183+ return true ;
170184 })
171185 .catch (() => {
172186 containerFiles .value = [];
187+ return false ;
173188 });
174189};
175190
191+ const loadContainerFiles = async () => {
192+ await fetchContainerFiles (filePath .value );
193+ };
194+
176195const enterDir = async (path : string ) => {
177196 filePath .value = path ;
178197 await loadContainerFiles ();
179198};
180199
181200const navigateToPath = async (path : string ) => {
182201 filePath .value = path || ' /' ;
202+ pathInput .value = filePath .value ;
203+ pathEditing .value = false ;
183204 await loadContainerFiles ();
184205};
185206
207+ const getParentPath = (path : string ) => {
208+ if (! path || path === ' /' ) {
209+ return ' /' ;
210+ }
211+ const segments = path .split (' /' ).filter ((item ) => item );
212+ if (segments .length <= 1 ) {
213+ return ' /' ;
214+ }
215+ return ' /' + segments .slice (0 , - 1 ).join (' /' );
216+ };
217+
218+ const enablePathEditing = async () => {
219+ pathInput .value = filePath .value || ' /' ;
220+ pathEditing .value = true ;
221+ await nextTick ();
222+ pathInputRef .value ?.focus ();
223+ };
224+
225+ const cancelPathEditing = () => {
226+ pathEditing .value = false ;
227+ pathInput .value = filePath .value || ' /' ;
228+ };
229+
230+ const submitPathInput = async () => {
231+ let targetPath = (pathInput .value || ' ' ).trim ();
232+ if (! targetPath ) {
233+ targetPath = ' /' ;
234+ }
235+ if (! targetPath .startsWith (' /' )) {
236+ targetPath = ' /' + targetPath ;
237+ }
238+ let currentPath = targetPath ;
239+ while (true ) {
240+ const success = await fetchContainerFiles (currentPath );
241+ if (success ) {
242+ filePath .value = currentPath ;
243+ pathInput .value = currentPath ;
244+ pathEditing .value = false ;
245+ return ;
246+ }
247+ if (currentPath === ' /' ) {
248+ filePath .value = ' /' ;
249+ pathInput .value = ' /' ;
250+ pathEditing .value = false ;
251+ return ;
252+ }
253+ currentPath = getParentPath (currentPath );
254+ }
255+ };
256+
186257const onUploadChange = async (uploadFile : UploadFile ) => {
187258 if (! uploadFile .raw ) {
188259 return ;
@@ -331,6 +402,11 @@ defineExpose({
331402 border : 1px solid var (--el-border-color );
332403 border-radius : 4px ;
333404 overflow-x : auto ;
405+ cursor : text ;
406+ }
407+
408+ .path-input {
409+ overflow : visible ;
334410}
335411
336412.preview-content {
0 commit comments