Add folder mapping status indicator to task list
Add account label to folder mapping modal Update folder mapping logic to include destination login
This commit is contained in:
@@ -797,6 +797,16 @@ table.tbl a.rowlink:hover {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* Marks accounts whose folders have already been mapped/excluded. */
|
||||
.map-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
flex: none;
|
||||
background: var(--ok);
|
||||
box-shadow: 0 0 5px var(--ok);
|
||||
}
|
||||
|
||||
.empty-row td {
|
||||
text-align: center;
|
||||
color: var(--fg-faint);
|
||||
|
||||
@@ -7,6 +7,7 @@ type Props = {
|
||||
dstFolders: string[]
|
||||
initialMapping: Record<string, string>
|
||||
initialExcluded: string[]
|
||||
accountLabel?: string
|
||||
onConfirm: (mapping: Record<string, string>, excluded: string[]) => void
|
||||
onCancel: () => void
|
||||
}
|
||||
@@ -20,7 +21,7 @@ function defaultDst(src: string, dstFolders: string[], initial: Record<string, s
|
||||
}
|
||||
|
||||
export function FolderMappingModal({
|
||||
open, srcFolders, dstFolders, initialMapping, initialExcluded, onConfirm, onCancel,
|
||||
open, srcFolders, dstFolders, initialMapping, initialExcluded, accountLabel, onConfirm, onCancel,
|
||||
}: Props) {
|
||||
const [choice, setChoice] = useState<Record<string, string>>({})
|
||||
const [synced, setSynced] = useState<Record<string, boolean>>(() => {
|
||||
@@ -58,7 +59,12 @@ export function FolderMappingModal({
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={open} title="Map folders (source → destination)" onClose={onCancel} size="lg">
|
||||
<Modal
|
||||
open={open}
|
||||
title={accountLabel ? `Map folders — ${accountLabel}` : 'Map folders (source → destination)'}
|
||||
onClose={onCancel}
|
||||
size="lg"
|
||||
>
|
||||
<div className="map-body">
|
||||
<p className="map-hint">
|
||||
Route each source folder to an existing destination folder. Leaving a folder mapped to its own name
|
||||
|
||||
@@ -79,6 +79,7 @@ export function TaskDetail({ id }: { id: number }) {
|
||||
const [mapState, setMapState] = useState<{ src: string[]; dst: string[]; creds: typeof emptyAccount } | null>(null)
|
||||
const [editMap, setEditMap] = useState<{
|
||||
accId: number
|
||||
label: string
|
||||
src: string[]
|
||||
dst: string[]
|
||||
mapping: Record<string, string>
|
||||
@@ -214,7 +215,7 @@ export function TaskDetail({ id }: { id: number }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function onEditFolders(a: { id: number; src_login: string; folder_mapping?: Record<string, string>; excluded_folders?: string[] }) {
|
||||
async function onEditFolders(a: { id: number; src_login: string; dst_login: string; folder_mapping?: Record<string, string>; excluded_folders?: string[] }) {
|
||||
setBusy('probe')
|
||||
setError(null)
|
||||
try {
|
||||
@@ -228,6 +229,7 @@ export function TaskDetail({ id }: { id: number }) {
|
||||
}
|
||||
setEditMap({
|
||||
accId: a.id,
|
||||
label: a.dst_login && a.dst_login !== a.src_login ? `${a.src_login} → ${a.dst_login}` : a.src_login,
|
||||
src: res.src.folders ?? [],
|
||||
dst: res.dst.folders ?? [],
|
||||
mapping: a.folder_mapping ?? {},
|
||||
@@ -629,6 +631,18 @@ export function TaskDetail({ id }: { id: number }) {
|
||||
</td>
|
||||
<td className="num-cell">
|
||||
<div className="row-actions">
|
||||
{(() => {
|
||||
const mapped =
|
||||
Object.keys(a.folder_mapping ?? {}).length > 0 ||
|
||||
(a.excluded_folders?.length ?? 0) > 0
|
||||
return mapped ? (
|
||||
<span
|
||||
className="map-dot"
|
||||
title="Folders already mapped for this account"
|
||||
aria-label="Folders mapped"
|
||||
/>
|
||||
) : null
|
||||
})()}
|
||||
{a.status !== 'running' && data?.task.status !== 'running' && (
|
||||
<button
|
||||
type="button"
|
||||
@@ -671,6 +685,11 @@ export function TaskDetail({ id }: { id: number }) {
|
||||
dstFolders={mapState.dst}
|
||||
initialMapping={task.folder_mapping ?? {}}
|
||||
initialExcluded={[]}
|
||||
accountLabel={
|
||||
mapState.creds.dst_login && mapState.creds.dst_login !== mapState.creds.src_login
|
||||
? `${mapState.creds.src_login} → ${mapState.creds.dst_login}`
|
||||
: mapState.creds.src_login
|
||||
}
|
||||
onCancel={() => setMapState(null)}
|
||||
onConfirm={confirmMapping}
|
||||
/>
|
||||
@@ -683,6 +702,7 @@ export function TaskDetail({ id }: { id: number }) {
|
||||
dstFolders={editMap.dst}
|
||||
initialMapping={editMap.mapping}
|
||||
initialExcluded={editMap.excluded}
|
||||
accountLabel={editMap.label}
|
||||
onCancel={() => setEditMap(null)}
|
||||
onConfirm={saveEditMapping}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user