feat: F6 Move functionaliteit aangepast
This commit is contained in:
@@ -0,0 +1,189 @@
|
|||||||
|
# UI_F6_PURE_MOVE_V1
|
||||||
|
|
||||||
|
## 1. Doel
|
||||||
|
|
||||||
|
`F6` moet in de UI een expliciete pure `Move`-actie worden.
|
||||||
|
|
||||||
|
Waarom:
|
||||||
|
- `F2` heeft nu een eigen rename-flow
|
||||||
|
- daarmee is de oorspronkelijke gecombineerde `Rename/Move`-semantiek in de UI niet meer nodig
|
||||||
|
- een pure `Move`-flow maakt de functietoetsen voorspelbaarder:
|
||||||
|
- `F2 = Rename`
|
||||||
|
- `F6 = Move`
|
||||||
|
- dit sluit beter aan op klassieke file-manager verwachtingen en vermindert cognitieve ruis in de popup-flow
|
||||||
|
|
||||||
|
Belangrijk bestaande context:
|
||||||
|
- move-functionaliteit bestaat backendmatig al
|
||||||
|
- move-functionaliteit bestaat UI-matig al
|
||||||
|
- file move, directory move binnen huidige scope en batch move binnen huidige scope werken al
|
||||||
|
- deze stap gaat dus niet over nieuwe move-capaciteit, maar over het vereenvoudigen van de UI-flow rond de bestaande move-actie
|
||||||
|
|
||||||
|
## 2. Scope
|
||||||
|
|
||||||
|
De pure `Move`-flow in v1 moet de bestaande move-scope UI-matig netjes afdekken voor zover die al ondersteund wordt.
|
||||||
|
|
||||||
|
In scope:
|
||||||
|
- exact 1 file
|
||||||
|
- exact 1 directory
|
||||||
|
- meerdere files
|
||||||
|
- meerdere directories
|
||||||
|
- gemengde selectie van files + directories
|
||||||
|
|
||||||
|
Voorwaarde:
|
||||||
|
- alleen binnen de bestaande huidige move-scope
|
||||||
|
- alles wat backendmatig al geblokkeerd is, blijft geblokkeerd
|
||||||
|
- de UI mag dat duidelijker presenteren, maar mag de scope niet verbreden
|
||||||
|
|
||||||
|
Niet in scope:
|
||||||
|
- nieuwe backend move-capaciteit
|
||||||
|
- nieuwe tasksemantiek
|
||||||
|
- nieuwe batch-semantieken buiten de bestaande backend
|
||||||
|
- rename binnen `F6`
|
||||||
|
|
||||||
|
## 3. Gewenst gedrag
|
||||||
|
|
||||||
|
`F6` en de `Move`-knop moeten exact dezelfde frontendflow gebruiken.
|
||||||
|
|
||||||
|
Kernregel:
|
||||||
|
- `F6` keyboard shortcut = pure move-flow
|
||||||
|
- `Move`-knop in functiebalk = exact dezelfde pure move-flow
|
||||||
|
- beide gebruiken dezelfde centrale frontendhandler
|
||||||
|
|
||||||
|
Popupregel:
|
||||||
|
- de bestaande move-popup wordt een pure move-popup
|
||||||
|
- geen rename-invoerveld in deze flow
|
||||||
|
- geen naamwijzigingssemantiek in deze flow
|
||||||
|
- de popup richt zich alleen op doelpad of doelmap voor verplaatsen
|
||||||
|
|
||||||
|
Interactie:
|
||||||
|
- `Enter` bevestigt
|
||||||
|
- `Escape` annuleert
|
||||||
|
- `X` sluit popup
|
||||||
|
|
||||||
|
Gedragslijn per context:
|
||||||
|
- exact 1 item: popup toont expliciete move-context voor dat item
|
||||||
|
- meerdere items: popup toont batch move-context
|
||||||
|
- popuptekst en labels moeten spreken in termen van `Move`, niet `Rename/Move`
|
||||||
|
|
||||||
|
## 4. Relatie met bestaande move-scope
|
||||||
|
|
||||||
|
Wat al bestaat en alleen hergebruikt moet worden:
|
||||||
|
- single file move
|
||||||
|
- single directory move binnen de huidige scope
|
||||||
|
- batch move binnen de huidige scope
|
||||||
|
- task-based move
|
||||||
|
- bestaande validaties en blokkades
|
||||||
|
|
||||||
|
Dat betekent:
|
||||||
|
- de pure `Move`-popup hoeft geen nieuwe backendbeslissingen te nemen
|
||||||
|
- de frontend mag alleen een duidelijkere presentatie en dispatchlaag geven
|
||||||
|
- validatiefouten zoals cross-root blokkades, subtree-blokkades, mixed-root blokkades en bestaande destination-conflicten blijven door de bestaande backend en bestaande UI-validatie worden afgevangen
|
||||||
|
|
||||||
|
Pragmatische consequentie:
|
||||||
|
- de move-popup moet vooral destination-gericht zijn
|
||||||
|
- submit moet direct de bestaande move-logica aanroepen
|
||||||
|
- geen impliciete keuze meer tussen rename en move in deze flow
|
||||||
|
|
||||||
|
## 5. Relatie met F2 Rename
|
||||||
|
|
||||||
|
Na invoering van pure `F6 Move` geldt:
|
||||||
|
- `F2` blijft exclusief voor rename
|
||||||
|
- `Rename`-knop blijft exclusief voor rename
|
||||||
|
- `F6` wordt exclusief voor move
|
||||||
|
- `Move`-knop wordt exclusief voor move
|
||||||
|
|
||||||
|
Belangrijk ontwerpprincipe:
|
||||||
|
- geen gedeelde rename/move-popup meer
|
||||||
|
- `F2` en `F6` krijgen elk een eigen, semantisch heldere popupflow
|
||||||
|
- dit maakt toekomstige onderhoud en UX-consistentie eenvoudiger
|
||||||
|
|
||||||
|
## 6. UI-semantiek
|
||||||
|
|
||||||
|
### Welke contextinformatie is nuttig
|
||||||
|
|
||||||
|
Voor een pure move-popup is nuttig:
|
||||||
|
- broninformatie: welk item of hoeveel items geselecteerd zijn
|
||||||
|
- destination-informatie: waarheen wordt verplaatst
|
||||||
|
- bij batch move: doelmap in plaats van volledig doelpad per item
|
||||||
|
|
||||||
|
### Default destination
|
||||||
|
|
||||||
|
Aanbevolen defaultvoorstel:
|
||||||
|
- gebruik het current path van het inactieve paneel als destination-basis
|
||||||
|
|
||||||
|
Voor exact 1 item:
|
||||||
|
- toon een destination pad of destination map duidelijk, afhankelijk van de bestaande implementatierichting
|
||||||
|
- aanbevolen: toon volledig destination path, vooraf ingevuld op basis van het inactieve paneel + itemnaam
|
||||||
|
- dit houdt aan bij de bestaande move-aanroepsemantiek voor single-item move
|
||||||
|
|
||||||
|
Voor batch move:
|
||||||
|
- toon aantal geselecteerde items
|
||||||
|
- toon doelmap = current path van het inactieve paneel
|
||||||
|
- geen rename-achtige tekst of naamveld per item
|
||||||
|
|
||||||
|
### Foutmeldingen en blokkades
|
||||||
|
|
||||||
|
Compact tonen in de popup of bestaande errorzone:
|
||||||
|
- destination exists
|
||||||
|
- mixed roots not allowed
|
||||||
|
- destination inside source not allowed
|
||||||
|
- cross-root directory move not supported
|
||||||
|
- andere bestaande backendfouten
|
||||||
|
|
||||||
|
Belangrijk:
|
||||||
|
- foutmeldingen moeten move-gericht geformuleerd zijn
|
||||||
|
- geen verwijzing naar rename of gecombineerde semantiek
|
||||||
|
|
||||||
|
## 7. Regressierisico
|
||||||
|
|
||||||
|
Belangrijkste risico's:
|
||||||
|
- per ongeluk opnieuw bouwen van bestaande move-functionaliteit in plaats van die te hergebruiken
|
||||||
|
- verwarring tussen oude gecombineerde popup en nieuwe pure move-popup
|
||||||
|
- inconsistente keyboard- en knopwiring tussen `F6` en `Move`
|
||||||
|
- onbedoelde impact op de al werkende `F2 Rename`-flow
|
||||||
|
|
||||||
|
Mitigatie:
|
||||||
|
- `F6` en `Move` één centrale pure move-handler laten delen
|
||||||
|
- bestaande backend move-calls intact laten
|
||||||
|
- `F2` volledig gescheiden houden
|
||||||
|
- popup-tekst en labels expliciet move-only maken
|
||||||
|
- geen backendwijzigingen in deze stap
|
||||||
|
|
||||||
|
## 8. Teststrategie
|
||||||
|
|
||||||
|
UI smoke/regressietests:
|
||||||
|
- functiebalk bevat `Move` met `F6`
|
||||||
|
- `F6` wiring blijft aanwezig
|
||||||
|
- `Move`-knop gebruikt dezelfde handler als `F6`
|
||||||
|
- move-popupcontainer aanwezig en move-only geëtiketteerd
|
||||||
|
- rename-popup blijft apart aanwezig voor `F2`
|
||||||
|
|
||||||
|
Handmatige validatie:
|
||||||
|
- exact 1 file -> `F6` opent pure move-popup
|
||||||
|
- exact 1 directory -> `F6` opent pure move-popup binnen huidige scope
|
||||||
|
- meerdere files -> batch move-popup blijft logisch werken
|
||||||
|
- meerdere directories -> batch move-popup blijft logisch werken binnen huidige scope
|
||||||
|
- gemengde selectie -> bestaande batch move-scope en blokkades blijven correct
|
||||||
|
- `F2 Rename` blijft volledig los en ongewijzigd
|
||||||
|
|
||||||
|
Bestaande regressies die bewaakt moeten blijven:
|
||||||
|
- single file move same-root
|
||||||
|
- single file move cross-root
|
||||||
|
- single directory move binnen huidige scope
|
||||||
|
- batch move file-only
|
||||||
|
- batch move met directories binnen huidige scope
|
||||||
|
- blokkades voor mixed roots, subtree en symlink source
|
||||||
|
|
||||||
|
## 9. Aanbeveling
|
||||||
|
|
||||||
|
Aanbevolen v1-richting met laag regressierisico:
|
||||||
|
- maak `F6` en `Move` UI-semantisch puur move-only
|
||||||
|
- verwijder rename-semantiek uit de `F6`-popupflow
|
||||||
|
- behoud en hergebruik alle bestaande move-logica, validaties en backendcalls
|
||||||
|
- houd `F2 Rename` volledig apart
|
||||||
|
|
||||||
|
Waarom dit de veiligste richting is:
|
||||||
|
- maximale herbruik van bestaande backend en UI-logica
|
||||||
|
- minimale semantische overlap tussen `Rename` en `Move`
|
||||||
|
- duidelijkere functietoetsbetekenis
|
||||||
|
- laag regressierisico omdat de verandering vooral UI-opschoning is, geen capability-uitbreiding
|
||||||
Binary file not shown.
Binary file not shown.
@@ -62,8 +62,10 @@ class UiSmokeGoldenTest(unittest.TestCase):
|
|||||||
self.assertIn('id="editor-content"', body)
|
self.assertIn('id="editor-content"', body)
|
||||||
self.assertIn('id="editor-save-btn"', body)
|
self.assertIn('id="editor-save-btn"', body)
|
||||||
self.assertIn('id="editor-cancel-btn"', body)
|
self.assertIn('id="editor-cancel-btn"', body)
|
||||||
self.assertIn('id="rename-move-popup"', body)
|
self.assertIn('id="move-popup"', body)
|
||||||
self.assertIn('id="rename-move-input"', body)
|
self.assertIn('id="move-input"', body)
|
||||||
|
self.assertIn(">Move</h3>", body)
|
||||||
|
self.assertIn(">Target path</label>", body)
|
||||||
self.assertIn('id="batch-move-popup"', body)
|
self.assertIn('id="batch-move-popup"', body)
|
||||||
self.assertIn('id="batch-move-apply-btn"', body)
|
self.assertIn('id="batch-move-apply-btn"', body)
|
||||||
self.assertIn('id="mkdir-btn"', body)
|
self.assertIn('id="mkdir-btn"', body)
|
||||||
@@ -108,6 +110,8 @@ class UiSmokeGoldenTest(unittest.TestCase):
|
|||||||
self.assertIn('function openRenamePopup()', app_js)
|
self.assertIn('function openRenamePopup()', app_js)
|
||||||
self.assertIn('document.getElementById("rename-btn").onclick = openRenamePopup;', app_js)
|
self.assertIn('document.getElementById("rename-btn").onclick = openRenamePopup;', app_js)
|
||||||
self.assertIn('return triggerActionButton("rename-btn");', app_js)
|
self.assertIn('return triggerActionButton("rename-btn");', app_js)
|
||||||
|
self.assertIn('function openMovePopup()', app_js)
|
||||||
|
self.assertIn('document.getElementById("move-btn").onclick = openF6Flow;', app_js)
|
||||||
self.assertIn('await apiRequest("GET", "/api/history")', app_js)
|
self.assertIn('await apiRequest("GET", "/api/history")', app_js)
|
||||||
self.assertIn('Cross-root directory move is not supported in v1', app_js)
|
self.assertIn('Cross-root directory move is not supported in v1', app_js)
|
||||||
self.assertIn('Batch directory move is not supported in v1', app_js)
|
self.assertIn('Batch directory move is not supported in v1', app_js)
|
||||||
|
|||||||
+39
-50
@@ -30,7 +30,7 @@ let editorState = {
|
|||||||
originalContent: "",
|
originalContent: "",
|
||||||
modified: null,
|
modified: null,
|
||||||
};
|
};
|
||||||
let renameMoveState = {
|
let moveState = {
|
||||||
source: null,
|
source: null,
|
||||||
destination: "",
|
destination: "",
|
||||||
};
|
};
|
||||||
@@ -140,14 +140,15 @@ function editorElements() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function renameMoveElements() {
|
function moveElements() {
|
||||||
return {
|
return {
|
||||||
overlay: document.getElementById("rename-move-popup"),
|
overlay: document.getElementById("move-popup"),
|
||||||
source: document.getElementById("rename-move-source"),
|
source: document.getElementById("move-source"),
|
||||||
input: document.getElementById("rename-move-input"),
|
input: document.getElementById("move-input"),
|
||||||
error: document.getElementById("rename-move-error"),
|
error: document.getElementById("move-error"),
|
||||||
applyButton: document.getElementById("rename-move-apply-btn"),
|
applyButton: document.getElementById("move-apply-btn"),
|
||||||
cancelButton: document.getElementById("rename-move-cancel-btn"),
|
cancelButton: document.getElementById("move-cancel-btn"),
|
||||||
|
closeButton: document.getElementById("move-close-btn"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1002,8 +1003,8 @@ function isWildcardPopupOpen() {
|
|||||||
return !wildcardPopupElements().overlay.classList.contains("hidden");
|
return !wildcardPopupElements().overlay.classList.contains("hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRenameMovePopupOpen() {
|
function isMovePopupOpen() {
|
||||||
return !renameMoveElements().overlay.classList.contains("hidden");
|
return !moveElements().overlay.classList.contains("hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isRenamePopupOpen() {
|
function isRenamePopupOpen() {
|
||||||
@@ -1088,8 +1089,8 @@ function showBatchDirectoryMoveNotSupported() {
|
|||||||
setStatus(message);
|
setStatus(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetRenameMoveState() {
|
function resetMoveState() {
|
||||||
renameMoveState = {
|
moveState = {
|
||||||
source: null,
|
source: null,
|
||||||
destination: "",
|
destination: "",
|
||||||
};
|
};
|
||||||
@@ -1134,12 +1135,12 @@ function resetBatchMoveState() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeRenameMovePopup() {
|
function closeMovePopup() {
|
||||||
const elements = renameMoveElements();
|
const elements = moveElements();
|
||||||
elements.overlay.classList.add("hidden");
|
elements.overlay.classList.add("hidden");
|
||||||
elements.error.textContent = "";
|
elements.error.textContent = "";
|
||||||
elements.input.value = "";
|
elements.input.value = "";
|
||||||
resetRenameMoveState();
|
resetMoveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeBatchMovePopup() {
|
function closeBatchMovePopup() {
|
||||||
@@ -1149,16 +1150,16 @@ function closeBatchMovePopup() {
|
|||||||
resetBatchMoveState();
|
resetBatchMoveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRenameMovePopup() {
|
function openMovePopup() {
|
||||||
const selectedItems = activePaneState().selectedItems;
|
const selectedItems = activePaneState().selectedItems;
|
||||||
if (selectedItems.length !== 1) {
|
if (selectedItems.length !== 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const source = selectedItems[0];
|
const source = selectedItems[0];
|
||||||
const destination = defaultDestination(source.path, paneState(otherPane(state.activePane)).currentPath);
|
const destination = defaultDestination(source.path, paneState(otherPane(state.activePane)).currentPath);
|
||||||
const elements = renameMoveElements();
|
const elements = moveElements();
|
||||||
renameMoveState.source = source;
|
moveState.source = source;
|
||||||
renameMoveState.destination = destination;
|
moveState.destination = destination;
|
||||||
elements.source.textContent = `Source: ${source.path}`;
|
elements.source.textContent = `Source: ${source.path}`;
|
||||||
elements.input.value = destination;
|
elements.input.value = destination;
|
||||||
elements.error.textContent = "";
|
elements.error.textContent = "";
|
||||||
@@ -1190,7 +1191,7 @@ function openF6Flow() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (selectedItems.length === 1) {
|
if (selectedItems.length === 1) {
|
||||||
return openRenameMovePopup();
|
return openMovePopup();
|
||||||
}
|
}
|
||||||
if (selectedItems.some((item) => item.kind !== "file")) {
|
if (selectedItems.some((item) => item.kind !== "file")) {
|
||||||
const roots = uniqueRootKeysForItems(selectedItems);
|
const roots = uniqueRootKeysForItems(selectedItems);
|
||||||
@@ -1244,20 +1245,19 @@ async function submitRenamePopup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function submitRenameMovePopup() {
|
async function submitMovePopup() {
|
||||||
const elements = renameMoveElements();
|
const elements = moveElements();
|
||||||
const source = renameMoveState.source;
|
const source = moveState.source;
|
||||||
if (!source) {
|
if (!source) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const destination = elements.input.value.trim();
|
const destination = elements.input.value.trim();
|
||||||
const sourceParent = currentParentPath(source.path);
|
const sourceParent = currentParentPath(source.path);
|
||||||
const destinationParent = currentParentPath(destination);
|
const destinationParent = currentParentPath(destination);
|
||||||
const destinationName = baseName(destination);
|
|
||||||
|
|
||||||
elements.error.textContent = "";
|
elements.error.textContent = "";
|
||||||
if (!destination) {
|
if (!destination) {
|
||||||
elements.error.textContent = "Destination path is required";
|
elements.error.textContent = "Target path is required";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (destination === source.path) {
|
if (destination === source.path) {
|
||||||
@@ -1278,25 +1278,13 @@ async function submitRenameMovePopup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (destinationParent === sourceParent) {
|
|
||||||
await apiRequest("POST", "/api/files/rename", {
|
|
||||||
path: source.path,
|
|
||||||
new_name: destinationName,
|
|
||||||
});
|
|
||||||
closeRenameMovePopup();
|
|
||||||
setSelectedItem(state.activePane, null);
|
|
||||||
await loadBrowsePane(state.activePane);
|
|
||||||
setStatus(`Renamed ${source.path}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await apiRequest("POST", "/api/files/move", {
|
const result = await apiRequest("POST", "/api/files/move", {
|
||||||
source: source.path,
|
source: source.path,
|
||||||
destination,
|
destination,
|
||||||
});
|
});
|
||||||
state.selectedTaskId = result.task_id;
|
state.selectedTaskId = result.task_id;
|
||||||
await refreshTasksSnapshot();
|
await refreshTasksSnapshot();
|
||||||
closeRenameMovePopup();
|
closeMovePopup();
|
||||||
setSelectedItem(state.activePane, null);
|
setSelectedItem(state.activePane, null);
|
||||||
await Promise.all([loadBrowsePane("left"), loadBrowsePane("right")]);
|
await Promise.all([loadBrowsePane("left"), loadBrowsePane("right")]);
|
||||||
setStatus(`Move: 1 success, 0 failed`);
|
setStatus(`Move: 1 success, 0 failed`);
|
||||||
@@ -1656,15 +1644,15 @@ function handleKeyboardShortcuts(event) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isRenameMovePopupOpen()) {
|
if (isMovePopupOpen()) {
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
closeRenameMovePopup();
|
closeMovePopup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
submitRenameMovePopup();
|
submitMovePopup();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1842,23 +1830,24 @@ function setupEvents() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renameMove = renameMoveElements();
|
const move = moveElements();
|
||||||
renameMove.cancelButton.onclick = closeRenameMovePopup;
|
move.closeButton.onclick = closeMovePopup;
|
||||||
renameMove.applyButton.onclick = submitRenameMovePopup;
|
move.cancelButton.onclick = closeMovePopup;
|
||||||
renameMove.input.onkeydown = (event) => {
|
move.applyButton.onclick = submitMovePopup;
|
||||||
|
move.input.onkeydown = (event) => {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
submitRenameMovePopup();
|
submitMovePopup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
closeRenameMovePopup();
|
closeMovePopup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
renameMove.overlay.onclick = (event) => {
|
move.overlay.onclick = (event) => {
|
||||||
if (event.target === renameMove.overlay) {
|
if (event.target === move.overlay) {
|
||||||
closeRenameMovePopup();
|
closeMovePopup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -113,16 +113,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="rename-move-popup" class="popup-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="rename-move-title">
|
<div id="move-popup" class="popup-overlay hidden" role="dialog" aria-modal="true" aria-labelledby="move-title">
|
||||||
<div class="popup-card">
|
<div class="popup-card">
|
||||||
<h3 id="rename-move-title">Rename/Move</h3>
|
<button id="move-close-btn" class="viewer-close" type="button" aria-label="Close move">X</button>
|
||||||
<div id="rename-move-source" class="popup-meta"></div>
|
<h3 id="move-title">Move</h3>
|
||||||
<label for="rename-move-input" class="popup-label">Destination path</label>
|
<div id="move-source" class="popup-meta"></div>
|
||||||
<input id="rename-move-input" type="text" autocomplete="off">
|
<label for="move-input" class="popup-label">Target path</label>
|
||||||
<div id="rename-move-error" class="error"></div>
|
<input id="move-input" type="text" autocomplete="off">
|
||||||
|
<div id="move-error" class="error"></div>
|
||||||
<div class="popup-actions">
|
<div class="popup-actions">
|
||||||
<button id="rename-move-apply-btn" type="button">OK</button>
|
<button id="move-apply-btn" type="button">Move</button>
|
||||||
<button id="rename-move-cancel-btn" type="button">Cancel</button>
|
<button id="move-cancel-btn" type="button">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -484,13 +484,14 @@ button:disabled {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#wildcard-pattern-input,
|
#wildcard-pattern-input,
|
||||||
#rename-move-input {
|
#move-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#rename-popup .popup-card {
|
#rename-popup .popup-card,
|
||||||
|
#move-popup .popup-card {
|
||||||
width: min(520px, calc(100vw - 28px));
|
width: min(520px, calc(100vw - 28px));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user