Skip to content

Commit

Permalink
Merge pull request #5 from alpaca-tc/render-multiple-methods-when-com…
Browse files Browse the repository at this point in the history
…pound-is-true

Render multiple methods when compound=true
  • Loading branch information
alpaca-tc authored Apr 10, 2024
2 parents 817cf14 + 3846fe3 commit 20f0577
Show file tree
Hide file tree
Showing 6 changed files with 428 additions and 183 deletions.
18 changes: 10 additions & 8 deletions frontend/models/combinedDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,25 @@ type BaseDotMetadata = {
id: string
}

type DotSourceMetadata = {
export type DotSourceMetadata = {
type: 'source'
sourceName: string
modules: Module[]
} & BaseDotMetadata

type DotDependencyMetadata = {
export type DotDependencyMetadata = {
type: 'dependency'
sourceName: string
methodIds: Array<{
name: string
context: 'class' | 'instance'
human: string
dependencies: Array<{
sourceName: string
methodIds: Array<{
name: string
context: 'class' | 'instance'
human: string
}>
}>
} & BaseDotMetadata

type DotModuleMetadata = {
export type DotModuleMetadata = {
type: 'module'
modules: Module[]
} & BaseDotMetadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,6 @@ export const ScrollableSvg: FC<Props> = ({ combinedDefinition, setVisibleDialog
) ?? null
)
case 'dependency':
return (
combinedDefinition.dotMetadata.find(
(metadata) => metadata.type === 'dependency' && metadata.sourceName === prev.sourceName,
) ?? null
)
case 'module':
// Can't find previous module
return prev
Expand Down
192 changes: 115 additions & 77 deletions frontend/pages/Home/components/MetadataDialog/MetadataDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ComponentProps, FC, useState } from 'react'
import { ComponentProps, FC, useMemo, useState } from 'react'
import styled from 'styled-components'

import { Link } from '@/components/Link'
import { Button, Cluster, DefinitionList, FaPencilIcon, Heading, ModelessDialog, Stack } from '@/components/ui'
import { Button, Cluster, DefinitionList, FaPencilIcon, Heading, ModelessDialog, Stack, Table, Td, Th } from '@/components/ui'
import { path } from '@/constants/path'
import { spacing } from '@/constants/theme'
import { DotMetadata } from '@/models/combinedDefinition'
import { DotDependencyMetadata, DotMetadata, DotModuleMetadata, DotSourceMetadata } from '@/models/combinedDefinition'

import { SourceModulesComboBox } from '../SourceModulesComboBox'
import { DialogProps } from '../dialog'
Expand All @@ -20,82 +20,114 @@ type Props = {
left: number
}

export const MetadataDialog: FC<Props> = ({ dotMetadata, isOpen, onClose, top, left, mutateCombinedDefinition }) => {
const SourceDotMetadataContent: FC<{ metadata: DotSourceMetadata } & Pick<Props, 'mutateCombinedDefinition'>> = ({
metadata,
mutateCombinedDefinition,
}) => {
const [editingModules, setEditingModules] = useState<boolean>(false)
const items: ComponentProps<typeof DefinitionList>['items'] = []
const items: ComponentProps<typeof DefinitionList>['items'] = [
{
term: 'Source Name',
description: <Link to={path.sources.show(metadata.sourceName)}>{metadata.sourceName}</Link>,
},
{
term: 'Modules',
description: (
<Cluster>
{editingModules ? (
<SourceModulesComboBox
sourceName={metadata.sourceName}
initialModules={metadata.modules}
onUpdate={() => {
setEditingModules(false)
mutateCombinedDefinition()
}}
onClose={() => {
setEditingModules(false)
}}
/>
) : (
<>
<div>
{metadata.modules.map((module) => (
<p key={module.moduleName}>{module.moduleName}</p>
))}
</div>
<Button
square={true}
onClick={() => {
setEditingModules(true)
}}
size="s"
>
<FaPencilIcon alt="編集" />
</Button>
</>
)}
</Cluster>
),
},
]

switch (dotMetadata?.type) {
case 'source': {
items.push({
term: 'Source Name',
description: <Link to={path.sources.show(dotMetadata.sourceName)}>{dotMetadata.sourceName}</Link>,
})
return <DefinitionList items={items} />
}

items.push({
term: 'Modules',
description: (
<Cluster>
{editingModules ? (
<SourceModulesComboBox
sourceName={dotMetadata.sourceName}
initialModules={dotMetadata.modules}
onUpdate={() => {
setEditingModules(false)
mutateCombinedDefinition()
}}
onClose={() => {
setEditingModules(false)
}}
/>
) : (
<>
<div>
{dotMetadata.modules.map((module) => (
<p key={module.moduleName}>{module.moduleName}</p>
))}
</div>
<Button
square={true}
onClick={() => {
setEditingModules(true)
}}
size="s"
>
<FaPencilIcon alt="編集" />
</Button>
</>
)}
</Cluster>
),
})
const DependencyDotMetadataContent: FC<{ metadata: DotDependencyMetadata }> = ({ metadata }) => (
<Stack gap={0.5}>
<div style={{ overflow: 'clip' }}>
<Table fixedHead>
<thead>
<tr>
<Th>Source Name</Th>
<Th>Method Id</Th>
</tr>
</thead>
<tbody>
{metadata.dependencies.map((dependency) =>
dependency.methodIds.map((methodId, index) => (
<tr key={`${dependency.sourceName}-${methodId.context}-${methodId.name}`}>
<Td>
{index === 0 ? <Link to={`${path.sources.show(dependency.sourceName)}`}>{dependency.sourceName}</Link> : null}
</Td>
<Td>{`${methodId.context === 'class' ? '.' : '#'}${methodId.name}`}</Td>
</tr>
)),
)}
</tbody>
</Table>
</div>
</Stack>
)

break
}
case 'dependency': {
items.push({
term: 'Dependency Name',
description: <Link to={path.sources.show(dotMetadata.sourceName)}>{dotMetadata.sourceName}</Link>,
})
items.push({
term: 'Method ID',
description: dotMetadata.methodIds.map((methodId) => (
<p key={`${methodId.context}-${methodId.name}`}>{methodId.human}</p>
)),
})
break
}
case 'module': {
items.push({
term: 'Module Name',
description: (
<Link to={path.modules.show(dotMetadata.modules.map((module) => module.moduleName))}>
{dotMetadata.modules.map((module) => module.moduleName).join(' / ')}
</Link>
),
})
break
const ModuleDotMetadataContent: FC<{ metadata: DotModuleMetadata }> = ({ metadata }) => {
const items: ComponentProps<typeof DefinitionList>['items'] = [
{
term: 'Module Name',
description: (
<Link to={path.modules.show(metadata.modules.map((module) => module.moduleName))}>
{metadata.modules.map((module) => module.moduleName).join(' / ')}
</Link>
),
},
]

return <DefinitionList items={items} />
}

export const MetadataDialog: FC<Props> = ({ dotMetadata, isOpen, onClose, top, left, mutateCombinedDefinition }) => {
const content = useMemo(() => {
switch (dotMetadata?.type) {
case 'source': {
return <SourceDotMetadataContent metadata={dotMetadata} mutateCombinedDefinition={mutateCombinedDefinition} />
}
case 'dependency': {
return <DependencyDotMetadataContent metadata={dotMetadata} />
}
case 'module': {
return <ModuleDotMetadataContent metadata={dotMetadata} />
}
}
}
}, [dotMetadata, mutateCombinedDefinition])

return (
<ModelessDialog
Expand All @@ -107,9 +139,9 @@ export const MetadataDialog: FC<Props> = ({ dotMetadata, isOpen, onClose, top, l
left={left}
>
<Wrapper>
<Stack gap={0.5} as="section">
<DefinitionList items={items} />
</Stack>
<ScrollableStack gap={0.5} as="section">
{content}
</ScrollableStack>
</Wrapper>
</ModelessDialog>
)
Expand All @@ -123,4 +155,10 @@ const ModelessHeading = styled(Heading)`

const Wrapper = styled.div`
padding: ${spacing.XS};
overflow: hidden;
`

const ScrollableStack = styled(Stack)`
overflow-y: auto;
max-height: 350px;
`
22 changes: 13 additions & 9 deletions frontend/repositories/combinedDefinitionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ type DotSourceMetadataResponse = {
type DotDependencyMetadataResponse = {
id: string
type: 'dependency'
source_name: string
method_ids: Array<{
name: string
context: 'class' | 'instance'
dependencies: Array<{
source_name: string
method_ids: Array<{
name: string
context: 'class' | 'instance'
}>
}>
}

Expand Down Expand Up @@ -65,11 +67,13 @@ const parseDotMetadata = (metadata: DotMetadataResponse): DotMetadata => {
return {
id: metadata.id,
type: metadata.type,
sourceName: metadata.source_name,
methodIds: metadata.method_ids.map((methodId) => ({
name: methodId.name,
context: methodId.context,
human: `${methodId.context === 'class' ? '.' : '#'}${methodId.name}`,
dependencies: metadata.dependencies.map((dependency) => ({
sourceName: dependency.source_name,
methodIds: dependency.method_ids.map((methodId) => ({
name: methodId.name,
context: methodId.context,
human: `${methodId.context === 'class' ? '.' : '#'}${methodId.name}`,
})),
})),
}
}
Expand Down
Loading

0 comments on commit 20f0577

Please sign in to comment.