Skip to content

Commit

Permalink
Merge pull request #38 from alpaca-tc/add-classified-source-count
Browse files Browse the repository at this point in the history
Add classified source count
  • Loading branch information
alpaca-tc authored May 13, 2024
2 parents c02098a + a4c3dc1 commit d776477
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 42 deletions.
41 changes: 41 additions & 0 deletions frontend/models/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Module } from './module'

export type Source = {
sourceName: string
modules: Module[]
}

type RelatedDefinition = {
Expand All @@ -21,3 +22,43 @@ export type SpecificSource = {
relatedDefinitions: RelatedDefinition[]
reverseDependencies: ReverseDependency[]
}

export type Sources = {
sources: Source[]
classifiedSourcesCount: number
}

export const sortSources = (sources: Source[], key: 'sourceName' | 'modules', sort: 'none' | 'asc' | 'desc'): Source[] => {
if (sort === 'none') {
return sources
}

let sorted = [...sources]

const ascString = (a: string, b: string) => {
if (a > b) return 1
if (a < b) return -1
return 0
}

switch (key) {
case 'sourceName': {
sorted = sorted.sort((a, b) => ascString(a.sourceName, b.sourceName))
break
}
case 'modules': {
sorted = sorted.sort((a, b) =>
ascString(
a.modules.map((module) => module.moduleName).join('-'),
b.modules.map((module) => module.moduleName).join('-'),
),
)
}
}

if (sort === 'desc') {
sorted = sorted.reverse()
}

return sorted
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { color } from '@/constants/theme'
import { CombinedDefinition } from '@/models/combinedDefinition'

import { SourceModulesComboBox } from '../SourceModulesComboBox'
import { sortSources } from '@/models/source'

type Props = {
combinedDefinition: CombinedDefinition
Expand Down Expand Up @@ -44,38 +45,7 @@ export const DefinitionSources: FC<Props> = ({ combinedDefinition, mutateCombine
)

const sources: CombinedDefinition['sources'] = useMemo(() => {
let sorted = [...combinedDefinition.sources]

if (sortState.sort === 'none') {
return sorted
}

const ascString = (a: string, b: string) => {
if (a > b) return 1
if (a < b) return -1
return 0
}

switch (sortState.key) {
case 'sourceName': {
sorted = sorted.sort((a, b) => ascString(a.sourceName, b.sourceName))
break
}
case 'modules': {
sorted = sorted.sort((a, b) =>
ascString(
a.modules.map((module) => module.moduleName).join('-'),
b.modules.map((module) => module.moduleName).join('-'),
),
)
}
}

if (sortState.sort === 'desc') {
sorted = sorted.reverse()
}

return sorted
return sortSources(combinedDefinition.sources, sortState.key, sortState.sort)
}, [combinedDefinition.sources, sortState])

return (
Expand Down
57 changes: 53 additions & 4 deletions frontend/pages/Sources/List.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC } from 'react'
import { FC, useCallback, useMemo, useState } from 'react'
import styled from 'styled-components'

import { Link } from '@/components/Link'
Expand All @@ -7,20 +7,60 @@ import { EmptyTableBody, Heading, Section, Stack, Table, Td, Text, Th } from '@/
import { path } from '@/constants/path'
import { spacing } from '@/constants/theme'
import { useSources } from '@/repositories/sourceRepository'
import { Sources, sortSources } from '@/models/source'

const sortTypes = ['asc', 'desc', 'none'] as const

type SortTypes = (typeof sortTypes)[number]

type SortState = {
key: 'sourceName' | 'modules'
sort: SortTypes
}

export const List: FC = () => {
const { sources, isLoading } = useSources()
const { data, isLoading } = useSources()
const [sortState, setSortState] = useState<SortState>({ key: 'sourceName', sort: 'asc' })

const setNextSortType = useCallback(
(key: SortState['key']) => {
setSortState((prev) => {
if (prev.key === key) {
return {
key,
sort: sortTypes[(sortTypes.indexOf(prev.sort) + 1) % sortTypes.length],
}
} else {
return { key, sort: 'asc' }
}
})
},
[setSortState],
)

const sources: Sources['sources'] = useMemo(() => {
if (!data) {
return []
}

return sortSources(data.sources, sortState.key, sortState.sort)
}, [data?.sources, sortState])

return (
<StyledSection>
<Stack>
<Heading type="screenTitle">Sources</Heading>
<Heading type="screenTitle">Sources {data ? `(classified: ${Math.round(data.classifiedSourcesCount / data.sources.length * 100)}% ${data.classifiedSourcesCount} / ${data.sources.length})` : null}</Heading>

<div style={{ overflow: 'clip' }}>
<Table fixedHead>
<thead>
<tr>
<Th>Source name</Th>
<Th sort={sortState.key === 'sourceName' ? sortState.sort : 'none'} onSort={() => setNextSortType('sourceName')}>
Source name
</Th>
<Th fixed sort={sortState.key === 'modules' ? sortState.sort : 'none'} onSort={() => setNextSortType('modules')}>
Modules
</Th>
</tr>
</thead>
{sources && sources.length > 0 ? (
Expand All @@ -30,6 +70,15 @@ export const List: FC = () => {
<Td>
<Link to={path.sources.show(source.sourceName)}>{source.sourceName}</Link>
</Td>
<Td>
{source.modules.map((module, index) => (
<Text key={index} as="div" whiteSpace="nowrap">
<Link to={path.modules.show(source.modules.slice(0, index + 1).map((mod) => mod.moduleName))}>
{module.moduleName}
</Link>
</Text>
))}
</Td>
</tr>
))}
</tbody>
Expand Down
22 changes: 17 additions & 5 deletions frontend/repositories/sourceRepository.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import useSWR from 'swr'

import { path } from '@/constants/path'
import { SpecificSource } from '@/models/source'
import { Sources, SpecificSource } from '@/models/source'

import { get } from './httpRequest'

type SourcesReponse = {
sources: Array<{ source_name: string }>
sources: Array<{
source_name: string
modules: Array<{
module_name: string
}>
}>
classified_sources_count: number
}

export const useSources = () => {
const { data, isLoading } = useSWR(path.api.sources.index(), async () => {
const { data, isLoading } = useSWR<Sources>(path.api.sources.index(), async () => {
const response = await get<SourcesReponse>(path.api.sources.index())
return response.sources.map((source) => ({ sourceName: source.source_name }))
return {
sources: response.sources.map((source) => ({
sourceName: source.source_name,
modules: source.modules.map((module) => ({ moduleName: module.module_name })),
})),
classifiedSourcesCount: response.classified_sources_count
}
})

return { sources: data, isLoading }
return { data, isLoading }
}

type SpecificSourceResponse = {
Expand Down
8 changes: 7 additions & 1 deletion lib/diver_down/web/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,18 @@ def sources
end
# rubocop:enable Style/HashEachMethods

classified_sources_count = source_names.count { @module_store.include?(_1) }

json(
sources: source_names.sort.map do |source_name|
{
source_name:,
modules: @module_store.get(source_name).map do |module_name|
{ module_name: }
end,
}
end
end,
classified_sources_count:
)
end

Expand Down
19 changes: 19 additions & 0 deletions spec/diver_down/web_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ def assert_definition_group(definition_group, expected_ids)
expect(last_response.status).to eq(200)
expect(JSON.parse(last_response.body)).to eq({
'sources' => [],
'classified_sources_count' => 0,
})
end

Expand All @@ -304,19 +305,37 @@ def assert_definition_group(definition_group, expected_ids)
DiverDown::Definition::Source.new(
source_name: 'a.rb'
),
DiverDown::Definition::Source.new(
source_name: 'b.rb'
),
DiverDown::Definition::Source.new(
source_name: 'c.rb'
),
]
)
store.set(definition)

module_store.set('a.rb', ['A'])

get '/api/sources.json'

expect(last_response.status).to eq(200)
expect(JSON.parse(last_response.body)).to eq({
'sources' => [
{
'source_name' => 'a.rb',
'modules' => [{ 'module_name' => 'A' }],
},
{
'source_name' => 'b.rb',
'modules' => [],
},
{
'source_name' => 'c.rb',
'modules' => [],
},
],
'classified_sources_count' => 1,
})
end
end
Expand Down

0 comments on commit d776477

Please sign in to comment.