Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement basic app shell for the authenticated area #131

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d62f4b1
Automated changes by yarn install
fabian-emilius Jun 24, 2024
01861bd
Fix issue that server container could not connect to keycloak
fabian-emilius Jun 24, 2024
3415b0d
Allow client ids being configured by environment variables
fabian-emilius Jun 25, 2024
3d4dfc6
Refactor folder structure and fix eslint
fabian-emilius Jun 25, 2024
f0006d9
Implement basic mock chart with echarts
fabian-emilius Jun 26, 2024
5866b08
Implement basic filters for chart
fabian-emilius Jun 26, 2024
b14b743
Fix issue that echart adds element from the bottom
fabian-emilius Jun 26, 2024
2954adf
Fix small filter issues in thesis overview
fabian-emilius Jun 28, 2024
38a45ce
Merge branch 'fix/pagination-issue-in-application-management' of gith…
fabian-emilius Jul 2, 2024
e954d44
Fix merge issues
fabian-emilius Jul 2, 2024
deb3071
Add basic app shell and create files for planned pages
fabian-emilius Jul 17, 2024
9e702df
Make navigation collapsible on desktop
fabian-emilius Jul 18, 2024
6c06b2f
Fix linting
fabian-emilius Jul 18, 2024
50da9c3
Rename legacy types to legacy to eventually remove them
fabian-emilius Jul 18, 2024
78ca5df
Rename legacy types to legacy to eventually remove them
fabian-emilius Jul 18, 2024
d7b2fb1
Implement new request logic
fabian-emilius Jul 20, 2024
9451e5c
Improve bundle size and build performance
fabian-emilius Jul 21, 2024
84c6ccb
Fix linting
fabian-emilius Jul 21, 2024
066b4cb
Remove unnecessary dependencies
fabian-emilius Jul 21, 2024
990e948
Remove unnecessary dependencies
fabian-emilius Jul 21, 2024
c78ab6e
Small webpack improvements
fabian-emilius Jul 21, 2024
e2c3705
Merge branch 'main' of github.com:ls1intum/thesis-track into 82-imple…
fabian-emilius Jul 21, 2024
283663c
Fix create application request
fabian-emilius Jul 21, 2024
47aaf5b
Improve keycloak token refresh logic and only use one keycloak client…
fabian-emilius Jul 21, 2024
de28d90
Close application modal after final changes were made
fabian-emilius Jul 21, 2024
efd3f3d
Set exact versions in package.json and update dependencies
fabian-emilius Jul 22, 2024
3b47254
Disable webpack bar on CI
fabian-emilius Jul 23, 2024
905dd97
Fix api server host
fabian-emilius Jul 23, 2024
a948fda
Add client id to args
fabian-emilius Jul 23, 2024
25b7526
Add better logging for keycloak initialization
fabian-emilius Jul 23, 2024
5af7988
Add runtime environment variables for easier hosting
fabian-emilius Jul 23, 2024
59c17d4
Remove testing code
fabian-emilius Jul 23, 2024
afe3a1f
Change .env production name
fabian-emilius Jul 23, 2024
2931171
Ignore all environment files
fabian-emilius Jul 23, 2024
76f542c
Modify deployment to support frontend runtime environments
fabian-emilius Jul 23, 2024
cb27228
Fix deployment
fabian-emilius Jul 23, 2024
d3a99a9
Fix deployment
fabian-emilius Jul 23, 2024
f3ddedc
Fix build environment variables
fabian-emilius Jul 23, 2024
dc5e251
Fix build environment variables
fabian-emilius Jul 23, 2024
fda6415
Fix build environment variables
fabian-emilius Jul 23, 2024
3aa507e
Fix build environment variables
fabian-emilius Jul 23, 2024
5518c86
Fix dev build commands
fabian-emilius Jul 23, 2024
13e1355
Remove docker build args and only use environment going forward
fabian-emilius Jul 23, 2024
842d8d7
Add logging messages to debug staging
fabian-emilius Jul 23, 2024
9fadb47
Fix issue that authentication tokens are reset if refresh token expir…
fabian-emilius Jul 23, 2024
2244d50
Improve refresh token logic
fabian-emilius Jul 24, 2024
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
Prev Previous commit
Next Next commit
Implement basic filters for chart
  • Loading branch information
