Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { useCallback, useRef, useState } from 'react'
import React, { useCallback, useRef, useState } from 'react'
import type { TreeItemIndex } from 'react-complex-tree'
import {
createFileInProject,
createFolderInProject,
renameInProject,
deleteInProject,
} from '~/services/file-tree-service'
import { createFile, deleteFile, renameFile } from '~/services/file-service'
import { createFolderInProject } from '~/services/file-tree-service'
import { clearConfigurationCache } from '~/services/configuration-service'
import useTabStore from '~/stores/tab-store'
import useEditorTabStore from '~/stores/editor-tab-store'
import { showErrorToastFrom } from '~/components/toast'
import { showErrorToast, showErrorToastFrom } from '~/components/toast'

export interface ContextMenuState {
position: { x: number; y: number }
Expand Down Expand Up @@ -47,15 +43,19 @@ interface UseFileTreeContextMenuOptions {
onAfterDelete?: (path: string) => void
}

const ALLOWED_EXTENSIONS = ['.xml', '.json', '.yaml', '.yml', '.properties']

export function getParentItemId(itemId: TreeItemIndex): TreeItemIndex {
const str = String(itemId)
const lastSlash = str.lastIndexOf('/')
return lastSlash > 0 ? str.slice(0, Math.max(0, lastSlash)) : 'root'
}

function ensureXmlExtension(name: string): string {
if (name.includes('.')) return name
return `${name}.xml`
function ensureHasCorrectExtension(name: string): boolean {
const dotIndex = name.lastIndexOf('.')
if (dotIndex === -1) return false
const extension = name.slice(dotIndex)
return ALLOWED_EXTENSIONS.includes(extension.toLowerCase())
}

function buildNewPath(oldPath: string, newName: string): string {
Expand Down Expand Up @@ -117,9 +117,13 @@ export function useFileTreeContextMenu({
setNameDialog({
title: 'New File',
onSubmit: async (name: string) => {
const fileName = ensureXmlExtension(name)
if (!ensureHasCorrectExtension(name)) {
showErrorToast(`Filename must have one of the following extensions: ${ALLOWED_EXTENSIONS.join(', ')}`)
return
}

try {
await createFileInProject(projectName, parentPath, fileName)
await createFile(projectName, `${parentPath}/${name}`)
await dataProvider.reloadDirectory(parentItemId)
} catch (error) {
showErrorToastFrom('Failed to create file', error)
Expand All @@ -143,7 +147,7 @@ export function useFileTreeContextMenu({
title: 'New Folder',
onSubmit: async (name: string) => {
try {
await createFolderInProject(projectName, parentPath, name)
await createFolderInProject(projectName, `${parentPath}/${name}`)
await dataProvider.reloadDirectory(parentItemId)
} catch (error) {
showErrorToastFrom('Failed to create folder', error)
Expand Down Expand Up @@ -171,9 +175,13 @@ export function useFileTreeContextMenu({
if (newName === oldName) {
setNameDialog(null)
return
} else if (!ensureHasCorrectExtension(newName)) {
showErrorToast(`Filename must have one of the following extensions: ${ALLOWED_EXTENSIONS.join(', ')}`)
return
}

try {
await renameInProject(projectName, oldPath, newName)
await renameFile(projectName, `${oldPath}`, `${oldPath}`.replace(oldName, newName))
clearConfigurationCache(projectName, oldPath)
const newPath = buildNewPath(oldPath, newName)
useTabStore.getState().renameTabsForConfig(oldPath, newPath)
Expand Down Expand Up @@ -209,7 +217,7 @@ export function useFileTreeContextMenu({
if (!deleteTarget || !projectName || !dataProvider) return

try {
await deleteInProject(projectName, deleteTarget.path)
await deleteFile(projectName, deleteTarget.path)
clearConfigurationCache(projectName, deleteTarget.path)
useTabStore.getState().removeTabsForConfig(deleteTarget.path)
useEditorTabStore.getState().refreshAllTabs()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { useCallback, useRef, useState } from 'react'
import type { TreeItemIndex } from 'react-complex-tree'
import {
createFileInProject,
createFolderInProject,
renameInProject,
deleteInProject,
} from '~/services/file-tree-service'
import { deleteFile, renameFile } from '~/services/file-service'
import { createFolderInProject } from '~/services/file-tree-service'
import { createAdapter, renameAdapter, deleteAdapter } from '~/services/adapter-service'
import { clearConfigurationCache } from '~/services/configuration-service'
import { clearConfigurationCache, createConfiguration } from '~/services/configuration-service'
import useTabStore from '~/stores/tab-store'
import { showErrorToastFrom } from '~/components/toast'
import type { StudioItemData, StudioFolderData, StudioAdapterData } from './studio-files-data-provider'
Expand Down Expand Up @@ -156,7 +152,7 @@ export function useStudioContextMenu({ projectName, dataProvider }: UseStudioCon
onSubmit: async (name: string) => {
const fileName = ensureXmlExtension(name)
try {
await createFileInProject(projectName, menu.folderPath, fileName)
await createConfiguration(projectName, `${menu.folderPath}/${fileName}`)
await dataProvider.reloadDirectory('root')
} catch (error) {
showErrorToastFrom('Failed to create configuration', error)
Expand Down Expand Up @@ -200,7 +196,7 @@ export function useStudioContextMenu({ projectName, dataProvider }: UseStudioCon
title: 'New Folder',
onSubmit: async (name: string) => {
try {
await createFolderInProject(projectName, menu.folderPath, name)
await createFolderInProject(projectName, `${menu.folderPath}/${name}`)
await dataProvider.reloadDirectory('root')
} catch (error) {
showErrorToastFrom('Failed to create folder', error)
Expand Down Expand Up @@ -232,7 +228,7 @@ export function useStudioContextMenu({ projectName, dataProvider }: UseStudioCon
await renameAdapter(projectName, oldName, newName, menu.path)
} else {
const finalName = menu.itemType === 'configuration' ? ensureXmlExtension(newName) : newName
await renameInProject(projectName, menu.path, finalName)
await renameFile(projectName, `${menu.path}/${oldName}`, `${menu.path}/${newName}`)
clearConfigurationCache(projectName, menu.path)
const newPath = `${getParentDir(menu.path)}/${finalName}`
useTabStore.getState().renameTabsForConfig(menu.path, newPath)
Expand Down Expand Up @@ -270,7 +266,7 @@ export function useStudioContextMenu({ projectName, dataProvider }: UseStudioCon
await deleteAdapter(projectName, deleteTarget.name, deleteTarget.path)
removeAdapterTab(deleteTarget.path, deleteTarget.name)
} else {
await deleteInProject(projectName, deleteTarget.path)
await deleteFile(projectName, deleteTarget.path)
clearConfigurationCache(projectName, deleteTarget.path)
useTabStore.getState().removeTabsForConfig(deleteTarget.path)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useEffect, useState } from 'react'
import React, { useEffect, useState } from 'react'
import { createConfiguration } from '~/services/configuration-service'
import { useProjectStore } from '~/stores/project-store'
import type { Project } from '~/types/project.types'
import Button from '~/components/inputs/button'
import DirectoryPicker from '~/components/directory-picker/directory-picker'
import { createFileInProject } from '~/services/file-tree-service'
import { fetchProject } from '~/services/project-service'

interface AddConfigurationModalProperties {
Expand Down Expand Up @@ -50,7 +50,7 @@ export default function AddConfigurationModal({
configname = `${configname}.xml`
}

await createFileInProject(currentProject.name, rootLocationName, configname)
await createConfiguration(currentProject.name, `${rootLocationName}/${configname}`)
const updatedProject = await fetchProject(currentProject.name)
setProject(updatedProject)
onSuccess?.()
Expand Down Expand Up @@ -92,7 +92,7 @@ export default function AddConfigurationModal({
className="bg-background/50 absolute inset-0 z-50 flex items-center justify-center"
onClick={handleClickedOutside}
>
<div className="bg-background border-border relative h-[400px] w-1/3 min-w-[800px] rounded-lg border p-6 shadow-lg">
<div className="bg-background border-border relative h-100 w-1/3 min-w-200 rounded-lg border p-6 shadow-lg">
<h2 className="mb-4 text-lg font-semibold">Add Configuration</h2>
<p className="mb-4">Add a new configuration file.</p>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { deleteFile } from '~/services/file-service'
import { useProjectStore } from '~/stores/project-store'
import ConfigurationTile from './configuration-tile'
import ArrowLeftIcon from '/icons/solar/Alt Arrow Left.svg?react'
Expand All @@ -7,7 +8,7 @@ import { useState, useEffect, useCallback, type ChangeEvent, useMemo } from 'rea
import AddConfigurationModal from './add-configuration-modal'
import LoadingSpinner from '~/components/loading-spinner'
import type { FileTreeNode } from '~/types/filesystem.types'
import { deleteInProject, fetchProjectTree } from '~/services/file-tree-service'
import { fetchProjectTree } from '~/services/file-tree-service'
import Button from '~/components/inputs/button'
import Search from '~/components/search/search'
import { toRelativePath } from '~/utils/path-utils'
Expand Down Expand Up @@ -104,7 +105,7 @@ export default function ConfigurationManager() {

const handleDelete = async (filepath: string) => {
if (!currentProject?.name) return
await deleteInProject(currentProject.name, filepath)
await deleteFile(currentProject.name, filepath)
loadTree()
}

Expand Down
Loading
Loading