bug fixes galore
This commit is contained in:
+1
-1
@@ -110,7 +110,7 @@ export function groupByCategory(
|
||||
const category = getFlagCategory(k, allFlags)
|
||||
if (!category) continue
|
||||
if (category.category.startsWith('serve.')) {
|
||||
const serveType = category.category.slice(5) as (typeof SERVE_TYPES)[number]
|
||||
const serveType = category.category.slice(6) as (typeof SERVE_TYPES)[number]
|
||||
collectedFlags.serve[serveType] = {
|
||||
...collectedFlags.serve[serveType],
|
||||
[k]: v,
|
||||
|
||||
@@ -6,6 +6,8 @@ const RE_LOCAL_WINDOWS_PATH = /^:local:([a-zA-Z]:\/?.*)$/
|
||||
const RE_PATH_SEPARATOR = /[/\\]/
|
||||
|
||||
export function formatBytes(bytes: number) {
|
||||
if (!Number.isFinite(bytes)) return '0 B'
|
||||
|
||||
if (bytes < 1024) {
|
||||
return `${Math.round(bytes)} B`
|
||||
}
|
||||
|
||||
+10
-12
@@ -50,18 +50,16 @@ export function useFlags() {
|
||||
|
||||
const serveFlags = SERVE_TYPES.reduce(
|
||||
(acc, type) => {
|
||||
acc[type] =
|
||||
allFlags?.[type] ||
|
||||
[]
|
||||
.map((flag: any) => ({
|
||||
...flag,
|
||||
FieldName: flag.Name,
|
||||
DefaultStr:
|
||||
flag.Name === 'addr'
|
||||
? flag.DefaultStr.replace('[', '').replace(']', '')
|
||||
: flag.DefaultStr,
|
||||
}))
|
||||
.sort((a: any, b: any) => a.Name.localeCompare(b.Name))
|
||||
acc[type] = (allFlags?.[type] || [])
|
||||
.map((flag: any) => ({
|
||||
...flag,
|
||||
FieldName: flag.Name,
|
||||
DefaultStr:
|
||||
flag.Name === 'addr'
|
||||
? flag.DefaultStr.replace('[', '').replace(']', '')
|
||||
: flag.DefaultStr,
|
||||
}))
|
||||
.sort((a: any, b: any) => a.Name.localeCompare(b.Name))
|
||||
return acc
|
||||
},
|
||||
{} as Record<(typeof SERVE_TYPES)[number], any[]>
|
||||
|
||||
+3
-3
@@ -892,7 +892,7 @@ export async function startBisync({
|
||||
{
|
||||
retries: 3,
|
||||
}
|
||||
).catch(null)
|
||||
).catch(() => null)
|
||||
|
||||
console.log('jobStatus', JSON.stringify(jobStatus, null, 2))
|
||||
|
||||
@@ -988,7 +988,7 @@ export async function startSync({
|
||||
{
|
||||
retries: 3,
|
||||
}
|
||||
).catch(null)
|
||||
).catch(() => null)
|
||||
|
||||
console.log('jobStatus', JSON.stringify(jobStatus, null, 2))
|
||||
|
||||
@@ -1229,7 +1229,7 @@ export async function startBatch(inputs: ({ _path: string } & Record<string, any
|
||||
{
|
||||
retries: 3,
|
||||
}
|
||||
).catch(null)
|
||||
).catch(() => null)
|
||||
|
||||
console.log('[startBatch] jobStatus', {
|
||||
jobid: r.jobid,
|
||||
|
||||
@@ -231,15 +231,13 @@ export function parseRcloneVersion(output: string) {
|
||||
}
|
||||
|
||||
export function shouldUpdateRclone(versionData: { yours: string; latest: string } | null) {
|
||||
if (!versionData?.yours) return false
|
||||
|
||||
if (!versionData) {
|
||||
console.warn('[shouldUpdateRclone] received no version data:', versionData)
|
||||
return false
|
||||
}
|
||||
|
||||
const currentVersion = versionData.yours
|
||||
const latestVersion = versionData.latest
|
||||
const currentVersion = versionData?.yours
|
||||
const latestVersion = versionData?.latest
|
||||
|
||||
if (!currentVersion || !latestVersion) {
|
||||
console.warn('[shouldUpdateRclone] could not parse version output:', versionData)
|
||||
@@ -249,8 +247,8 @@ export function shouldUpdateRclone(versionData: { yours: string; latest: string
|
||||
console.log('[shouldUpdateRclone] current version:', currentVersion)
|
||||
console.log('[shouldUpdateRclone] latest version:', latestVersion)
|
||||
|
||||
if (useHostStore.getState().lastSkippedVersion === currentVersion) {
|
||||
console.log('[shouldUpdateRclone] current version is in the lastSkippedVersion')
|
||||
if (useHostStore.getState().lastSkippedVersion === latestVersion) {
|
||||
console.log('[shouldUpdateRclone] latest version is in the lastSkippedVersion')
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -636,6 +636,11 @@ async function resumeTasks() {
|
||||
isEnabled: task.isEnabled,
|
||||
})
|
||||
|
||||
if (!task.isEnabled) {
|
||||
console.log('[resumeTasks] task', task.id, 'is disabled, skipping')
|
||||
continue
|
||||
}
|
||||
|
||||
if (task.isRunning) {
|
||||
console.log('[resumeTasks] task', task.id, 'was marked as running, resetting state')
|
||||
useHostStore.getState().updateScheduledTask(task.id, {
|
||||
@@ -866,8 +871,6 @@ async function handleTask(task: ScheduledTask) {
|
||||
console.error('[handleTask] task', task.id, 'failed with error:', err)
|
||||
console.error('[handleTask] task args were:', JSON.stringify(task.args, null, 2))
|
||||
useHostStore.getState().updateScheduledTask(task.id, {
|
||||
isRunning: false,
|
||||
currentRunId: undefined,
|
||||
lastRunError: err instanceof Error ? err.message : 'Unknown error',
|
||||
})
|
||||
} finally {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Button, Input, Select, SelectItem } from '@heroui/react'
|
||||
import cronstrue from 'cronstrue'
|
||||
import { ClockIcon, XIcon } from 'lucide-react'
|
||||
import type React from 'react'
|
||||
import { startTransition, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
interface CronEditorProps {
|
||||
expression: string | null
|
||||
@@ -51,7 +51,12 @@ export default function CronEditor({ expression, onChange }: CronEditorProps) {
|
||||
[cronExpression]
|
||||
)
|
||||
|
||||
const hasMounted = useRef(false)
|
||||
useEffect(() => {
|
||||
if (!hasMounted.current) {
|
||||
hasMounted.current = true
|
||||
return
|
||||
}
|
||||
onChange(cronExpression)
|
||||
}, [cronExpression, onChange])
|
||||
|
||||
|
||||
@@ -264,10 +264,11 @@ export function PathField({
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
item.type === 'folder' && !item.path.endsWith('/') && !item.path.endsWith('\\')
|
||||
? `${item.path}${sep()}`
|
||||
: item.path
|
||||
setPath(item.path)
|
||||
setPath(
|
||||
item.type === 'folder' && !item.path.endsWith('/') && !item.path.endsWith('\\')
|
||||
? `${item.path}${sep()}`
|
||||
: item.path
|
||||
)
|
||||
}}
|
||||
isOpen={isOpen}
|
||||
initialPaths={path ? [path] : []}
|
||||
|
||||
@@ -271,10 +271,11 @@ export default function RemoteCreateDrawer({
|
||||
data-focus-visible="false"
|
||||
onPress={() => {
|
||||
setTimeout(() => {
|
||||
const { name, type, ...parameters } = config
|
||||
createRemoteMutation.mutate({
|
||||
name: config.name,
|
||||
type: config.type,
|
||||
parameters: config,
|
||||
name,
|
||||
type,
|
||||
parameters,
|
||||
})
|
||||
}, 10)
|
||||
}}
|
||||
|
||||
@@ -186,7 +186,7 @@ export default function TemplateAddDrawer({
|
||||
const parsedNumber = Number(v)
|
||||
if (!isNaN(parsedNumber)) v = parsedNumber
|
||||
|
||||
if (value.includes(',')) v = value.split(',')
|
||||
if (value?.includes(',')) v = value.split(',')
|
||||
|
||||
flagGroups[flag.trim()] = v
|
||||
}
|
||||
|
||||
@@ -78,11 +78,14 @@ export default function PreviewDrawer({
|
||||
return
|
||||
}
|
||||
|
||||
const abortController = new AbortController()
|
||||
|
||||
setIsLoadingText(true)
|
||||
setTextError(null)
|
||||
|
||||
fetch(previewUrl, {
|
||||
headers: auth ? { Authorization: `Basic ${auth}` } : undefined,
|
||||
signal: abortController.signal,
|
||||
})
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
||||
@@ -93,9 +96,12 @@ export default function PreviewDrawer({
|
||||
setIsLoadingText(false)
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
if (abortController.signal.aborted) return
|
||||
setTextError(err.message)
|
||||
setIsLoadingText(false)
|
||||
})
|
||||
|
||||
return () => abortController.abort()
|
||||
}, [item, fileType, previewUrl, auth, isTooLarge])
|
||||
|
||||
const handleDownload = useCallback(() => {
|
||||
|
||||
@@ -468,15 +468,15 @@ export default function Bisync() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.copy)
|
||||
setBisyncOptions({ ...bisyncOptions, ...groupedOptions.copy })
|
||||
setBisyncOptionsJsonString(JSON.stringify({ ...bisyncOptions, ...groupedOptions.copy }, null, 2))
|
||||
if (groupedOptions.filter)
|
||||
setFilterOptions({ ...filterOptions, ...groupedOptions.filter })
|
||||
setFilterOptionsJsonString(JSON.stringify({ ...filterOptions, ...groupedOptions.filter }, null, 2))
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else {
|
||||
if (groupedOptions.copy) setBisyncOptions(groupedOptions.copy)
|
||||
if (groupedOptions.filter) setFilterOptions(groupedOptions.filter)
|
||||
if (groupedOptions.config) setConfigOptions(groupedOptions.config)
|
||||
if (groupedOptions.copy) setBisyncOptionsJsonString(JSON.stringify(groupedOptions.copy, null, 2))
|
||||
if (groupedOptions.filter) setFilterOptionsJsonString(JSON.stringify(groupedOptions.filter, null, 2))
|
||||
if (groupedOptions.config) setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
+68
-103
@@ -67,20 +67,6 @@ export default function Browser() {
|
||||
const [trackedJobIds, setTrackedJobIds] = useState<Set<number>>(new Set())
|
||||
|
||||
const handleJobStarted = useCallback((jobId: number) => {
|
||||
// #region agent log
|
||||
fetch('http://127.0.0.1:7250/ingest/2834749a-e80b-4040-ad02-08316d12b97e', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
location: 'Commander.tsx:handleJobStarted',
|
||||
message: 'handleJobStarted called',
|
||||
data: { jobId },
|
||||
timestamp: Date.now(),
|
||||
sessionId: 'debug-session',
|
||||
hypothesisId: 'G',
|
||||
}),
|
||||
}).catch(() => {})
|
||||
// #endregion
|
||||
setTrackedJobIds((prev) => new Set([...prev, jobId]))
|
||||
}, [])
|
||||
|
||||
@@ -206,91 +192,85 @@ export default function Browser() {
|
||||
setContextMenu(null)
|
||||
}, [])
|
||||
|
||||
const handleDelete = useCallback(
|
||||
async (entry: Entry) => {
|
||||
const confirmed = await ask(
|
||||
`Are you sure you want to delete "${entry.name}"?`,
|
||||
{ title: 'Confirm Delete', kind: 'warning' }
|
||||
)
|
||||
if (!confirmed) return
|
||||
const handleDelete = useCallback(async (entry: Entry) => {
|
||||
const confirmed = await ask(`Are you sure you want to delete "${entry.name}"?`, {
|
||||
title: 'Confirm Delete',
|
||||
kind: 'warning',
|
||||
})
|
||||
if (!confirmed) return
|
||||
|
||||
try {
|
||||
const source = entry.fullPath + (entry.isDir ? '/' : '')
|
||||
const info = getFsInfo(source)
|
||||
const endpoint = entry.isDir ? '/operations/purge' : '/operations/deletefile'
|
||||
try {
|
||||
const source = entry.fullPath + (entry.isDir ? '/' : '')
|
||||
const info = getFsInfo(source)
|
||||
const endpoint = entry.isDir ? '/operations/purge' : '/operations/deletefile'
|
||||
|
||||
await rclone(endpoint as any, {
|
||||
await rclone(endpoint as any, {
|
||||
params: {
|
||||
query: {
|
||||
fs: info.root,
|
||||
remote: info.filePath,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
leftPanelRef.current?.refresh()
|
||||
rightPanelRef.current?.refresh()
|
||||
} catch (error) {
|
||||
await message(error instanceof Error ? error.message : 'Delete failed', {
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleRename = useCallback(async (entry: Entry) => {
|
||||
const newName = await invoke<string | null>('prompt', {
|
||||
title: 'Rename',
|
||||
message: `Enter a new name for "${entry.name}"`,
|
||||
default: entry.name,
|
||||
sensitive: false,
|
||||
})
|
||||
if (!newName || newName === entry.name) return
|
||||
|
||||
try {
|
||||
const info = getFsInfo(entry.fullPath)
|
||||
const parentDir = info.filePath.includes('/')
|
||||
? info.filePath.slice(0, info.filePath.lastIndexOf('/') + 1)
|
||||
: ''
|
||||
const dstRemote = `${parentDir}${newName}`
|
||||
|
||||
if (entry.isDir) {
|
||||
await rclone('/sync/move' as any, {
|
||||
params: {
|
||||
query: {
|
||||
fs: info.root,
|
||||
remote: info.filePath,
|
||||
srcFs: `${info.root}${info.filePath}/`,
|
||||
dstFs: `${info.root}${dstRemote}/`,
|
||||
deleteEmptySrcDirs: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
leftPanelRef.current?.refresh()
|
||||
rightPanelRef.current?.refresh()
|
||||
} catch (error) {
|
||||
await message(error instanceof Error ? error.message : 'Delete failed', {
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
} else {
|
||||
await rclone('/operations/movefile' as any, {
|
||||
params: {
|
||||
query: {
|
||||
srcFs: info.root,
|
||||
srcRemote: info.filePath,
|
||||
dstFs: info.root,
|
||||
dstRemote,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const handleRename = useCallback(
|
||||
async (entry: Entry) => {
|
||||
const newName = await invoke<string | null>('prompt', {
|
||||
title: 'Rename',
|
||||
message: `Enter a new name for "${entry.name}"`,
|
||||
default: entry.name,
|
||||
sensitive: false,
|
||||
leftPanelRef.current?.refresh()
|
||||
rightPanelRef.current?.refresh()
|
||||
} catch (error) {
|
||||
await message(error instanceof Error ? error.message : 'Rename failed', {
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
})
|
||||
if (!newName || newName === entry.name) return
|
||||
|
||||
try {
|
||||
const info = getFsInfo(entry.fullPath)
|
||||
const parentDir = info.filePath.includes('/')
|
||||
? info.filePath.slice(0, info.filePath.lastIndexOf('/') + 1)
|
||||
: ''
|
||||
const dstRemote = `${parentDir}${newName}`
|
||||
|
||||
if (entry.isDir) {
|
||||
await rclone('/sync/move' as any, {
|
||||
params: {
|
||||
query: {
|
||||
srcFs: `${info.root}${info.filePath}/`,
|
||||
dstFs: `${info.root}${dstRemote}/`,
|
||||
deleteEmptySrcDirs: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
await rclone('/operations/movefile' as any, {
|
||||
params: {
|
||||
query: {
|
||||
srcFs: info.root,
|
||||
srcRemote: info.filePath,
|
||||
dstFs: info.root,
|
||||
dstRemote,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
leftPanelRef.current?.refresh()
|
||||
rightPanelRef.current?.refresh()
|
||||
} catch (error) {
|
||||
await message(error instanceof Error ? error.message : 'Rename failed', {
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
})
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleCreateFolder = useCallback(
|
||||
async (panelSide: 'left' | 'right') => {
|
||||
@@ -519,21 +499,6 @@ function TransfersBar({ trackedJobIds }: { trackedJobIds: Set<number> }) {
|
||||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
const jobIds = Array.from(trackedJobIds)
|
||||
|
||||
// #region agent log
|
||||
fetch('http://127.0.0.1:7250/ingest/2834749a-e80b-4040-ad02-08316d12b97e', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
location: 'Commander.tsx:TransfersBar:render',
|
||||
message: 'TransfersBar rendering',
|
||||
data: { jobIdsCount: jobIds.length, jobIds },
|
||||
timestamp: Date.now(),
|
||||
sessionId: 'debug-session',
|
||||
hypothesisId: 'G,H',
|
||||
}),
|
||||
}).catch(() => {})
|
||||
// #endregion
|
||||
|
||||
const itemsQuery = useQuery({
|
||||
queryKey: ['transfers', 'items', jobIds],
|
||||
queryFn: async () => {
|
||||
|
||||
+10
-10
@@ -266,7 +266,7 @@ export default function Copy() {
|
||||
if (startCopyMutation.isPending) return 'STARTING...'
|
||||
if (!sources || sources.length === 0) return 'Please select a source path'
|
||||
if (!dest) return 'Please select a destination path'
|
||||
if (sources[0] === dest) return 'Source and destination cannot be the same'
|
||||
if (sources.some((s) => s === dest)) return 'Source and destination cannot be the same'
|
||||
if (jsonError) return 'Invalid JSON for ' + jsonError.toUpperCase() + ' options'
|
||||
if (cronExpression) return 'START AND SCHEDULE COPY'
|
||||
return 'START COPY'
|
||||
@@ -274,7 +274,7 @@ export default function Copy() {
|
||||
|
||||
const buttonIcon = useMemo(() => {
|
||||
if (startCopyMutation.isPending) return
|
||||
if (!sources || sources.length === 0 || !dest || sources[0] === dest)
|
||||
if (!sources || sources.length === 0 || !dest || sources.some((s) => s === dest))
|
||||
return <FoldersIcon className="w-5 h-5" />
|
||||
if (jsonError) return <AlertOctagonIcon className="w-5 h-5" />
|
||||
return <PlayIcon className="w-5 h-5 fill-current" />
|
||||
@@ -411,15 +411,15 @@ export default function Copy() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.copy)
|
||||
setCopyOptions({ ...copyOptions, ...groupedOptions.copy })
|
||||
setCopyOptionsJsonString(JSON.stringify({ ...copyOptions, ...groupedOptions.copy }, null, 2))
|
||||
if (groupedOptions.filter)
|
||||
setFilterOptions({ ...filterOptions, ...groupedOptions.filter })
|
||||
setFilterOptionsJsonString(JSON.stringify({ ...filterOptions, ...groupedOptions.filter }, null, 2))
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else {
|
||||
if (groupedOptions.copy) setCopyOptions(groupedOptions.copy)
|
||||
if (groupedOptions.filter) setFilterOptions(groupedOptions.filter)
|
||||
if (groupedOptions.config) setConfigOptions(groupedOptions.config)
|
||||
if (groupedOptions.copy) setCopyOptionsJsonString(JSON.stringify(groupedOptions.copy, null, 2))
|
||||
if (groupedOptions.filter) setFilterOptionsJsonString(JSON.stringify(groupedOptions.filter, null, 2))
|
||||
if (groupedOptions.config) setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
}
|
||||
})
|
||||
}}
|
||||
@@ -565,7 +565,7 @@ export default function Copy() {
|
||||
!sources ||
|
||||
sources.length === 0 ||
|
||||
!dest ||
|
||||
sources[0] === dest
|
||||
sources.some((s) => s === dest)
|
||||
}
|
||||
isLoading={startCopyMutation.isPending}
|
||||
endContent={buttonIcon}
|
||||
@@ -597,7 +597,7 @@ export default function Copy() {
|
||||
!sources ||
|
||||
sources.length === 0 ||
|
||||
!dest ||
|
||||
sources[0] === dest
|
||||
sources.some((s) => s === dest)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -343,12 +343,12 @@ export default function Delete() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.filter)
|
||||
setFilterOptions({ ...filterOptions, ...groupedOptions.filter })
|
||||
setFilterOptionsJsonString(JSON.stringify({ ...filterOptions, ...groupedOptions.filter }, null, 2))
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else {
|
||||
if (groupedOptions.filter) setFilterOptions(groupedOptions.filter)
|
||||
if (groupedOptions.config) setConfigOptions(groupedOptions.config)
|
||||
if (groupedOptions.filter) setFilterOptionsJsonString(JSON.stringify(groupedOptions.filter, null, 2))
|
||||
if (groupedOptions.config) setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -207,7 +207,11 @@ export default function Download() {
|
||||
setIsFetchingDownloadData(false)
|
||||
})
|
||||
})
|
||||
.catch()
|
||||
.catch(() => {
|
||||
startTransition(() => {
|
||||
setIsFetchingDownloadData(false)
|
||||
})
|
||||
})
|
||||
|
||||
return () => {
|
||||
abortController.abort()
|
||||
|
||||
+8
-8
@@ -308,18 +308,18 @@ export default function Mount() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.mount)
|
||||
setMountOptions({ ...mountOptions, ...groupedOptions.mount })
|
||||
setMountOptionsJsonString(JSON.stringify({ ...mountOptions, ...groupedOptions.mount }, null, 2))
|
||||
if (groupedOptions.vfs)
|
||||
setVfsOptions({ ...vfsOptions, ...groupedOptions.vfs })
|
||||
setVfsOptionsJsonString(JSON.stringify({ ...vfsOptions, ...groupedOptions.vfs }, null, 2))
|
||||
if (groupedOptions.filter)
|
||||
setFilterOptions({ ...filterOptions, ...groupedOptions.filter })
|
||||
setFilterOptionsJsonString(JSON.stringify({ ...filterOptions, ...groupedOptions.filter }, null, 2))
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else {
|
||||
if (groupedOptions.mount) setMountOptions(groupedOptions.mount)
|
||||
if (groupedOptions.vfs) setVfsOptions(groupedOptions.vfs)
|
||||
if (groupedOptions.filter) setFilterOptions(groupedOptions.filter)
|
||||
if (groupedOptions.config) setConfigOptions(groupedOptions.config)
|
||||
if (groupedOptions.mount) setMountOptionsJsonString(JSON.stringify(groupedOptions.mount, null, 2))
|
||||
if (groupedOptions.vfs) setVfsOptionsJsonString(JSON.stringify(groupedOptions.vfs, null, 2))
|
||||
if (groupedOptions.filter) setFilterOptionsJsonString(JSON.stringify(groupedOptions.filter, null, 2))
|
||||
if (groupedOptions.config) setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
+10
-10
@@ -293,7 +293,7 @@ export default function Move() {
|
||||
if (startMoveMutation.isPending) return 'STARTING...'
|
||||
if (!sources || sources.length === 0) return 'Please select a source path'
|
||||
if (!dest) return 'Please select a destination path'
|
||||
if (sources[0] === dest) return 'Source and destination cannot be the same'
|
||||
if (sources.some((s) => s === dest)) return 'Source and destination cannot be the same'
|
||||
if (jsonError) return 'Invalid JSON for ' + jsonError.toUpperCase() + ' options'
|
||||
if (cronExpression) return 'START AND SCHEDULE MOVE'
|
||||
return 'START MOVE'
|
||||
@@ -301,7 +301,7 @@ export default function Move() {
|
||||
|
||||
const buttonIcon = useMemo(() => {
|
||||
if (startMoveMutation.isPending) return
|
||||
if (!sources || sources.length === 0 || !dest || sources[0] === dest)
|
||||
if (!sources || sources.length === 0 || !dest || sources.some((s) => s === dest))
|
||||
return <FoldersIcon className="w-5 h-5" />
|
||||
if (jsonError) return <AlertOctagonIcon className="w-5 h-5" />
|
||||
return <PlayIcon className="w-5 h-5 fill-current" />
|
||||
@@ -433,15 +433,15 @@ export default function Move() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.copy)
|
||||
setMoveOptions({ ...moveOptions, ...groupedOptions.copy })
|
||||
setMoveOptionsJsonString(JSON.stringify({ ...moveOptions, ...groupedOptions.copy }, null, 2))
|
||||
if (groupedOptions.filter)
|
||||
setFilterOptions({ ...filterOptions, ...groupedOptions.filter })
|
||||
setFilterOptionsJsonString(JSON.stringify({ ...filterOptions, ...groupedOptions.filter }, null, 2))
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else {
|
||||
if (groupedOptions.copy) setMoveOptions(groupedOptions.copy)
|
||||
if (groupedOptions.filter) setFilterOptions(groupedOptions.filter)
|
||||
if (groupedOptions.config) setConfigOptions(groupedOptions.config)
|
||||
if (groupedOptions.copy) setMoveOptionsJsonString(JSON.stringify(groupedOptions.copy, null, 2))
|
||||
if (groupedOptions.filter) setFilterOptionsJsonString(JSON.stringify(groupedOptions.filter, null, 2))
|
||||
if (groupedOptions.config) setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
}
|
||||
})
|
||||
}}
|
||||
@@ -587,7 +587,7 @@ export default function Move() {
|
||||
!sources ||
|
||||
sources.length === 0 ||
|
||||
!dest ||
|
||||
sources[0] === dest
|
||||
sources.some((s) => s === dest)
|
||||
}
|
||||
isLoading={startMoveMutation.isPending}
|
||||
endContent={buttonIcon}
|
||||
@@ -619,7 +619,7 @@ export default function Move() {
|
||||
!sources ||
|
||||
sources.length === 0 ||
|
||||
!dest ||
|
||||
sources[0] === dest
|
||||
sources.some((s) => s === dest)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
+2
-2
@@ -230,9 +230,9 @@ export default function Purge() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else if (groupedOptions.config)
|
||||
setConfigOptions(groupedOptions.config)
|
||||
setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
})
|
||||
}}
|
||||
getOptions={() => ({
|
||||
|
||||
@@ -69,8 +69,10 @@ function TaskCard({
|
||||
}
|
||||
}, [task.name, isEditingName])
|
||||
|
||||
const parsed = useMemo(() => CronExpressionParser.parse(task.cron), [task.cron])
|
||||
const nextRun = useMemo(() => (parsed.hasNext() ? parsed.next().toDate() : null), [parsed])
|
||||
const nextRun = useMemo(() => {
|
||||
const parsed = CronExpressionParser.parse(task.cron)
|
||||
return parsed.hasNext() ? parsed.next().toDate() : null
|
||||
}, [task.cron])
|
||||
|
||||
const source = useMemo(
|
||||
() => ('source' in task.args ? task.args.source : task.args.sources[0]),
|
||||
|
||||
+8
-11
@@ -290,22 +290,19 @@ export default function Serve() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.serve && type)
|
||||
setServeOptions({
|
||||
...serveOptions,
|
||||
...groupedOptions.serve[type],
|
||||
})
|
||||
setServeOptionsJsonString(JSON.stringify({ ...serveOptions, ...groupedOptions.serve[type] }, null, 2))
|
||||
if (groupedOptions.vfs)
|
||||
setVfsOptions({ ...vfsOptions, ...groupedOptions.vfs })
|
||||
setVfsOptionsJsonString(JSON.stringify({ ...vfsOptions, ...groupedOptions.vfs }, null, 2))
|
||||
if (groupedOptions.filter)
|
||||
setFilterOptions({ ...filterOptions, ...groupedOptions.filter })
|
||||
setFilterOptionsJsonString(JSON.stringify({ ...filterOptions, ...groupedOptions.filter }, null, 2))
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else {
|
||||
if (groupedOptions.serve && type)
|
||||
setServeOptions(groupedOptions.serve[type])
|
||||
if (groupedOptions.vfs) setVfsOptions(groupedOptions.vfs)
|
||||
if (groupedOptions.filter) setFilterOptions(groupedOptions.filter)
|
||||
if (groupedOptions.config) setConfigOptions(groupedOptions.config)
|
||||
setServeOptionsJsonString(JSON.stringify(groupedOptions.serve[type], null, 2))
|
||||
if (groupedOptions.vfs) setVfsOptionsJsonString(JSON.stringify(groupedOptions.vfs, null, 2))
|
||||
if (groupedOptions.filter) setFilterOptionsJsonString(JSON.stringify(groupedOptions.filter, null, 2))
|
||||
if (groupedOptions.config) setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -109,22 +109,18 @@ export default function LicenseSection() {
|
||||
try {
|
||||
await validateLicense(licenseKeyInput)
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
await message(e.message, {
|
||||
await message(
|
||||
e instanceof Error ? e.message : 'An error occurred. Please try again.',
|
||||
{
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
okLabel: 'Ok',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
await message('An error occurred. Please try again.', {
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
okLabel: 'Ok',
|
||||
})
|
||||
}
|
||||
)
|
||||
return
|
||||
} finally {
|
||||
setIsActivating(false)
|
||||
}
|
||||
setIsActivating(false)
|
||||
|
||||
await message('Your license has been successfully activated.', {
|
||||
title: 'Congrats!',
|
||||
@@ -165,22 +161,18 @@ export default function LicenseSection() {
|
||||
try {
|
||||
await revokeMachineLicense(licenseKeyInput)
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
await message(e.message, {
|
||||
await message(
|
||||
e instanceof Error ? e.message : 'An error occurred. Please try again.',
|
||||
{
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
okLabel: 'Ok',
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
await message('An error occurred. Please try again.', {
|
||||
title: 'Error',
|
||||
kind: 'error',
|
||||
okLabel: 'Ok',
|
||||
})
|
||||
}
|
||||
)
|
||||
return
|
||||
} finally {
|
||||
setIsRevoking(false)
|
||||
}
|
||||
setIsRevoking(false)
|
||||
|
||||
await message('Your license has been successfully deactivated.', {
|
||||
title: 'License deactivated',
|
||||
|
||||
@@ -365,8 +365,6 @@ function RemoteCard({
|
||||
enabled: supportsAbout,
|
||||
})
|
||||
|
||||
console.log('about', remote, type, JSON.stringify(remoteAboutData, null, 2))
|
||||
|
||||
const imageUrl = useMemo(
|
||||
() =>
|
||||
provider && !type ? `/icons/providers/${provider}.png` : `/icons/backends/${type}.png`,
|
||||
|
||||
+6
-6
@@ -416,15 +416,15 @@ export default function Sync() {
|
||||
startTransition(() => {
|
||||
if (shouldMerge) {
|
||||
if (groupedOptions.sync)
|
||||
setSyncOptions({ ...syncOptions, ...groupedOptions.sync })
|
||||
setSyncOptionsJsonString(JSON.stringify({ ...syncOptions, ...groupedOptions.sync }, null, 2))
|
||||
if (groupedOptions.filter)
|
||||
setFilterOptions({ ...filterOptions, ...groupedOptions.filter })
|
||||
setFilterOptionsJsonString(JSON.stringify({ ...filterOptions, ...groupedOptions.filter }, null, 2))
|
||||
if (groupedOptions.config)
|
||||
setConfigOptions({ ...configOptions, ...groupedOptions.config })
|
||||
setConfigOptionsJsonString(JSON.stringify({ ...configOptions, ...groupedOptions.config }, null, 2))
|
||||
} else {
|
||||
if (groupedOptions.sync) setSyncOptions(groupedOptions.sync)
|
||||
if (groupedOptions.filter) setFilterOptions(groupedOptions.filter)
|
||||
if (groupedOptions.config) setConfigOptions(groupedOptions.config)
|
||||
if (groupedOptions.sync) setSyncOptionsJsonString(JSON.stringify(groupedOptions.sync, null, 2))
|
||||
if (groupedOptions.filter) setFilterOptionsJsonString(JSON.stringify(groupedOptions.filter, null, 2))
|
||||
if (groupedOptions.config) setConfigOptionsJsonString(JSON.stringify(groupedOptions.config, null, 2))
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -59,17 +59,6 @@ export default function Transfers() {
|
||||
[transfersQuery.data]
|
||||
)
|
||||
|
||||
console.log('[Transfers] query state', {
|
||||
isLoading: transfersQuery.isLoading,
|
||||
isRefetching: transfersQuery.isRefetching,
|
||||
isError: transfersQuery.isError,
|
||||
error: transfersQuery.error,
|
||||
activeCount: transfers.active.length,
|
||||
inactiveCount: transfers.inactive.length,
|
||||
// checkingJobs: transfers.active.filter((j) => j.isChecking).length,
|
||||
})
|
||||
console.log('[Transfers] data', JSON.stringify(transfers, null, 2))
|
||||
|
||||
if (transfersQuery.isLoading) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-screen">
|
||||
|
||||
+3
-3
@@ -34,9 +34,9 @@ export async function initHostStore(hostId: string) {
|
||||
}
|
||||
|
||||
try {
|
||||
disposeKeyChange = activeStore.onKeyChange('host-store', async () => {
|
||||
disposeKeyChange = await activeStore.onKeyChange('host-store', async () => {
|
||||
await useHostStore.persist.rehydrate()
|
||||
}) as unknown as () => void
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('[HostStore] failed to register onKeyChange listener', err)
|
||||
}
|
||||
@@ -49,7 +49,7 @@ const getStorage = (): StateStorage => ({
|
||||
getItem: async (name: string): Promise<string | null> => {
|
||||
if (!activeStore) return null
|
||||
// console.log('[HostStore] getItem', { name, host: activeHostId })
|
||||
return (await activeStore.get(name)) || null
|
||||
return (await activeStore.get(name)) ?? null
|
||||
},
|
||||
setItem: async (name: string, value: string): Promise<void> => {
|
||||
if (!activeStore) return
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ interface PersistedStateV2 {
|
||||
const getStorage = (store: LazyStore): StateStorage => ({
|
||||
getItem: async (name: string): Promise<string | null> => {
|
||||
console.log('getItem', { name })
|
||||
return (await store.get(name)) || null
|
||||
return (await store.get(name)) ?? null
|
||||
},
|
||||
setItem: async (name: string, value: string): Promise<void> => {
|
||||
console.log('setItem', { name, value })
|
||||
|
||||
+1
-1
@@ -21,5 +21,5 @@
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src", "lib", "reset.d.ts", "toolbar"]
|
||||
"include": ["src", "lib", "store", "types", "toolbar", "main.ts", "reset.d.ts"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user