fabian-emilius committed Jun 26, 2024
commit 5866b08282bbebc275c83e751480e5bfa0f9af63
4 changes: 2 additions & 2 deletions client/src/pages/ThesisApplication/ThesisApplicationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ import { notifications } from '@mantine/notifications'
import { useDisclosure } from '@mantine/hooks'
import { ApplicationSuccessfulSubmission } from './components/ApplicationSubmission/ApplicationSuccessfulSubmission'
import { useEffect, useState } from 'react'
import FormTextField from '../../components/form/FormTextField'
import FormSelectField from '../../components/form/FormSelectField'
import FormTextField from './form/FormTextField'
import FormSelectField from './form/FormSelectField'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import {
getThesisAdvisors,
Expand Down
33 changes: 19 additions & 14 deletions client/src/pages/ThesisOverview/ThesisOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ import React from 'react'
import EChartsThesisProgressChart from './components/EChartsThesisProgressChart/EChartsThesisProgressChart'
import { Box } from '@mantine/core'
import chartData from './mock/chart-data.json'
import { IThesisProgressChartDataElement } from './types/chart'
import { useParams } from 'react-router-dom'
import CustomThesisProgressChart from './components/CustomThesisProgressChart/CustomThesisProgressChart'
import ThesisProgressFilter from './components/ThesisProgressFilter/ThesisProgressFilter'
import ThesisOverviewChartProvider from './components/ThesisOverviewChartProvider/ThesisOverviewChartProvider'
import { IThesisProgressChartDataElement } from './types/chart'

const ThesisOverview = () => {
const { variant } = useParams<{ variant: string }>()

return (
<div style={{ padding: '0 0 5vh 0' }}>
<div style={{ padding: '20px 0 5vh 0' }}>
<Box
style={{
display: 'flex',
Expand All @@ -22,18 +23,22 @@ const ThesisOverview = () => {
mx='auto'
pos='relative'
>
<ThesisProgressFilter />
{variant === 'custom' ? (
<CustomThesisProgressChart
data={chartData.data as IThesisProgressChartDataElement[]}
advisors={chartData.advisors as string[]}
/>
) : (
<EChartsThesisProgressChart
data={chartData.data as IThesisProgressChartDataElement[]}
advisors={chartData.advisors as string[]}
/>
)}
<ThesisOverviewChartProvider
mockData={{
thesisData: chartData.data as IThesisProgressChartDataElement[],
advisors: chartData.advisors,
}}
>
<center>
<h1>Thesis Overview Chart</h1>
</center>
<ThesisProgressFilter />
{variant === 'custom' ? (
<CustomThesisProgressChart width='100%' height={700} />
) : (
<EChartsThesisProgressChart width='100%' height={700} />
)}
</ThesisOverviewChartProvider>
</Box>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import React from 'react'
import { IThesisProgressChartDataElement } from '../../types/chart'
import { Skeleton } from '@mantine/core'
import { useThesisOverviewChart } from '../ThesisOverviewChartProvider/hooks'

interface ICustomThesisProgressChartProps {
data: IThesisProgressChartDataElement[]
advisors: string[]
width: string
height: number
}

const CustomThesisProgressChart = (props: ICustomThesisProgressChartProps) => {
const {} = props
const { width, height } = props

const { thesisData } = useThesisOverviewChart()

if (!thesisData) {
return <Skeleton style={{ height: height + 'px', width }} />
}

return <div></div>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import React, { useMemo } from 'react'
import ReactEChartsCore from 'echarts-for-react'
import * as echarts from 'echarts'
import { IThesisProgressChartDataElement, ThesisStateColor } from '../../types/chart'
import { ThesisStateColor } from '../../types/chart'
import { EChartsOption, ERectangle } from 'echarts'
import {
CustomSeriesRenderItemAPI,
CustomSeriesRenderItemParams,
CustomSeriesRenderItemReturn,
} from 'echarts/types/dist/echarts'
import RenderItemParams = echarts.EChartOption.SeriesCustom.RenderItemParams

const CHART_HEIGHT = 700
import { useThesisOverviewChart } from '../ThesisOverviewChartProvider/hooks'
import { Skeleton } from '@mantine/core'

interface IEChartsThesisProgressChartProps {
data: IThesisProgressChartDataElement[]
advisors: string[]
width: string
height: number
}

const EChartsThesisProgressChart = (props: IEChartsThesisProgressChartProps) => {
const { data: chartData } = props
const { width, height } = props

const { thesisData } = useThesisOverviewChart()

const currentTime = useMemo(() => {
return Date.now()
}, [])

const options = useMemo<EChartsOption>(() => {
const options = useMemo<EChartsOption | undefined>(() => {
if (!thesisData) {
return undefined
}

function clipRectByRect(params: RenderItemParams, rect: ERectangle) {
if (!params.coordSys) {
throw new Error('Rectangle does not exist on params')
Expand All @@ -38,10 +44,11 @@ const EChartsThesisProgressChart = (props: IEChartsThesisProgressChartProps) =>
})
}

const chartPages = Math.ceil((chartData.length * 35) / CHART_HEIGHT)
const chartPages = Math.ceil((thesisData.length * 35) / height)

return {
tooltip: {},
backgroundColor: 'transparent',
dataZoom: [
{
type: 'slider',
Expand Down Expand Up @@ -126,7 +133,7 @@ const EChartsThesisProgressChart = (props: IEChartsThesisProgressChartProps) =>
api: CustomSeriesRenderItemAPI,
): CustomSeriesRenderItemReturn => {
const dataIndex = params.dataIndex
const item = chartData[dataIndex]
const item = thesisData[dataIndex]

const startTime = item.started_at
const endTime = item.ended_at || currentTime
Expand Down Expand Up @@ -171,7 +178,7 @@ const EChartsThesisProgressChart = (props: IEChartsThesisProgressChartProps) =>
'Topic',
'State',
],
data: chartData.map((element, index) => [
data: thesisData.map((element, index) => [
index,
element.student,
element.started_at - 3600 * 24 * 1000,
Expand All @@ -183,14 +190,18 @@ const EChartsThesisProgressChart = (props: IEChartsThesisProgressChartProps) =>
},
],
}
}, [chartData, currentTime])
}, [thesisData, currentTime, height])

if (!options) {
return <Skeleton style={{ height: height + 'px', width }} />
}

return (
<ReactEChartsCore
echarts={echarts}
option={options}
theme='dark'
style={{ height: CHART_HEIGHT + 'px', width: '100%' }}
style={{ height: height + 'px', width }}
/>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, { useMemo, useState } from 'react'
import { IThesisProgressChartDataElement, ThesisState } from '../../types/chart'
import ThesisOverviewChartContext, {
IThesisOverviewChartContext,
IThesisOverviewChartContextFilters,
IThesisOverviewChartContextSort,
} from './context'

interface IThesisOverviewChartProviderProps {
children: any
mockData?: {
thesisData: IThesisProgressChartDataElement[]
advisors: string[]
}
}

const ThesisOverviewChartProvider = (props: IThesisOverviewChartProviderProps) => {
const { children, mockData } = props

const [thesisData] = useState<IThesisProgressChartDataElement[] | undefined>(mockData?.thesisData)
const [advisors, setAdvisors] = useState<string[] | undefined>(mockData?.advisors)
const [filters, setFilters] = useState<IThesisOverviewChartContextFilters>({
states: [ThesisState.proposal, ThesisState.active, ThesisState.submitted, ThesisState.graded],
})
const [sort, setSort] = useState<IThesisOverviewChartContextSort>({
column: 'start_date',
direction: 'asc',
})

const contextState = useMemo<IThesisOverviewChartContext>(() => {
const currentTime = Date.now()

return {
advisors,
setAdvisors,
thesisData: thesisData
?.filter((x) => {
if (filters.advisors && !filters.advisors.includes(x.advisor)) {
return false
}

if (filters.states && !filters.states.includes(x.state)) {
return false
}

const elementRange: [number, number] = [x.started_at, x.ended_at || currentTime]

const filterRange: [number, number] = [
typeof filters.startDate === 'number' ? filters.startDate : 0,
typeof filters.endDate === 'number' ? filters.endDate : currentTime,
]

return (
(elementRange[0] >= filterRange[0] && elementRange[0] <= filterRange[1]) ||
(elementRange[1] >= filterRange[0] && elementRange[1] <= filterRange[1])
)
})
.sort((a, b) => {
let aComparibleNumber = 0
let bComparibleNumber = 0

if (sort.column === 'start_date') {
aComparibleNumber = a.started_at
bComparibleNumber = b.started_at
}

if (sort.column === 'end_date') {
aComparibleNumber = a.ended_at || currentTime
bComparibleNumber = b.ended_at || currentTime
}

if (sort.column === 'advisor') {
aComparibleNumber = a.advisor.localeCompare(b.advisor)
bComparibleNumber = 0
}

if (sort.direction === 'desc') {
return aComparibleNumber - bComparibleNumber
} else {
return bComparibleNumber - aComparibleNumber
}
}),
filters,
setFilters,
sort,
setSort,
}
}, [thesisData, advisors, filters, sort])

return (
<ThesisOverviewChartContext.Provider value={contextState}>
{children}
</ThesisOverviewChartContext.Provider>
)
}

export default ThesisOverviewChartProvider
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { Dispatch, SetStateAction } from 'react'
import { IThesisProgressChartDataElement, ThesisState } from '../../types/chart'

export interface IThesisOverviewChartContextFilters {
advisors?: string[]
states?: ThesisState[]
startDate?: number
endDate?: number
}

export interface IThesisOverviewChartContextSort {
column: 'start_date' | 'end_date' | 'advisor'
direction: 'asc' | 'desc'
}

export interface IThesisOverviewChartContext {
thesisData: IThesisProgressChartDataElement[] | undefined
advisors: string[] | undefined
filters: IThesisOverviewChartContextFilters
setFilters: Dispatch<SetStateAction<IThesisOverviewChartContextFilters>>
sort: IThesisOverviewChartContextSort
setSort: Dispatch<SetStateAction<IThesisOverviewChartContextSort>>
}

const ThesisOverviewChartContext = React.createContext<IThesisOverviewChartContext | undefined>(
undefined,
)

export default ThesisOverviewChartContext
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useContext } from 'react'
import ThesisOverviewChartContext from './context'

export function useThesisOverviewChart() {
const data = useContext(ThesisOverviewChartContext)

if (!data) {
throw new Error('ThesisOverviewChartContext not properly initialized')
}

return data
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,67 @@
import React from 'react'
import { MultiSelect, Select } from '@mantine/core'
import { useThesisOverviewChart } from '../ThesisOverviewChartProvider/hooks'
import { ThesisState } from '../../types/chart'
import { DateInput } from '@mantine/dates'

const ThesisOverviewFilter = () => {
return <div></div>
const { filters, advisors, setFilters, sort, setSort } = useThesisOverviewChart()

return (
<div>
<MultiSelect
hidePickedOptions
label='Advisors'
placeholder='Select Advisors'
data={advisors}
value={filters.advisors}
onChange={(x) =>
setFilters((prev) => ({ ...prev, advisors: x.length > 0 ? x : undefined }))
}
searchable={true}
/>
<MultiSelect
hidePickedOptions
label='States'
placeholder='Select Thesis States'
data={Object.values(ThesisState)}
value={filters.states}
onChange={(x) =>
setFilters((prev) => ({
...prev,
states: x.length > 0 ? (x as ThesisState[]) : undefined,
}))
}
/>
<DateInput
value={filters.startDate ? new Date(filters.startDate) : undefined}
onChange={(x) => setFilters((prev) => ({ ...prev, startDate: x?.getTime() ?? undefined }))}
label='Start Date'
clearable={true}
/>
<DateInput
value={filters.endDate ? new Date(filters.endDate) : undefined}
onChange={(x) => setFilters((prev) => ({ ...prev, endDate: x?.getTime() ?? undefined }))}
label='End Date'
clearable={true}
/>
<Select
label='Sort By'
data={[
{ label: 'Start Date Ascending', value: 'start_date:asc' },
{ label: 'Start Date Descending', value: 'start_date:desc' },
{ label: 'Advisor Name', value: 'advisor:asc' },
]}
value={sort.column + ':' + sort.direction}
onChange={(x) =>
setSort({
column: (x?.split(':')[0] || 'start_date') as any,
direction: (x?.split(':')[1] || 'asc') as any,
})
}
/>
</div>
)
}

export default ThesisOverviewFilter