feat: default document language select
This commit is contained in:
parent
290bc8481d
commit
8eada10e87
@ -21,3 +21,24 @@ func GetInstance() *App {
|
|||||||
func (a *App) Startup(ctx context.Context) {
|
func (a *App) Startup(ctx context.Context) {
|
||||||
a.Context = ctx
|
a.Context = ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Language struct {
|
||||||
|
DisplayName string
|
||||||
|
ProcessCode string
|
||||||
|
TranslateCode string
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSuppportedLanguages() []Language {
|
||||||
|
return []Language{
|
||||||
|
{
|
||||||
|
DisplayName: "English",
|
||||||
|
ProcessCode: "eng",
|
||||||
|
TranslateCode: "en",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DisplayName: "Hebrew",
|
||||||
|
ProcessCode: "heb",
|
||||||
|
TranslateCode: "he",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package document
|
package document
|
||||||
|
|
||||||
|
import app "textualize/core/App"
|
||||||
|
|
||||||
type Entity struct {
|
type Entity struct {
|
||||||
Id string
|
Id string
|
||||||
GroupId string
|
GroupId string
|
||||||
@ -7,6 +9,7 @@ type Entity struct {
|
|||||||
Path string
|
Path string
|
||||||
ProjectId string
|
ProjectId string
|
||||||
Areas []Area
|
Areas []Area
|
||||||
|
DefaultLanguage app.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
type Area struct {
|
type Area struct {
|
||||||
@ -16,6 +19,7 @@ type Area struct {
|
|||||||
StartY int
|
StartY int
|
||||||
EndX int
|
EndX int
|
||||||
EndY int
|
EndY int
|
||||||
|
Language app.Language
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Entity) AddArea(a Area) {
|
func (e *Entity) AddArea(a Area) {
|
||||||
|
|||||||
@ -1,6 +1,18 @@
|
|||||||
package session
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
app "textualize/core/App"
|
||||||
|
)
|
||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
Id string
|
Id string
|
||||||
|
OrganizationId string
|
||||||
Name string
|
Name string
|
||||||
|
Settings ProjectSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectSettings struct {
|
||||||
|
DefaultProcessLanguage app.Language
|
||||||
|
DefaultTranslateTargetLanguage app.Language
|
||||||
|
IsHosted bool
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,8 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"@next/next/no-img-element": "off",
|
"@next/next/no-img-element": "off",
|
||||||
"quotes": ["warn", "single"],
|
"quotes": ["warn", "single"],
|
||||||
"semi": ["warn", "never"]
|
"semi": ["warn", "never"],
|
||||||
|
"react-hooks/exhaustive-deps": "off"
|
||||||
},
|
},
|
||||||
"ignorePatterns": ["wailsjs/*"]
|
"ignorePatterns": ["wailsjs/*"]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
import { useRef } from 'react'
|
import { Switch } from '@headlessui/react'
|
||||||
|
import { useRef, useState } from 'react'
|
||||||
|
import classNames from '../../utils/classNames'
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onCreateNewProjectHandler: (projectName: string) => void
|
onCreateNewProjectHandler: (projectName: string) => void
|
||||||
@ -6,16 +9,17 @@ type Props = {
|
|||||||
|
|
||||||
const NewProjectModal = (props: Props) => {
|
const NewProjectModal = (props: Props) => {
|
||||||
const projectNameRef = useRef<HTMLInputElement>(null)
|
const projectNameRef = useRef<HTMLInputElement>(null)
|
||||||
|
const [isHostedProjectSelected, setIsHostedProjectSelected] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className=" p-8 absolute top-2/4 -translate-y-1/2 left-2/4 -translate-x-1/2 z-50 bg-white shadow sm:rounded-lg">
|
<div className=" p-8 absolute top-2/4 -translate-y-1/2 left-2/4 -translate-x-1/2 z-50 bg-white shadow sm:rounded-lg">
|
||||||
<div className="px-4 py-5 sm:p-6">
|
<div className="px-4 py-5 sm:p-6">
|
||||||
<h3 className="text-lg font-medium leading-6 text-gray-900">Name Your New Project</h3>
|
<h3 className="text-lg font-medium leading-6 text-gray-900">Name Your New Project</h3>
|
||||||
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
||||||
<p>A unique name will be best. This <b>can</b> be changed later.</p>
|
<p>A unique name makes the project easier to identify later. This <b>can</b> be changed later.</p>
|
||||||
</div>
|
</div>
|
||||||
<form className="mt-5 sm:flex sm:items-center">
|
<form className="mt-3 items-center">
|
||||||
<div className="w-full sm:max-w-xs">
|
<div className="w-full mb-5">
|
||||||
<label htmlFor="name" className="sr-only">
|
<label htmlFor="name" className="sr-only">
|
||||||
Project Name
|
Project Name
|
||||||
</label>
|
</label>
|
||||||
@ -25,17 +29,46 @@ const NewProjectModal = (props: Props) => {
|
|||||||
id="name"
|
id="name"
|
||||||
autoFocus
|
autoFocus
|
||||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm text-gray-900"
|
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm text-gray-900"
|
||||||
placeholder="New Project"
|
placeholder="Project Name"
|
||||||
ref={projectNameRef}
|
ref={projectNameRef}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Switch.Group as="div" className="flex items-center justify-between mb-5">
|
||||||
|
<span className="flex flex-grow flex-col">
|
||||||
|
<Switch.Label as="span" className="text-sm font-medium text-gray-900" passive>
|
||||||
|
Hosted Project
|
||||||
|
</Switch.Label>
|
||||||
|
<Switch.Description as="span" className="text-sm text-gray-500">
|
||||||
|
A hosted project can store and process data on a server. This <b>can</b> be added later. <em className='text-xs'>Currently unavalible</em>
|
||||||
|
</Switch.Description>
|
||||||
|
</span>
|
||||||
|
<Switch
|
||||||
|
checked={isHostedProjectSelected}
|
||||||
|
onChange={setIsHostedProjectSelected}
|
||||||
|
disabled
|
||||||
|
className={classNames(
|
||||||
|
isHostedProjectSelected ? 'bg-indigo-600' : 'bg-gray-200',
|
||||||
|
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
className={classNames(
|
||||||
|
isHostedProjectSelected ? 'translate-x-5' : 'translate-x-0',
|
||||||
|
'pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out'
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Switch>
|
||||||
|
</Switch.Group>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!projectNameRef.current?.value) return
|
if (!projectNameRef.current?.value) return
|
||||||
props.onCreateNewProjectHandler(projectNameRef.current?.value)
|
props.onCreateNewProjectHandler(projectNameRef.current?.value)
|
||||||
}}
|
}}
|
||||||
className="mt-3 inline-flex w-full items-center justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
className="inline-flex w-full items-center justify-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 sm:mt-0 sm:w-auto sm:text-sm"
|
||||||
>
|
>
|
||||||
Start
|
Start
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -5,10 +5,7 @@ import { Fragment } from 'react'
|
|||||||
import { useNavigation } from '../../context/Navigation/provider'
|
import { useNavigation } from '../../context/Navigation/provider'
|
||||||
import { mainPages } from '../../context/Navigation/types'
|
import { mainPages } from '../../context/Navigation/types'
|
||||||
import UserAvatar from './UserAvatar'
|
import UserAvatar from './UserAvatar'
|
||||||
|
import classNames from '../../utils/classNames'
|
||||||
function classNames(...classes: any[]) {
|
|
||||||
return classes.filter(Boolean).join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
const Search = () => {
|
const Search = () => {
|
||||||
const { setSelectedMainPage } = useNavigation()
|
const { setSelectedMainPage } = useNavigation()
|
||||||
@ -75,7 +72,7 @@ const Search = () => {
|
|||||||
leaveFrom="transform opacity-100 scale-100"
|
leaveFrom="transform opacity-100 scale-100"
|
||||||
leaveTo="transform opacity-0 scale-95"
|
leaveTo="transform opacity-0 scale-95"
|
||||||
>
|
>
|
||||||
<Menu.Items className="absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
<Menu.Items className="absolute right-0 z-10 mt-1 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||||
{userNavigation.map((item) => (
|
{userNavigation.map((item) => (
|
||||||
<Menu.Item key={item.name}>
|
<Menu.Item key={item.name}>
|
||||||
{({ active }) => (
|
{({ active }) => (
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import React, { useEffect, useRef } from 'react'
|
|||||||
import { useProject } from '../../context/Project/provider'
|
import { useProject } from '../../context/Project/provider'
|
||||||
import loadImage from '../../useCases/loadImage'
|
import loadImage from '../../useCases/loadImage'
|
||||||
import processImageArea from '../../useCases/processImageArea'
|
import processImageArea from '../../useCases/processImageArea'
|
||||||
|
import LanguageSelect from './LanguageSelect'
|
||||||
|
|
||||||
const DocumentRenderer = () => {
|
const DocumentRenderer = () => {
|
||||||
const { getSelectedDocument, requestAddArea } = useProject()
|
const { getSelectedDocument, requestAddArea } = useProject()
|
||||||
@ -146,13 +147,17 @@ const DocumentRenderer = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedDocument?.path) applyDocumentToCanvas(selectedDocument.path)
|
if (selectedDocument?.path) applyDocumentToCanvas(selectedDocument.path)
|
||||||
}, [selectedDocument?.id])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
applyAreasToCanvas()
|
applyAreasToCanvas()
|
||||||
}, [areas, areas?.length])
|
})
|
||||||
|
|
||||||
return <div className="relative">
|
return <div className='relative'>
|
||||||
|
<div className='flex justify-between mt-2'>
|
||||||
|
<h1 className="text-2xl font-semibold text-gray-900">
|
||||||
|
{getSelectedDocument()?.name}
|
||||||
|
</h1>
|
||||||
|
<LanguageSelect shouldUpdateDocument defaultLanguage={selectedDocument?.defaultLanguage} />
|
||||||
|
</div>
|
||||||
|
<div className="relative mt-2">
|
||||||
<canvas
|
<canvas
|
||||||
className="absolute border-4 border-dashed border-gray-200"
|
className="absolute border-4 border-dashed border-gray-200"
|
||||||
ref={documentCanvas}
|
ref={documentCanvas}
|
||||||
@ -169,6 +174,7 @@ const DocumentRenderer = () => {
|
|||||||
onMouseMove={handleMouseMove}
|
onMouseMove={handleMouseMove}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DocumentRenderer
|
export default DocumentRenderer
|
||||||
|
|||||||
87
frontend/components/workspace/LanguageSelect.tsx
Normal file
87
frontend/components/workspace/LanguageSelect.tsx
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { Combobox } from '@headlessui/react'
|
||||||
|
import { LanguageIcon } from '@heroicons/react/20/solid'
|
||||||
|
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/24/outline'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useProject } from '../../context/Project/provider'
|
||||||
|
import classNames from '../../utils/classNames'
|
||||||
|
import getSupportedLanguages from '../../utils/getSupportedLanguages'
|
||||||
|
import { ipc } from '../../wailsjs/wailsjs/go/models'
|
||||||
|
|
||||||
|
type forAreaType = { shouldUpdateArea?: true, shouldUpdateDocument?: never }
|
||||||
|
type forDocumentType = { shouldUpdateDocument?: true, shouldUpdateArea?: never }
|
||||||
|
type Props = (forAreaType | forDocumentType) & { defaultLanguage?: ipc.Language }
|
||||||
|
|
||||||
|
const LanguageSelect = (props?: Props) => {
|
||||||
|
const { requestUpdateDocument, getSelectedDocument } = useProject()
|
||||||
|
const [languages, setLanguages] = useState<ipc.Language[]>([])
|
||||||
|
const [query, setQuery] = useState('')
|
||||||
|
const [selectedLanguage, setSelectedLanguage] = useState<ipc.Language | undefined>(props?.defaultLanguage)
|
||||||
|
|
||||||
|
|
||||||
|
const filteredLanguages = query === ''
|
||||||
|
? languages
|
||||||
|
: languages.filter(l => {
|
||||||
|
return l.displayName.toLowerCase().includes(query.toLowerCase())
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (languages.length === 0) {
|
||||||
|
getSupportedLanguages().then(response => {
|
||||||
|
setLanguages(response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props?.shouldUpdateDocument && selectedLanguage?.displayName) {
|
||||||
|
const currentDocument = { ...getSelectedDocument() }
|
||||||
|
currentDocument.defaultLanguage = selectedLanguage
|
||||||
|
requestUpdateDocument(currentDocument)
|
||||||
|
}
|
||||||
|
}, [selectedLanguage])
|
||||||
|
|
||||||
|
|
||||||
|
return <Combobox as="div" value={selectedLanguage} onChange={setSelectedLanguage}>
|
||||||
|
<div className="inline-block relative">
|
||||||
|
<Combobox.Input
|
||||||
|
className="w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-10 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm"
|
||||||
|
onChange={(event) => setQuery(event.target.value)}
|
||||||
|
displayValue={(language: ipc.Language) => language?.displayName}
|
||||||
|
placeholder='Document Language'
|
||||||
|
/>
|
||||||
|
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
|
||||||
|
<LanguageIcon className="h-5 w-5 text-gray-400" />
|
||||||
|
<ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||||
|
</Combobox.Button>
|
||||||
|
|
||||||
|
{filteredLanguages.length > 0 && (
|
||||||
|
<Combobox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
|
||||||
|
{filteredLanguages.map((l) => (
|
||||||
|
<Combobox.Option
|
||||||
|
key={l.displayName}
|
||||||
|
value={l}
|
||||||
|
className={({ active }) => classNames(
|
||||||
|
'relative cursor-default select-none py-2 pl-3 pr-9',
|
||||||
|
active ? 'bg-indigo-600 text-white' : 'text-gray-900'
|
||||||
|
)}>
|
||||||
|
{({ active, selected }) => <>
|
||||||
|
<span className={classNames('block truncate', selected && 'font-semibold')}>{l.displayName}</span>
|
||||||
|
{selected && (
|
||||||
|
<span className={classNames(
|
||||||
|
'absolute inset-y-0 right-0 flex items-center pr-4',
|
||||||
|
active ? 'text-white' : 'text-indigo-600'
|
||||||
|
)}>
|
||||||
|
<CheckIcon className="h-5 w-5" aria-hidden="true" />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</Combobox.Option>
|
||||||
|
))}
|
||||||
|
</Combobox.Options>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Combobox>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LanguageSelect
|
||||||
@ -22,9 +22,9 @@ const renderSelectedWorkSpace = () => {
|
|||||||
<div className="mx-auto px-4 sm:px-6 md:px-8">
|
<div className="mx-auto px-4 sm:px-6 md:px-8">
|
||||||
<div className="py-1">
|
<div className="py-1">
|
||||||
<div className="mx-auto px-4 sm:px-6 md:px-8">
|
<div className="mx-auto px-4 sm:px-6 md:px-8">
|
||||||
<h1 className="text-2xl font-semibold text-gray-900">
|
{!getSelectedDocument()?.id ? <h1 className="text-2xl mt-2 font-semibold text-gray-900">
|
||||||
{getSelectedDocument()?.name || 'Image Processor'}
|
Image Processor
|
||||||
</h1>
|
</h1> : ''}
|
||||||
</div>
|
</div>
|
||||||
{ renderSelectedWorkSpace() }
|
{ renderSelectedWorkSpace() }
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,9 +1,22 @@
|
|||||||
import { DocumentPlusIcon } from '@heroicons/react/24/outline'
|
import { DocumentPlusIcon } from '@heroicons/react/24/outline'
|
||||||
|
import { useProject } from '../../context/Project/provider'
|
||||||
|
|
||||||
export default function NoSelectedDocument() {
|
export default function NoSelectedDocument() {
|
||||||
|
const { requestAddDocument, setSelectedDocumentId } = useProject()
|
||||||
|
|
||||||
|
const onAddDocumentClickHandler = async () => {
|
||||||
|
const documentName = 'Untitled Document'
|
||||||
|
|
||||||
|
const response = await requestAddDocument('', documentName)
|
||||||
|
if (!response.id) return
|
||||||
|
|
||||||
|
setSelectedDocumentId(response.id)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
onClick={() => onAddDocumentClickHandler()}
|
||||||
className="relative block w-full rounded-lg border-4 border-dashed border-gray-200 p-12 text-center hover:border-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
className="relative block w-full rounded-lg border-4 border-dashed border-gray-200 p-12 text-center hover:border-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import React, { useRef, useState } from 'react'
|
|||||||
import { PlusIcon, XMarkIcon, DocumentPlusIcon } from '@heroicons/react/20/solid'
|
import { PlusIcon, XMarkIcon, DocumentPlusIcon } from '@heroicons/react/20/solid'
|
||||||
import { ipc } from '../../wailsjs/wailsjs/go/models'
|
import { ipc } from '../../wailsjs/wailsjs/go/models'
|
||||||
import { useProject } from '../../context/Project/provider'
|
import { useProject } from '../../context/Project/provider'
|
||||||
|
import classNames from '../../utils/classNames'
|
||||||
|
|
||||||
type GroupNavigationItem = {
|
type GroupNavigationItem = {
|
||||||
id: string,
|
id: string,
|
||||||
@ -43,29 +44,28 @@ const getNavigationProps = (documents: ipc.Document[], groups: ipc.Group[]): Gro
|
|||||||
return [
|
return [
|
||||||
...groupsWithDocuments,
|
...groupsWithDocuments,
|
||||||
{
|
{
|
||||||
id: 'Uncategorized',
|
id: '',
|
||||||
name: 'Uncategorized',
|
name: 'Uncategorized',
|
||||||
documents: documentsWithoutGroup
|
documents: documentsWithoutGroup
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
function classNames(...classes: any[]) {
|
|
||||||
return classes.filter(Boolean).join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sidebar() {
|
function Sidebar() {
|
||||||
const [selectedGroupId, setSelectedGroupId] = useState('')
|
const [selectedGroupId, setSelectedGroupId] = useState('')
|
||||||
const [isAddNewDocumentInputShowing, setIsAddNewDocumentInputShowing] = useState(false)
|
const [isAddNewDocumentInputShowing, setIsAddNewDocumentInputShowing] = useState(false)
|
||||||
|
const [isEditDocumentNameInputShowing, setIsEditDocumentNameInputShowing] = useState(false)
|
||||||
const [isAddNewGroupInputShowing, setIsAddNewGroupInputShowing] = useState(false)
|
const [isAddNewGroupInputShowing, setIsAddNewGroupInputShowing] = useState(false)
|
||||||
const [isEditAreaNameInputShowing, setIsEditAreaNameInputShowing] = useState(false)
|
const [isEditAreaNameInputShowing, setIsEditAreaNameInputShowing] = useState(false)
|
||||||
const addDocumentTextInput = useRef<HTMLInputElement>(null)
|
const addDocumentTextInput = useRef<HTMLInputElement>(null)
|
||||||
const addGroupTextInput = useRef<HTMLInputElement>(null)
|
const addGroupTextInput = useRef<HTMLInputElement>(null)
|
||||||
const editAreaNameTextInput = useRef<HTMLInputElement>(null)
|
const editAreaNameTextInput = useRef<HTMLInputElement>(null)
|
||||||
|
const editDocumentNameTextInput = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
documents,
|
documents,
|
||||||
groups,
|
groups,
|
||||||
|
getSelectedDocument,
|
||||||
getAreaById,
|
getAreaById,
|
||||||
requestUpdateArea,
|
requestUpdateArea,
|
||||||
requestAddDocument,
|
requestAddDocument,
|
||||||
@ -75,6 +75,7 @@ function Sidebar() {
|
|||||||
selectedDocumentId,
|
selectedDocumentId,
|
||||||
setSelectedDocumentId,
|
setSelectedDocumentId,
|
||||||
currentSession,
|
currentSession,
|
||||||
|
requestUpdateDocument,
|
||||||
} = useProject()
|
} = useProject()
|
||||||
|
|
||||||
const navigation = getNavigationProps(documents, groups)
|
const navigation = getNavigationProps(documents, groups)
|
||||||
@ -115,7 +116,7 @@ function Sidebar() {
|
|||||||
setSelectedAreaId(areaId)
|
setSelectedAreaId(areaId)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onAreaDoubleclick = (areaId: string) => {
|
const onAreaDoubleClick = (areaId: string) => {
|
||||||
const documentIdOfArea = getDocumentIdFromAreaId(areaId)
|
const documentIdOfArea = getDocumentIdFromAreaId(areaId)
|
||||||
setIsEditAreaNameInputShowing(true)
|
setIsEditAreaNameInputShowing(true)
|
||||||
console.log('double click')
|
console.log('double click')
|
||||||
@ -132,6 +133,14 @@ function Sidebar() {
|
|||||||
setIsAddNewGroupInputShowing(false)
|
setIsAddNewGroupInputShowing(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onDocumentDoubleClickHandler = (docuemntId: string) => {
|
||||||
|
setIsEditDocumentNameInputShowing(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onDocumentInputBlur = () => {
|
||||||
|
setIsEditDocumentNameInputShowing(false)
|
||||||
|
}
|
||||||
|
|
||||||
const onCancelAddGroupClickHandler = () => {
|
const onCancelAddGroupClickHandler = () => {
|
||||||
setIsAddNewGroupInputShowing(false)
|
setIsAddNewGroupInputShowing(false)
|
||||||
}
|
}
|
||||||
@ -153,6 +162,17 @@ function Sidebar() {
|
|||||||
setIsEditAreaNameInputShowing(false)
|
setIsEditAreaNameInputShowing(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onConfirmDocumentNameChangeHandler = async (documentName: string) => {
|
||||||
|
const documentToUpdate = { ...getSelectedDocument() }
|
||||||
|
if (documentToUpdate) {
|
||||||
|
documentToUpdate.name = documentName
|
||||||
|
requestUpdateDocument(documentToUpdate)
|
||||||
|
.then(response => console.log('onConfirmDocumentNameChangeHandler response: ', response))
|
||||||
|
.catch(console.error)
|
||||||
|
}
|
||||||
|
setIsEditDocumentNameInputShowing(false)
|
||||||
|
}
|
||||||
|
|
||||||
const onConfirmAddDocumentClickHandler = async (groupId: string) => {
|
const onConfirmAddDocumentClickHandler = async (groupId: string) => {
|
||||||
const documentName = addDocumentTextInput.current?.value
|
const documentName = addDocumentTextInput.current?.value
|
||||||
if (!documentName) return
|
if (!documentName) return
|
||||||
@ -294,8 +314,10 @@ function Sidebar() {
|
|||||||
{group.documents.map((d, index) => (
|
{group.documents.map((d, index) => (
|
||||||
<li className='p-0 m-0' key={d.id}>
|
<li className='p-0 m-0' key={d.id}>
|
||||||
{!d.areas.length
|
{!d.areas.length
|
||||||
? <div
|
?
|
||||||
|
<div
|
||||||
onClick={() => onDocumentClickHandler(d.id)}
|
onClick={() => onDocumentClickHandler(d.id)}
|
||||||
|
onDoubleClick={() => onDocumentDoubleClickHandler(d.id)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
d.id === selectedDocumentId
|
d.id === selectedDocumentId
|
||||||
? 'bg-gray-900 text-white'
|
? 'bg-gray-900 text-white'
|
||||||
@ -303,7 +325,22 @@ function Sidebar() {
|
|||||||
'group items-center py-2 text-base font-medium rounded-b-md pl-10',
|
'group items-center py-2 text-base font-medium rounded-b-md pl-10',
|
||||||
index !== 0 ? 'rounded-t-md' : '',
|
index !== 0 ? 'rounded-t-md' : '',
|
||||||
)}>
|
)}>
|
||||||
<a
|
{selectedDocumentId === d.id && isEditDocumentNameInputShowing
|
||||||
|
? <input
|
||||||
|
type="text"
|
||||||
|
name="documentName"
|
||||||
|
id="documentName"
|
||||||
|
autoFocus
|
||||||
|
className="h-8 text-white placeholder-gray-400 bg-gray-900 bg-opacity-5 block w-full rounded-none rounded-l-md border-late-700 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||||
|
defaultValue={d.name}
|
||||||
|
onBlur={onDocumentInputBlur}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
onEnterHandler(event,
|
||||||
|
() => onConfirmDocumentNameChangeHandler(event.currentTarget.value))
|
||||||
|
}}
|
||||||
|
ref={editDocumentNameTextInput}
|
||||||
|
/>
|
||||||
|
: <a
|
||||||
role='button'
|
role='button'
|
||||||
className={classNames(
|
className={classNames(
|
||||||
d.id === selectedDocumentId
|
d.id === selectedDocumentId
|
||||||
@ -314,10 +351,12 @@ function Sidebar() {
|
|||||||
>
|
>
|
||||||
{d.name}
|
{d.name}
|
||||||
</a>
|
</a>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
: <details>
|
: <details>
|
||||||
<summary
|
<summary
|
||||||
onClick={() => onDocumentClickHandler(d.id)}
|
onClick={() => onDocumentClickHandler(d.id)}
|
||||||
|
onDoubleClick={() => onDocumentDoubleClickHandler(d.id)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
d.id === selectedDocumentId
|
d.id === selectedDocumentId
|
||||||
? 'bg-gray-900 text-white'
|
? 'bg-gray-900 text-white'
|
||||||
@ -326,7 +365,22 @@ function Sidebar() {
|
|||||||
index !== 0 ? 'rounded-t-md' : '',
|
index !== 0 ? 'rounded-t-md' : '',
|
||||||
|
|
||||||
)}>
|
)}>
|
||||||
<a
|
{selectedDocumentId === d.id && isEditDocumentNameInputShowing
|
||||||
|
? <input // TODO: this
|
||||||
|
type="text"
|
||||||
|
name="documentName"
|
||||||
|
id="documentName"
|
||||||
|
autoFocus
|
||||||
|
className="h-8 text-white placeholder-gray-400 bg-gray-900 bg-opacity-5 block w-full rounded-none rounded-l-md border-late-700 focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||||
|
defaultValue={d.name}
|
||||||
|
onBlur={onDocumentInputBlur}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
onEnterHandler(event,
|
||||||
|
() => onConfirmDocumentNameChangeHandler(event.currentTarget.value))
|
||||||
|
}}
|
||||||
|
ref={editDocumentNameTextInput}
|
||||||
|
/>
|
||||||
|
: <a
|
||||||
role='button'
|
role='button'
|
||||||
className={classNames(
|
className={classNames(
|
||||||
d.id === selectedDocumentId
|
d.id === selectedDocumentId
|
||||||
@ -337,6 +391,7 @@ function Sidebar() {
|
|||||||
>
|
>
|
||||||
{d.name}
|
{d.name}
|
||||||
</a>
|
</a>
|
||||||
|
}
|
||||||
</summary>
|
</summary>
|
||||||
<ul>
|
<ul>
|
||||||
{d.areas.map((a, index) => (
|
{d.areas.map((a, index) => (
|
||||||
@ -359,7 +414,7 @@ function Sidebar() {
|
|||||||
: <a
|
: <a
|
||||||
role='button'
|
role='button'
|
||||||
onClick={() => onAreaClick(a.id)}
|
onClick={() => onAreaClick(a.id)}
|
||||||
onDoubleClick={() => onAreaDoubleclick(a.id)}
|
onDoubleClick={() => onAreaDoubleClick(a.id)}
|
||||||
className={classNames('text-gray-300 hover:bg-gray-700 hover:text-white',
|
className={classNames('text-gray-300 hover:bg-gray-700 hover:text-white',
|
||||||
'group w-full flex items-center pr-2 py-2 text-left font-medium pl-8 text-xs',
|
'group w-full flex items-center pr-2 py-2 text-left font-medium pl-8 text-xs',
|
||||||
'rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 py-2 select-none',
|
'rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 py-2 select-none',
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { DiffEditor } from '@monaco-editor/react'
|
import { loader, DiffEditor } from '@monaco-editor/react'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useProject } from '../../context/Project/provider'
|
import { useProject } from '../../context/Project/provider'
|
||||||
import type { DiffOnMount } from '@monaco-editor/react/'
|
import type { DiffOnMount } from '@monaco-editor/react/'
|
||||||
@ -6,18 +6,29 @@ import TextEditorButtons from './TextEditorButtons'
|
|||||||
import createDiffEditorInteractions from '../../useCases/createDiffEditorInteractions'
|
import createDiffEditorInteractions from '../../useCases/createDiffEditorInteractions'
|
||||||
import TextPreview from './TextPreview'
|
import TextPreview from './TextPreview'
|
||||||
import createDebounce from '../../utils/createDebounce'
|
import createDebounce from '../../utils/createDebounce'
|
||||||
|
import LanguageSelect from './LanguageSelect'
|
||||||
|
|
||||||
|
loader.config({
|
||||||
|
paths: {
|
||||||
|
vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.34.0/min/vs',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
let editorInteractions: ReturnType<typeof createDiffEditorInteractions>
|
let editorInteractions: ReturnType<typeof createDiffEditorInteractions>
|
||||||
|
const editorHeightOffset = 234
|
||||||
|
|
||||||
const TextEditor = () => {
|
const TextEditor = () => {
|
||||||
const { selectedDocumentId, getProcessedAreasByDocumentId, requestUpdateDocumentUserMarkdown, getUserMarkdownByDocumentId } = useProject()
|
const { getSelectedDocument, getProcessedAreasByDocumentId, requestUpdateDocumentUserMarkdown, getUserMarkdownByDocumentId } = useProject()
|
||||||
const [editorHeight, setEditorHeight] = useState(window.innerHeight - 200)
|
const [editorHeight, setEditorHeight] = useState(window.innerHeight - editorHeightOffset)
|
||||||
const [editorValue, setEditorValue] = useState('')
|
const [editorValue, setEditorValue] = useState('')
|
||||||
const [isEditorReady, setIsEditorReady] = useState(false)
|
const [isEditorReady, setIsEditorReady] = useState(false)
|
||||||
const [isPreviewOpen, setIsPreviewOpen] = useState(false)
|
const [isPreviewOpen, setIsPreviewOpen] = useState(false)
|
||||||
const [modifiedEditorValue, setModifiedEditorValue] = useState('')
|
const [modifiedEditorValue, setModifiedEditorValue] = useState('')
|
||||||
|
|
||||||
const handleEditorDidMount: DiffOnMount = async (editor, monaco) => {
|
const selectedDocument = getSelectedDocument()
|
||||||
|
const selectedDocumentId = selectedDocument?.id || ''
|
||||||
|
|
||||||
|
const handleEditorDidMount: DiffOnMount = async (editor, _) => {
|
||||||
const currentDocumentId = selectedDocumentId
|
const currentDocumentId = selectedDocumentId
|
||||||
|
|
||||||
editorInteractions = createDiffEditorInteractions(editor)
|
editorInteractions = createDiffEditorInteractions(editor)
|
||||||
@ -66,18 +77,23 @@ const TextEditor = () => {
|
|||||||
}, [selectedDocumentId, getProcessedAreasByDocumentId])
|
}, [selectedDocumentId, getProcessedAreasByDocumentId])
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
window.addEventListener('resize', () => {
|
||||||
setEditorHeight(window.innerHeight - 200)
|
setEditorHeight(window.innerHeight - editorHeightOffset)
|
||||||
})
|
})
|
||||||
|
|
||||||
return <div className='relative m-0 p-0'>
|
return <div className='m-0 p-0 relative'>
|
||||||
|
<span className="flex z-0 rounded-md shadow-sm mb-2 mt-2 justify-between">
|
||||||
{isEditorReady
|
{isEditorReady
|
||||||
? <TextEditorButtons
|
? <>
|
||||||
|
<TextEditorButtons
|
||||||
isPreviewOpen={isPreviewOpen}
|
isPreviewOpen={isPreviewOpen}
|
||||||
togglePreview={() => setIsPreviewOpen(!isPreviewOpen)}
|
togglePreview={() => setIsPreviewOpen(!isPreviewOpen)}
|
||||||
editorInteractions={editorInteractions}
|
editorInteractions={editorInteractions}
|
||||||
/>
|
/>
|
||||||
|
<LanguageSelect shouldUpdateDocument defaultLanguage={selectedDocument?.defaultLanguage} />
|
||||||
|
</>
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
|
</span>
|
||||||
<DiffEditor
|
<DiffEditor
|
||||||
original={editorValue}
|
original={editorValue}
|
||||||
modified={modifiedEditorValue}
|
modified={modifiedEditorValue}
|
||||||
@ -87,6 +103,7 @@ const TextEditor = () => {
|
|||||||
options={{
|
options={{
|
||||||
renderMarginRevertIcon: true,
|
renderMarginRevertIcon: true,
|
||||||
enableSplitViewResizing: false,
|
enableSplitViewResizing: false,
|
||||||
|
glyphMargin: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { ListBulletIcon, MinusIcon } from '@heroicons/react/20/solid'
|
import { ListBulletIcon, MinusIcon } from '@heroicons/react/20/solid'
|
||||||
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline'
|
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline'
|
||||||
import createDiffEditorInteractions, { MarkdownOperator } from '../../useCases/createDiffEditorInteractions'
|
import createDiffEditorInteractions, { MarkdownOperator } from '../../useCases/createDiffEditorInteractions'
|
||||||
|
import classNames from '../../utils/classNames'
|
||||||
function classNames(...classes: any[]) {
|
|
||||||
return classes.filter(Boolean).join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
editorInteractions: ReturnType<typeof createDiffEditorInteractions>
|
editorInteractions: ReturnType<typeof createDiffEditorInteractions>
|
||||||
@ -14,7 +11,8 @@ type Props = {
|
|||||||
|
|
||||||
const TextEditorButtons = (props: Props) => {
|
const TextEditorButtons = (props: Props) => {
|
||||||
const { editorInteractions, togglePreview } = props
|
const { editorInteractions, togglePreview } = props
|
||||||
return <span className="isolate inline-flex rounded-md shadow-sm">
|
|
||||||
|
return <span className="inline-flex rounded-md shadow-sm">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={togglePreview}
|
onClick={togglePreview}
|
||||||
@ -143,7 +141,7 @@ const TextEditorButtons = (props: Props) => {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => editorInteractions.insertMarkdownOperator(MarkdownOperator.DIVIDER)}
|
onClick={() => editorInteractions.insertMarkdownOperator(MarkdownOperator.DIVIDER)}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'text-sm relative inline-flex items-center rounded-r-md border',
|
'text-sm relative inline-flex items-center border',
|
||||||
'border-gray-300 bg-white px-2 py-0 text-gray-700 hover:bg-gray-50',
|
'border-gray-300 bg-white px-2 py-0 text-gray-700 hover:bg-gray-50',
|
||||||
'focus:z-10 focus:border-indigo-500 focus:outline-none focus:ring-1',
|
'focus:z-10 focus:border-indigo-500 focus:outline-none focus:ring-1',
|
||||||
'focus:ring-indigo-500 italic',
|
'focus:ring-indigo-500 italic',
|
||||||
@ -151,6 +149,8 @@ const TextEditorButtons = (props: Props) => {
|
|||||||
<span className="sr-only">Divider</span>
|
<span className="sr-only">Divider</span>
|
||||||
<MinusIcon className="h-5 w-5" aria-hidden="true" />
|
<MinusIcon className="h-5 w-5" aria-hidden="true" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ type Props = { markdown: string, height: number }
|
|||||||
|
|
||||||
const TextPreview = (props: Props) => (
|
const TextPreview = (props: Props) => (
|
||||||
<div
|
<div
|
||||||
className='absolute w-[calc(50%-14px)] top-[30px] bg-white overflow-y-scroll p-4 m-0'
|
className='absolute w-[calc(50%-14px)] top-[46px] bg-white overflow-y-scroll p-4 m-0'
|
||||||
style={{ 'height': `${props.height}px` }}>
|
style={{ 'height': `${props.height}px` }}>
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
components={{
|
components={{
|
||||||
|
|||||||
@ -1,15 +1,20 @@
|
|||||||
import { useNavigation } from '../../context/Navigation/provider'
|
import { useNavigation } from '../../context/Navigation/provider'
|
||||||
import { workspaces } from '../../context/Navigation/types'
|
import { workspaces } from '../../context/Navigation/types'
|
||||||
|
import classNames from '../../utils/classNames'
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ displayName: 'Processor', type: workspaces.PROCESSOR },
|
{ displayName: 'Processor', type: workspaces.PROCESSOR },
|
||||||
{ displayName: 'Text Editor', type: workspaces.TEXTEDITOR },
|
{ displayName: 'Text Editor', type: workspaces.TEXTEDITOR },
|
||||||
{ displayName: 'Translator', type: workspaces.TRANSLATOR },
|
{ displayName: 'Translator', type: workspaces.TRANSLATOR, disabled: true, },
|
||||||
{ displayName: 'Details', type: workspaces.DETAILS },
|
{ displayName: 'Details', type: workspaces.DETAILS, disabled: true, },
|
||||||
]
|
]
|
||||||
|
|
||||||
function classNames(...classes: string[]) {
|
const getTabClasses = (isTabSelected: boolean, isDisabled?: boolean) => {
|
||||||
return classes.filter(Boolean).join(' ')
|
if (isDisabled) return classNames('cursor-not-allowed w-1/4 py-4 px-1 text-center border-b-2 font-medium text-gray-200 text-sm')
|
||||||
|
|
||||||
|
const baseClasses = 'cursor-pointer w-1/4 py-4 px-1 text-center border-b-2 font-medium text-sm'
|
||||||
|
if (isTabSelected) return classNames(baseClasses, 'border-indigo-500 text-indigo-600')
|
||||||
|
else return classNames(baseClasses, 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300')
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ToolTabs() {
|
export default function ToolTabs() {
|
||||||
@ -24,14 +29,12 @@ export default function ToolTabs() {
|
|||||||
<nav className="-mb-px flex" aria-label="Tabs">
|
<nav className="-mb-px flex" aria-label="Tabs">
|
||||||
{tabs.map((tab) => (
|
{tabs.map((tab) => (
|
||||||
<a
|
<a
|
||||||
|
aria-disabled={tab.disabled}
|
||||||
key={tab.displayName}
|
key={tab.displayName}
|
||||||
onClick={_ => setSelectedWorkspace(tab.type)}
|
onClick={_ => {
|
||||||
className={classNames(
|
if (!tab.disabled) setSelectedWorkspace(tab.type)
|
||||||
getIsSelectedTab(tab.type)
|
}}
|
||||||
? 'border-indigo-500 text-indigo-600'
|
className={getTabClasses(getIsSelectedTab(tab.type), tab.disabled)}
|
||||||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300',
|
|
||||||
'cursor-pointer w-1/4 py-4 px-1 text-center border-b-2 font-medium text-sm'
|
|
||||||
)}
|
|
||||||
aria-current={getIsSelectedTab(tab.type) ? 'page' : undefined}
|
aria-current={getIsSelectedTab(tab.type) ? 'page' : undefined}
|
||||||
>
|
>
|
||||||
{tab.displayName}
|
{tab.displayName}
|
||||||
|
|||||||
@ -23,6 +23,7 @@ const makeDefaultProject = (): ProjectContextType => ({
|
|||||||
createNewProject: (name: string) => Promise.resolve(new ipc.Session()),
|
createNewProject: (name: string) => Promise.resolve(new ipc.Session()),
|
||||||
requestUpdateCurrentUser: (updatedUserProps: UserProps) => Promise.resolve(new ipc.User()),
|
requestUpdateCurrentUser: (updatedUserProps: UserProps) => Promise.resolve(new ipc.User()),
|
||||||
requestChooseUserAvatar: () => Promise.resolve(''),
|
requestChooseUserAvatar: () => Promise.resolve(''),
|
||||||
|
requestUpdateDocument: ({}) => Promise.resolve(new ipc.Document),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default makeDefaultProject
|
export default makeDefaultProject
|
||||||
|
|||||||
@ -7,9 +7,10 @@ import {
|
|||||||
RequestAddDocument, RequestAddDocumentGroup, RequestAddProcessedArea,
|
RequestAddDocument, RequestAddDocumentGroup, RequestAddProcessedArea,
|
||||||
RequestUpdateArea, RequestUpdateCurrentUser, RequestUpdateDocumentUserMarkdown,
|
RequestUpdateArea, RequestUpdateCurrentUser, RequestUpdateDocumentUserMarkdown,
|
||||||
RequestChooseUserAvatar,
|
RequestChooseUserAvatar,
|
||||||
|
RequestUpdateDocument,
|
||||||
} from '../../wailsjs/wailsjs/go/ipc/Channel'
|
} from '../../wailsjs/wailsjs/go/ipc/Channel'
|
||||||
import { ipc } from '../../wailsjs/wailsjs/go/models'
|
import { ipc } from '../../wailsjs/wailsjs/go/models'
|
||||||
import { AddAreaProps, AreaProps, ProjectContextType, ProjectProps, UserProps } from './types'
|
import { AddAreaProps, AreaProps, ProjectContextType, ProjectProps, UpdateDocumentRequest, UserProps } from './types'
|
||||||
import makeDefaultProject from './makeDefaultProject'
|
import makeDefaultProject from './makeDefaultProject'
|
||||||
|
|
||||||
const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
|
const ProjectContext = createContext<ProjectContextType>(makeDefaultProject())
|
||||||
@ -122,6 +123,13 @@ export function ProjectProvider({ children, projectProps }: Props) {
|
|||||||
return filePathResponse
|
return filePathResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const requestUpdateDocument = async (docuemntProps: UpdateDocumentRequest) => {
|
||||||
|
console.log('request: ', docuemntProps)
|
||||||
|
const response = await RequestUpdateDocument(new ipc.Document(docuemntProps))
|
||||||
|
await updateDocuments()
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!documents.length && !groups.length) updateDocuments()
|
if (!documents.length && !groups.length) updateDocuments()
|
||||||
}, [documents.length, groups.length])
|
}, [documents.length, groups.length])
|
||||||
@ -148,6 +156,7 @@ export function ProjectProvider({ children, projectProps }: Props) {
|
|||||||
createNewProject,
|
createNewProject,
|
||||||
requestUpdateCurrentUser,
|
requestUpdateCurrentUser,
|
||||||
requestChooseUserAvatar,
|
requestChooseUserAvatar,
|
||||||
|
requestUpdateDocument,
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ProjectContext.Provider value={value}>
|
return <ProjectContext.Provider value={value}>
|
||||||
|
|||||||
@ -26,6 +26,16 @@ export type UserProps = {
|
|||||||
email?: string
|
email?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type UpdateDocumentRequest = {
|
||||||
|
id?: string,
|
||||||
|
projectId?: string,
|
||||||
|
groupId?: string,
|
||||||
|
name?: string,
|
||||||
|
path?: string,
|
||||||
|
areas?: ipc.Area[]
|
||||||
|
defaultLanguage?: ipc.Language
|
||||||
|
}
|
||||||
|
|
||||||
export type ProjectContextType = {
|
export type ProjectContextType = {
|
||||||
getSelectedDocument: () => ipc.Document | undefined
|
getSelectedDocument: () => ipc.Document | undefined
|
||||||
getAreaById: (areaId: string) => ipc.Area | undefined
|
getAreaById: (areaId: string) => ipc.Area | undefined
|
||||||
@ -45,4 +55,5 @@ export type ProjectContextType = {
|
|||||||
createNewProject: (name: string) => Promise<ipc.Session>
|
createNewProject: (name: string) => Promise<ipc.Session>
|
||||||
requestUpdateCurrentUser: (updatedUserProps: UserProps) => Promise<ipc.User>
|
requestUpdateCurrentUser: (updatedUserProps: UserProps) => Promise<ipc.User>
|
||||||
requestChooseUserAvatar: () => Promise<string>
|
requestChooseUserAvatar: () => Promise<string>
|
||||||
|
requestUpdateDocument: (request: UpdateDocumentRequest) => Promise<ipc.Document>
|
||||||
} & ProjectProps
|
} & ProjectProps
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { NextPage } from 'next'
|
import { NextPage } from 'next'
|
||||||
import { useEffect } from 'react'
|
|
||||||
import MainHead from '../components/head'
|
import MainHead from '../components/head'
|
||||||
import MainProject from '../components/project/Main'
|
import MainProject from '../components/project/Main'
|
||||||
import User from '../components/settings/User'
|
import User from '../components/settings/User'
|
||||||
@ -12,12 +11,7 @@ import { useProject } from '../context/Project/provider'
|
|||||||
const Home: NextPage = () => {
|
const Home: NextPage = () => {
|
||||||
|
|
||||||
const { currentSession } = useProject()
|
const { currentSession } = useProject()
|
||||||
const { selectedMainPage, setSelectedMainPage } = useNavigation()
|
const { selectedMainPage } = useNavigation()
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!currentSession?.user?.localId) setSelectedMainPage(mainPages.EDITUSER)
|
|
||||||
else if (!currentSession?.project?.id) setSelectedMainPage(mainPages.SELECTPROJECT)
|
|
||||||
},)
|
|
||||||
|
|
||||||
const renderSelectedMainPage = () => {
|
const renderSelectedMainPage = () => {
|
||||||
if (selectedMainPage === mainPages.SELECTPROJECT) return <MainProject />
|
if (selectedMainPage === mainPages.SELECTPROJECT) return <MainProject />
|
||||||
@ -31,12 +25,10 @@ const Home: NextPage = () => {
|
|||||||
else return <MainProject />
|
else return <MainProject />
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <>
|
||||||
<>
|
|
||||||
<MainHead />
|
<MainHead />
|
||||||
{ renderSelectedMainPage() }
|
{renderSelectedMainPage()}
|
||||||
</>
|
</>
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Home
|
export default Home
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export enum MarkdownOperator {
|
|||||||
ITALLICS = '_',
|
ITALLICS = '_',
|
||||||
BOLD = '**',
|
BOLD = '**',
|
||||||
BULLET = '* ',
|
BULLET = '* ',
|
||||||
DIVIDER = '\n\n---\n\n'
|
DIVIDER = '\n\n---\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrapperOperators = [
|
const wrapperOperators = [
|
||||||
@ -43,8 +43,6 @@ const createDiffEditorInteractions = (editor: monaco.editor.IStandaloneDiffEdito
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (operator == MarkdownOperator.DIVIDER) {
|
if (operator == MarkdownOperator.DIVIDER) {
|
||||||
console.log('lineOfCursor:', lineOfCursor)
|
|
||||||
console.log('lengthOfLine:', lengthOfLine)
|
|
||||||
range = {
|
range = {
|
||||||
startLineNumber,
|
startLineNumber,
|
||||||
startColumn: lengthOfLine,
|
startColumn: lengthOfLine,
|
||||||
@ -72,12 +70,9 @@ const createDiffEditorInteractions = (editor: monaco.editor.IStandaloneDiffEdito
|
|||||||
newText = `${operator}${modifiedEditor.getModel()?.getValueInRange(range)}`
|
newText = `${operator}${modifiedEditor.getModel()?.getValueInRange(range)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiedEditor.executeEdits('editor', [{
|
modifiedEditor.executeEdits('editor', [{ range, text: newText }])
|
||||||
range,
|
|
||||||
text: newText
|
|
||||||
}])
|
|
||||||
|
|
||||||
modifiedEditor.pushUndoStop()
|
modifiedEditor.pushUndoStop()
|
||||||
|
modifiedEditor.focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
frontend/utils/classNames.ts
Normal file
3
frontend/utils/classNames.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
const classNames = (...classes: any[]) => classes.filter(Boolean).join(' ')
|
||||||
|
|
||||||
|
export default classNames
|
||||||
8
frontend/utils/getSupportedLanguages.ts
Normal file
8
frontend/utils/getSupportedLanguages.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { GetSuppportedLanguages } from '../wailsjs/wailsjs/go/ipc/Channel'
|
||||||
|
|
||||||
|
const getSupportedLanguages = async () => {
|
||||||
|
const response = await GetSuppportedLanguages()
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getSupportedLanguages
|
||||||
4
frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts
vendored
4
frontend/wailsjs/wailsjs/go/ipc/Channel.d.ts
vendored
@ -14,6 +14,8 @@ export function GetDocuments():Promise<ipc.GetDocumentsResponse>;
|
|||||||
|
|
||||||
export function GetProcessedAreasByDocumentId(arg1:string):Promise<Array<ipc.ProcessedArea>>;
|
export function GetProcessedAreasByDocumentId(arg1:string):Promise<Array<ipc.ProcessedArea>>;
|
||||||
|
|
||||||
|
export function GetSuppportedLanguages():Promise<Array<ipc.Language>>;
|
||||||
|
|
||||||
export function GetUserMarkdownByDocumentId(arg1:string):Promise<ipc.UserMarkdown>;
|
export function GetUserMarkdownByDocumentId(arg1:string):Promise<ipc.UserMarkdown>;
|
||||||
|
|
||||||
export function RequestAddArea(arg1:string,arg2:ipc.Area):Promise<ipc.Area>;
|
export function RequestAddArea(arg1:string,arg2:ipc.Area):Promise<ipc.Area>;
|
||||||
@ -30,4 +32,6 @@ export function RequestUpdateArea(arg1:ipc.Area):Promise<ipc.Area>;
|
|||||||
|
|
||||||
export function RequestUpdateCurrentUser(arg1:ipc.User):Promise<ipc.User>;
|
export function RequestUpdateCurrentUser(arg1:ipc.User):Promise<ipc.User>;
|
||||||
|
|
||||||
|
export function RequestUpdateDocument(arg1:ipc.Document):Promise<ipc.Document>;
|
||||||
|
|
||||||
export function RequestUpdateDocumentUserMarkdown(arg1:string,arg2:string):Promise<ipc.UserMarkdown>;
|
export function RequestUpdateDocumentUserMarkdown(arg1:string,arg2:string):Promise<ipc.UserMarkdown>;
|
||||||
|
|||||||
@ -26,6 +26,10 @@ export function GetProcessedAreasByDocumentId(arg1) {
|
|||||||
return window['go']['ipc']['Channel']['GetProcessedAreasByDocumentId'](arg1);
|
return window['go']['ipc']['Channel']['GetProcessedAreasByDocumentId'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GetSuppportedLanguages() {
|
||||||
|
return window['go']['ipc']['Channel']['GetSuppportedLanguages']();
|
||||||
|
}
|
||||||
|
|
||||||
export function GetUserMarkdownByDocumentId(arg1) {
|
export function GetUserMarkdownByDocumentId(arg1) {
|
||||||
return window['go']['ipc']['Channel']['GetUserMarkdownByDocumentId'](arg1);
|
return window['go']['ipc']['Channel']['GetUserMarkdownByDocumentId'](arg1);
|
||||||
}
|
}
|
||||||
@ -58,6 +62,10 @@ export function RequestUpdateCurrentUser(arg1) {
|
|||||||
return window['go']['ipc']['Channel']['RequestUpdateCurrentUser'](arg1);
|
return window['go']['ipc']['Channel']['RequestUpdateCurrentUser'](arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function RequestUpdateDocument(arg1) {
|
||||||
|
return window['go']['ipc']['Channel']['RequestUpdateDocument'](arg1);
|
||||||
|
}
|
||||||
|
|
||||||
export function RequestUpdateDocumentUserMarkdown(arg1, arg2) {
|
export function RequestUpdateDocumentUserMarkdown(arg1, arg2) {
|
||||||
return window['go']['ipc']['Channel']['RequestUpdateDocumentUserMarkdown'](arg1, arg2);
|
return window['go']['ipc']['Channel']['RequestUpdateDocumentUserMarkdown'](arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,21 @@
|
|||||||
export namespace ipc {
|
export namespace ipc {
|
||||||
|
|
||||||
|
export class Language {
|
||||||
|
displayName: string;
|
||||||
|
processCode: string;
|
||||||
|
translateCode: string;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new Language(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.displayName = source["displayName"];
|
||||||
|
this.processCode = source["processCode"];
|
||||||
|
this.translateCode = source["translateCode"];
|
||||||
|
}
|
||||||
|
}
|
||||||
export class Area {
|
export class Area {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -7,6 +23,7 @@ export namespace ipc {
|
|||||||
startY: number;
|
startY: number;
|
||||||
endX: number;
|
endX: number;
|
||||||
endY: number;
|
endY: number;
|
||||||
|
language: Language;
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new Area(source);
|
return new Area(source);
|
||||||
@ -20,6 +37,25 @@ export namespace ipc {
|
|||||||
this.startY = source["startY"];
|
this.startY = source["startY"];
|
||||||
this.endX = source["endX"];
|
this.endX = source["endX"];
|
||||||
this.endY = source["endY"];
|
this.endY = source["endY"];
|
||||||
|
this.language = this.convertValues(source["language"], Language);
|
||||||
|
}
|
||||||
|
|
||||||
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
if (!a) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a.slice) {
|
||||||
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
|
} else if ("object" === typeof a) {
|
||||||
|
if (asMap) {
|
||||||
|
for (const key of Object.keys(a)) {
|
||||||
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export class Document {
|
export class Document {
|
||||||
@ -29,6 +65,7 @@ export namespace ipc {
|
|||||||
path: string;
|
path: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
areas: Area[];
|
areas: Area[];
|
||||||
|
defaultLanguage: Language;
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new Document(source);
|
return new Document(source);
|
||||||
@ -42,6 +79,7 @@ export namespace ipc {
|
|||||||
this.path = source["path"];
|
this.path = source["path"];
|
||||||
this.projectId = source["projectId"];
|
this.projectId = source["projectId"];
|
||||||
this.areas = this.convertValues(source["areas"], Area);
|
this.areas = this.convertValues(source["areas"], Area);
|
||||||
|
this.defaultLanguage = this.convertValues(source["defaultLanguage"], Language);
|
||||||
}
|
}
|
||||||
|
|
||||||
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
@ -113,6 +151,7 @@ export namespace ipc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class User {
|
export class User {
|
||||||
id: string;
|
id: string;
|
||||||
localId: string;
|
localId: string;
|
||||||
@ -335,9 +374,45 @@ export namespace ipc {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export class ProjectSettings {
|
||||||
|
defaultProcessLanguage: Language;
|
||||||
|
defaultTranslateTargetLanguage: Language;
|
||||||
|
IsHosted: boolean;
|
||||||
|
|
||||||
|
static createFrom(source: any = {}) {
|
||||||
|
return new ProjectSettings(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(source: any = {}) {
|
||||||
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
|
this.defaultProcessLanguage = this.convertValues(source["defaultProcessLanguage"], Language);
|
||||||
|
this.defaultTranslateTargetLanguage = this.convertValues(source["defaultTranslateTargetLanguage"], Language);
|
||||||
|
this.IsHosted = source["IsHosted"];
|
||||||
|
}
|
||||||
|
|
||||||
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
if (!a) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a.slice) {
|
||||||
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
|
} else if ("object" === typeof a) {
|
||||||
|
if (asMap) {
|
||||||
|
for (const key of Object.keys(a)) {
|
||||||
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
export class Project {
|
export class Project {
|
||||||
id: string;
|
id: string;
|
||||||
|
organizationId: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
settings: ProjectSettings;
|
||||||
|
|
||||||
static createFrom(source: any = {}) {
|
static createFrom(source: any = {}) {
|
||||||
return new Project(source);
|
return new Project(source);
|
||||||
@ -346,9 +421,30 @@ export namespace ipc {
|
|||||||
constructor(source: any = {}) {
|
constructor(source: any = {}) {
|
||||||
if ('string' === typeof source) source = JSON.parse(source);
|
if ('string' === typeof source) source = JSON.parse(source);
|
||||||
this.id = source["id"];
|
this.id = source["id"];
|
||||||
|
this.organizationId = source["organizationId"];
|
||||||
this.name = source["name"];
|
this.name = source["name"];
|
||||||
|
this.settings = this.convertValues(source["settings"], ProjectSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
||||||
|
if (!a) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
if (a.slice) {
|
||||||
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
||||||
|
} else if ("object" === typeof a) {
|
||||||
|
if (asMap) {
|
||||||
|
for (const key of Object.keys(a)) {
|
||||||
|
a[key] = new classs(a[key]);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
return new classs(a);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Session {
|
export class Session {
|
||||||
project: Project;
|
project: Project;
|
||||||
organization: Organization;
|
organization: Organization;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package ipc
|
package ipc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
app "textualize/core/App"
|
app "textualize/core/App"
|
||||||
document "textualize/core/Document"
|
document "textualize/core/Document"
|
||||||
session "textualize/core/Session"
|
session "textualize/core/Session"
|
||||||
@ -19,7 +20,15 @@ func (c *Channel) GetDocumentById(id string) Document {
|
|||||||
var jsonAreas []Area
|
var jsonAreas []Area
|
||||||
|
|
||||||
for _, a := range foundDocument.Areas {
|
for _, a := range foundDocument.Areas {
|
||||||
jsonAreas = append(jsonAreas, Area(a))
|
jsonAreas = append(jsonAreas, Area{
|
||||||
|
Id: a.Id,
|
||||||
|
Name: a.Name,
|
||||||
|
StartX: a.StartX,
|
||||||
|
StartY: a.StartY,
|
||||||
|
EndX: a.EndX,
|
||||||
|
EndY: a.EndY,
|
||||||
|
Language: Language(a.Language),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
response := Document{
|
response := Document{
|
||||||
Id: foundDocument.Id,
|
Id: foundDocument.Id,
|
||||||
@ -44,7 +53,15 @@ func (c *Channel) GetDocuments() GetDocumentsResponse {
|
|||||||
for _, d := range documents {
|
for _, d := range documents {
|
||||||
jsonAreas := make([]Area, 0)
|
jsonAreas := make([]Area, 0)
|
||||||
for _, a := range d.Areas {
|
for _, a := range d.Areas {
|
||||||
jsonAreas = append(jsonAreas, Area(a))
|
jsonAreas = append(jsonAreas, Area{
|
||||||
|
Id: a.Id,
|
||||||
|
Name: a.Name,
|
||||||
|
StartX: a.StartX,
|
||||||
|
StartY: a.StartY,
|
||||||
|
EndX: a.EndX,
|
||||||
|
EndY: a.EndY,
|
||||||
|
Language: Language(a.Language),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonDocument := Document{
|
jsonDocument := Document{
|
||||||
@ -54,6 +71,7 @@ func (c *Channel) GetDocuments() GetDocumentsResponse {
|
|||||||
Path: d.Path,
|
Path: d.Path,
|
||||||
ProjectId: d.ProjectId,
|
ProjectId: d.ProjectId,
|
||||||
Areas: jsonAreas,
|
Areas: jsonAreas,
|
||||||
|
DefaultLanguage: Language(d.DefaultLanguage),
|
||||||
}
|
}
|
||||||
response.Documents = append(response.Documents, jsonDocument)
|
response.Documents = append(response.Documents, jsonDocument)
|
||||||
}
|
}
|
||||||
@ -182,9 +200,14 @@ func (c *Channel) RequestAddArea(documentId string, area Area) Area {
|
|||||||
EndX: area.EndX,
|
EndX: area.EndX,
|
||||||
StartY: area.StartY,
|
StartY: area.StartY,
|
||||||
EndY: area.EndY,
|
EndY: area.EndY,
|
||||||
|
Language: app.Language(area.Language),
|
||||||
}
|
}
|
||||||
foundDocument.AddArea(newArea)
|
foundDocument.AddArea(newArea)
|
||||||
return Area(newArea)
|
|
||||||
|
responseArea := area
|
||||||
|
responseArea.Id = id
|
||||||
|
|
||||||
|
return responseArea
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Channel) RequestUpdateArea(updatedArea Area) Area {
|
func (c *Channel) RequestUpdateArea(updatedArea Area) Area {
|
||||||
@ -206,11 +229,41 @@ func (c *Channel) RequestUpdateArea(updatedArea Area) Area {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Area{
|
return Area{
|
||||||
Id: updatedArea.Id,
|
Id: areaToUpdate.Id,
|
||||||
Name: updatedArea.Name,
|
Name: areaToUpdate.Name,
|
||||||
StartX: updatedArea.StartX,
|
StartX: areaToUpdate.StartX,
|
||||||
StartY: updatedArea.StartY,
|
StartY: areaToUpdate.StartY,
|
||||||
EndX: updatedArea.EndX,
|
EndX: areaToUpdate.EndX,
|
||||||
EndY: updatedArea.EndY,
|
EndY: areaToUpdate.EndY,
|
||||||
|
Language: Language(areaToUpdate.Language),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Channel) RequestUpdateDocument(updatedDocument Document) Document {
|
||||||
|
documentToUpdate := document.GetDocumentCollection().GetDocumentById(updatedDocument.Id)
|
||||||
|
|
||||||
|
if documentToUpdate == nil {
|
||||||
|
return Document{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updatedDocument.Id != "" {
|
||||||
|
documentToUpdate.Id = updatedDocument.Id
|
||||||
|
}
|
||||||
|
if updatedDocument.Name != "" {
|
||||||
|
documentToUpdate.Name = updatedDocument.Name
|
||||||
|
}
|
||||||
|
if updatedDocument.GroupId != "" {
|
||||||
|
documentToUpdate.GroupId = updatedDocument.GroupId
|
||||||
|
}
|
||||||
|
if updatedDocument.Path != "" {
|
||||||
|
documentToUpdate.Path = updatedDocument.Path
|
||||||
|
}
|
||||||
|
if updatedDocument.DefaultLanguage.DisplayName != "" {
|
||||||
|
documentToUpdate.DefaultLanguage = app.Language(updatedDocument.DefaultLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("updated doc")
|
||||||
|
fmt.Println(document.GetDocumentCollection().GetDocumentById(updatedDocument.Id))
|
||||||
|
|
||||||
|
return updatedDocument
|
||||||
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ type Document struct {
|
|||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
ProjectId string `json:"projectId"`
|
ProjectId string `json:"projectId"`
|
||||||
Areas []Area `json:"areas"`
|
Areas []Area `json:"areas"`
|
||||||
|
DefaultLanguage Language `json:"defaultLanguage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DocumentCollection struct {
|
type DocumentCollection struct {
|
||||||
@ -34,6 +35,7 @@ type Area struct {
|
|||||||
StartY int `json:"startY"`
|
StartY int `json:"startY"`
|
||||||
EndX int `json:"endX"`
|
EndX int `json:"endX"`
|
||||||
EndY int `json:"endY"`
|
EndY int `json:"endY"`
|
||||||
|
Language Language `json:"language"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessedBoundingBox struct {
|
type ProcessedBoundingBox struct {
|
||||||
@ -98,7 +100,15 @@ type Organization struct {
|
|||||||
|
|
||||||
type Project struct {
|
type Project struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
OrganizationId string `json:"organizationId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Settings ProjectSettings `json:"settings"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProjectSettings struct {
|
||||||
|
DefaultProcessLanguage Language `json:"defaultProcessLanguage"`
|
||||||
|
DefaultTranslateTargetLanguage Language `json:"defaultTranslateTargetLanguage"`
|
||||||
|
IsHosted bool `json:"IsHosted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
@ -106,3 +116,9 @@ type Session struct {
|
|||||||
Organization Organization `json:"organization"`
|
Organization Organization `json:"organization"`
|
||||||
User User `json:"user"`
|
User User `json:"user"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Language struct {
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
ProcessCode string `json:"processCode"`
|
||||||
|
TranslateCode string `json:"translateCode"`
|
||||||
|
}
|
||||||
|
|||||||
@ -17,8 +17,22 @@ func (c *Channel) GetCurrentSession() Session {
|
|||||||
sessionUsers = append(sessionUsers, User(u))
|
sessionUsers = append(sessionUsers, User(u))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentProject := currentSession.Project
|
||||||
|
currentDefaultProcessLanguage := Language(currentProject.Settings.DefaultProcessLanguage)
|
||||||
|
currentDefaultTranslateTargetLanguage := Language(currentProject.Settings.DefaultTranslateTargetLanguage)
|
||||||
|
project := Project{
|
||||||
|
Id: currentProject.Id,
|
||||||
|
Name: currentProject.Name,
|
||||||
|
OrganizationId: currentProject.OrganizationId,
|
||||||
|
Settings: ProjectSettings{
|
||||||
|
DefaultProcessLanguage: currentDefaultProcessLanguage,
|
||||||
|
DefaultTranslateTargetLanguage: currentDefaultTranslateTargetLanguage,
|
||||||
|
IsHosted: currentProject.Settings.IsHosted,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
return Session{
|
return Session{
|
||||||
Project: Project(currentSession.Project),
|
Project: Project(project),
|
||||||
User: User(currentSession.User),
|
User: User(currentSession.User),
|
||||||
Organization: Organization{
|
Organization: Organization{
|
||||||
Id: currentSession.Organization.Id,
|
Id: currentSession.Organization.Id,
|
||||||
@ -34,6 +48,7 @@ func (c *Channel) CreateNewProject(name string) Session {
|
|||||||
|
|
||||||
currentSession.Project = session.Project{
|
currentSession.Project = session.Project{
|
||||||
Id: uuid.NewString(),
|
Id: uuid.NewString(),
|
||||||
|
OrganizationId: currentSession.Project.OrganizationId,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,3 +101,15 @@ func (c *Channel) RequestChooseUserAvatar() string {
|
|||||||
return filePath
|
return filePath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Channel) GetSuppportedLanguages() []Language {
|
||||||
|
supportedLanguages := app.GetSuppportedLanguages()
|
||||||
|
|
||||||
|
var response []Language
|
||||||
|
|
||||||
|
for _, l := range supportedLanguages {
|
||||||
|
response = append(response, Language(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user