Skip to content

Commit

Permalink
Merge pull request #1 from alpaca-tc/compound
Browse files Browse the repository at this point in the history
Support graph options
  • Loading branch information
alpaca-tc authored Apr 3, 2024
2 parents 9ec4b3b + af584fe commit b5b680b
Show file tree
Hide file tree
Showing 12 changed files with 292 additions and 47 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/ci_frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v2
- name: Set up frontend
uses: actions/setup-node@v4
with:
Expand All @@ -26,6 +28,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v2
- name: Set up frontend
uses: actions/setup-node@v4
with:
Expand Down
4 changes: 2 additions & 2 deletions exe/diver_down_web
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ begin
# Rack 2.0
require 'rack'
require 'rack/server'
Rack::Server.new(app:).start
Rack::Server.new(app:, server: :webrick).start
rescue LoadError
# Rack 3.0
require 'rackup'
Rackup::Server.new(app:).start
Rackup::Server.new(app:, server: :webrick).start
end
19 changes: 16 additions & 3 deletions frontend/pages/Home/Show.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,24 @@ import { Loading } from '@/components/Loading'
import { Aside, Section, Sidebar, Stack } from '@/components/ui'
import { color } from '@/constants/theme'
import { useBitIdHash } from '@/hooks/useBitIdHash'
import { useLocalStorage } from '@/hooks/useLocalStorage'
import { useCombinedDefinition } from '@/repositories/combinedDefinitionRepository'

import { DefinitionGraph } from './components/DefinitionGraph'
import { DefinitionGraph, GraphOptions } from './components/DefinitionGraph'
import { DefinitionList } from './components/DefinitionList'
import { DefinitionSources } from './components/DefinitionSources'

export const Show: React.FC = () => {
const [selectedDefinitionIds, setSelectedDefinitionIds] = useBitIdHash()
const { data: combinedDefinition, isLoading } = useCombinedDefinition(selectedDefinitionIds)
const [graphOptions, setGraphOptions] = useLocalStorage<GraphOptions>('HomeShow-GraphOptions', {
compound: false,
concentrate: false,
})
const { data: combinedDefinition, isLoading } = useCombinedDefinition(
selectedDefinitionIds,
graphOptions.compound,
graphOptions.concentrate,
)

return (
<Wrapper>
Expand All @@ -32,7 +41,11 @@ export const Show: React.FC = () => {
</CenterStack>
) : (
<StyledStack>
<DefinitionGraph combinedDefinition={combinedDefinition} />
<DefinitionGraph
combinedDefinition={combinedDefinition}
graphOptions={graphOptions}
setGraphOptions={setGraphOptions}
/>
<StyledDefinitionSources combinedDefinition={combinedDefinition} />
</StyledStack>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useCallback, useState } from 'react'
import styled from 'styled-components'

import { ActionDialog, CheckBox, FormControl, Section, Stack } from '@/components/ui'
import { spacing } from '@/constants/theme'

export type GraphOptions = {
compound: boolean
concentrate: boolean
}

type Props = {
isOpen: boolean
onClickClose: () => void
graphOptions: GraphOptions
setGraphOptions: React.Dispatch<React.SetStateAction<GraphOptions>>
}

export const ConfigureViewOptionsDialog: React.FC<Props> = ({ isOpen, onClickClose, graphOptions, setGraphOptions }) => {
const [temporaryViewOptions, setTemporaryViewOptions] = useState<GraphOptions>(graphOptions)

const handleDialogClose = () => {
onClickClose()

// reset
setTemporaryViewOptions(graphOptions)
}

const handleSubmit = () => {
setGraphOptions(temporaryViewOptions)
onClickClose()
}

const onChangeCompound = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
setTemporaryViewOptions((prev) => ({ ...prev, compound: event.target.checked }))
},
[setTemporaryViewOptions],
)

const onChangeConcentrate = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
setTemporaryViewOptions((prev) => ({ ...prev, concentrate: event.target.checked }))
},
[setTemporaryViewOptions],
)

return (
<ActionDialog
title="Configure Graph Options"
decorators={{ closeButtonLabel: () => 'Close' }}
actionText="Save"
actionTheme="primary"
isOpen={isOpen}
onClickAction={handleSubmit}
onClickClose={handleDialogClose}
onClickOverlay={handleDialogClose}
width={'500px'}
>
<WrapperSection>
<Stack gap={1.5}>
<Stack gap={1.5}>
<p>Configure graph settings.</p>

<Stack gap={1.5}>
<FormControl title="Clip the boundary" helpMessage="Clip the boundary of the module.">
<CheckBox name="compound" onChange={onChangeCompound} checked={temporaryViewOptions.compound} />
</FormControl>

<FormControl
title="Use edge concentrators"
helpMessage="This merges multiedges into a single edge and causes partially parallel edges to share part of their paths."
>
<CheckBox name="compound" onChange={onChangeConcentrate} checked={temporaryViewOptions.concentrate} />
</FormControl>
</Stack>
</Stack>
</Stack>
</WrapperSection>
</ActionDialog>
)
}

const WrapperSection = styled(Section)`
padding: ${spacing.XS};
`
30 changes: 27 additions & 3 deletions frontend/pages/Home/components/DefinitionGraph/DefinitionGraph.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { FC, useEffect, useState } from 'react'
import { FC, useCallback, useEffect, useState } from 'react'
import styled from 'styled-components'

