Skip to content
Merged
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
2 changes: 1 addition & 1 deletion src/main/frontend/app/components/inputs/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function Button({
return (
<button
className={clsx(
'border-border hover:bg-hover active:bg-selected text-foreground bg-backdrop rounded-md border px-4 py-2',
'border-border hover:bg-hover active:bg-selected text-foreground bg-backdrop rounded-md border px-4 py-2 hover:cursor-pointer',
className,
)}
{...properties}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ export default function ConfigurationTile({ filepath, relativePath }: Readonly<C
}

const handleOpenInEditor = () => {
openInEditor(relativePath, filepath)
const fileName = relativePath.split(/[/\\]/).pop()
if (!fileName) return

openInEditor(fileName, filepath)
}

return (
Expand Down
60 changes: 57 additions & 3 deletions src/main/frontend/app/routes/editor/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,45 @@ import SidebarLayout from '~/components/sidebars-layout/sidebar-layout'
import { SidebarSide } from '~/components/sidebars-layout/sidebar-layout-store'
import SidebarContentClose from '~/components/sidebars-layout/sidebar-content-close'
import { useTheme } from '~/hooks/use-theme'
import { useEffect, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useProjectStore } from '~/stores/project-store'
import EditorFileStructure from '~/components/file-structure/editor-file-structure'
import useEditorTabStore from '~/stores/editor-tab-store'
import EditorTabs from '~/components/tabs/editor-tabs'
import type { ElementDetails, Attribute, EnumValue } from '~/types/ff-doc.types'
import { useFrankDoc } from '~/providers/frankdoc-provider'
import { fetchConfiguration, saveConfiguration } from '~/services/configuration-service'
import { useNavigationStore } from '~/stores/navigation-store'
import useTabStore from '~/stores/tab-store'
import RulerCrossPenIcon from '/icons/solar/Ruler Cross Pen.svg?react'
import { openInStudio } from '~/actions/navigationActions'
import Button from '~/components/inputs/button'

function findAdaptersInXml(xml: string): { name: string; offset: number }[] {
const adapters: { name: string; offset: number }[] = []
const regex = /<Adapter\b[^>]*\bname\s*=\s*"([^"]*)"/g
let match: RegExpExecArray | null
while ((match = regex.exec(xml)) !== null) {
adapters.push({ name: match[1], offset: match.index })
}
return adapters
}

function lineToOffset(xml: string, lineNumber: number): number {
const lines = xml.split('\n')
let offset = 0
for (let i = 0; i < lineNumber - 1 && i < lines.length; i++) {
offset += lines[i].length + 1
}
return offset
}

function findAdapterAtOffset(adapters: { name: string; offset: number }[], cursorOffset: number): string {
for (let i = adapters.length - 1; i >= 0; i--) {
if (adapters[i].offset <= cursorOffset) return adapters[i].name
}
return adapters[0].name
}

export default function CodeEditor() {
const theme = useTheme()
Expand Down Expand Up @@ -241,6 +272,25 @@ export default function CodeEditor() {
}
}

const handleOpenInStudio = useCallback(() => {
const editorTab = useEditorTabStore.getState().getTab(activeTabFilePath)
if (!editorTab) return

const xml = editorReference.current?.getValue() || xmlContent
if (!xml) return

const adapters = findAdaptersInXml(xml)
if (adapters.length === 0) return

const cursorLine = editorReference.current?.getPosition()?.lineNumber
const adapterName =
adapters.length === 1 || !cursorLine
? adapters[0].name
: findAdapterAtOffset(adapters, lineToOffset(xml, cursorLine))

openInStudio(adapterName, editorTab.configurationPath)
}, [activeTabFilePath, xmlContent])

return (
<SidebarLayout name="editor">
<>
Expand All @@ -257,8 +307,12 @@ export default function CodeEditor() {
</div>
{activeTabFilePath ? (
<>
<div className="border-b-border bg-background flex h-12 items-center border-b p-4">
Path: {activeTabPath}
<div className="border-b-border bg-background flex h-12 items-center justify-between border-b p-4">
<span>Path: {activeTabPath}</span>
<Button onClick={handleOpenInStudio} className="flex items-center gap-1.5" title="Open in Studio">
<RulerCrossPenIcon className="fill-foreground h-4 w-4" />
Open in Studio
</Button>
</div>
<div className="h-full">
<Editor
Expand Down
22 changes: 19 additions & 3 deletions src/main/frontend/app/routes/studio/studio.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react'
import { useCallback, useState } from 'react'
import StudioTabs from '~/components/tabs/studio-tabs'
import StudioFileStructure from '~/components/file-structure/studio-file-structure'
import StudioContext from '~/routes/studio/context/studio-context'
Expand All @@ -13,6 +13,9 @@ import useTabStore from '~/stores/tab-store'
import { useShallow } from 'zustand/react/shallow'
import { ToastContainer } from 'react-toastify'
import { useTheme } from '~/hooks/use-theme'
import CodeIcon from '/icons/solar/Code.svg?react'
import { openInEditor } from '~/actions/navigationActions'
import Button from '~/components/inputs/button'

export default function Studio() {
const [showNodeContext, setShowNodeContext] = useState(false)
Expand All @@ -26,6 +29,15 @@ export default function Studio() {
})),
)

const handleOpenInEditor = useCallback(() => {
if (!activeTabPath) return

const fileName = activeTabPath.split(/[/\\]/).pop()
if (!fileName) return

openInEditor(fileName, activeTabPath)
}, [activeTabPath])

return (
<SidebarLayout name="studio">
<>
Expand All @@ -43,8 +55,12 @@ export default function Studio() {

{activeTab ? (
<>
<div className="border-b-border bg-background flex h-12 items-center border-b p-4">
Path: {activeTabPath}
<div className="border-b-border bg-background flex h-12 items-center justify-between border-b p-4">
<span>Path: {activeTabPath}</span>
<Button onClick={handleOpenInEditor} className="flex items-center gap-1.5" title="Open in Editor">
<CodeIcon className="fill-foreground h-4 w-4" />
Open in Editor
</Button>
</div>
<Flow showNodeContextMenu={setShowNodeContext} />
<ToastContainer position="bottom-right" theme={theme} closeOnClick={true} />
Expand Down
Loading