import { Heading, LineClamp, Section, Text } from '@/components/ui'
import { Button, FaGearIcon, Heading, LineClamp, Section, Text } from '@/components/ui'
import { color } from '@/constants/theme'
import { CombinedDefinition } from '@/models/combinedDefinition'
import { renderDot } from '@/utils/renderDot'

import { ConfigureViewOptionsDialog, GraphOptions } from './ConfigureGraphOptionsDialog'
import { ScrollableSvg } from './ScrollableSvg'

type Props = {
combinedDefinition: CombinedDefinition
graphOptions: GraphOptions
setGraphOptions: React.Dispatch<React.SetStateAction<GraphOptions>>
}

export const DefinitionGraph: FC<Props> = ({ combinedDefinition }) => {
type DialogType = 'configureViewOptionsDiaglog'

export const DefinitionGraph: FC<Props> = ({ combinedDefinition, graphOptions, setGraphOptions }) => {
const [visibleDialog, setVisibleDialog] = useState<DialogType | null>(null)
const [svg, setSvg] = useState<string>('')

useEffect(() => {
Expand All @@ -28,8 +34,18 @@ export const DefinitionGraph: FC<Props> = ({ combinedDefinition }) => {
loadSvg()
}, [combinedDefinition.dot, setSvg])

const onClickCloseDialog = useCallback(() => {
setVisibleDialog(null)
}, [setVisibleDialog])

return (
<WrapperSection>
<ConfigureViewOptionsDialog
isOpen={visibleDialog === 'configureViewOptionsDiaglog'}
onClickClose={onClickCloseDialog}
graphOptions={graphOptions}
setGraphOptions={setGraphOptions}
/>
<FixedHeightHeading type="sectionTitle">
<LineClamp>
{combinedDefinition.titles.map((title, index) => (
Expand All @@ -38,6 +54,14 @@ export const DefinitionGraph: FC<Props> = ({ combinedDefinition }) => {
</BlockText>
))}
</LineClamp>
<Button
size="s"
square
onClick={() => setVisibleDialog('configureViewOptionsDiaglog')}
prefix={<FaGearIcon alt="Open Options" />}
>
Open View Options
</Button>
</FixedHeightHeading>
<FlexHeightSvgWrapper>
<ScrollableSvg svg={svg} />
Expand Down
1 change: 1 addition & 0 deletions frontend/pages/Home/components/DefinitionGraph/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { DefinitionGraph } from './DefinitionGraph'
export type { GraphOptions } from './ConfigureGraphOptionsDialog'
11 changes: 9 additions & 2 deletions frontend/repositories/combinedDefinitionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import useSWR from 'swr'
import { path } from '@/constants/path'
import { CombinedDefinition } from '@/models/combinedDefinition'
import { bitIdToIds } from '@/utils/bitId'
import { stringify } from '@/utils/queryString'

import { get } from './httpRequest'

Expand Down Expand Up @@ -34,8 +35,14 @@ const fetchDefinitionShow = async (requestPath: string): Promise<CombinedDefinit
}
}

export const useCombinedDefinition = (ids: number[]) => {
const requestPath = path.api.definitions.show(ids)
const toBooleanFlag = (value: boolean) => (value ? '1' : null)

export const useCombinedDefinition = (ids: number[], compound: boolean, concentrate: boolean) => {
const params = {
compound: toBooleanFlag(compound),
concentrate: toBooleanFlag(concentrate),
}
const requestPath = `${path.api.definitions.show(ids)}?${stringify(params)}`
const shouldFetch = ids.length > 0
const { data, isLoading } = useSWR(shouldFetch ? requestPath : null, fetchDefinitionShow)

Expand Down
4 changes: 3 additions & 1 deletion lib/diver_down/web.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ def call(env)
action.module(module_name)
in ['GET', %r{\A/api/definitions/(?<bit_id>\d+)\.json\z}]
bit_id = Regexp.last_match[:bit_id].to_i
action.combine_definitions(bit_id)
compound = request.params['compound'] == '1'
concentrate = request.params['concentrate'] == '1'
action.combine_definitions(bit_id, compound, concentrate)
in ['GET', %r{\A/api/sources/(?<source>.+)\.json\z}]
source = Regexp.last_match[:source]
action.source(source)
Expand Down
6 changes: 4 additions & 2 deletions lib/diver_down/web/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ def pid
# GET /api/definitions/:bit_id.json
#
# @param bit_id [Integer]
def combine_definitions(bit_id)
# @param compound [Boolean]
# @param concentrate [Boolean]
def combine_definitions(bit_id, compound, concentrate)
ids = DiverDown::Web::BitId.bit_id_to_ids(bit_id)

valid_ids = ids.select do
Expand All @@ -167,7 +169,7 @@ def combine_definitions(bit_id)
json(
titles:,
bit_id: DiverDown::Web::BitId.ids_to_bit_id(valid_ids).to_s,
dot: DiverDown::Web::DefinitionToDot.new(definition).to_s,
dot: DiverDown::Web::DefinitionToDot.new(definition, compound:, concentrate:).to_s,
sources: definition.sources.map do
{
source_name: _1.source_name,
Expand Down
Loading

0 comments on commit b5b680b

Please sign in to comment.