-
Notifications
You must be signed in to change notification settings - Fork 0
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
feat: add base changelog list component #8
Changes from all commits
1d12ea1
ad571a3
f854bc2
48036fc
8a010e1
27b9aaa
758206f
c50ccc4
31452b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import * as React from 'react'; | ||
import { useChangelogs } from '../../changelog.hook.ts'; | ||
import { ChangelogContext } from '../ChangelogContext'; | ||
import { CircularProgress, CssVarsProvider, Typography } from '@mui/joy'; | ||
|
||
interface Props { | ||
API_KEY: string; | ||
|
@@ -9,16 +10,38 @@ interface Props { | |
url?: string; | ||
onlyLast?: boolean; | ||
}; | ||
Error?: React.ComponentType<{ error?: string }>; | ||
Loading?: React.ComponentType; | ||
children: React.ReactNode; | ||
} | ||
|
||
/** | ||
* Container for all UpdateHive react components. | ||
* This container is responsible for fetching the changelogs from the UpdateHive API and handling errors / loading states. | ||
* | ||
* For API_KEY, product, config see UpdateHiveConfig. | ||
* | ||
* @param children Child components to render loaded changelogs. | ||
* @param Error Overridable error component to render if an error occurs. | ||
* @param Loading Overridable loading component to render while loading. | ||
*/ | ||
export const ChangelogContainer: React.FC<Props> = ({ | ||
API_KEY, | ||
product, | ||
config, | ||
children, | ||
Error = () => ( | ||
<Typography> | ||
Ein Fehler ist beim Laden der Versionshistorie aufgetreten! | ||
</Typography> | ||
), | ||
Loading = () => <CircularProgress />, | ||
}) => { | ||
const { loading, error, data } = useChangelogs({ | ||
const { | ||
loading, | ||
error: errorMessage, | ||
data, | ||
} = useChangelogs({ | ||
connection: { | ||
API_KEY, | ||
url: config?.url, | ||
|
@@ -29,14 +52,18 @@ export const ChangelogContainer: React.FC<Props> = ({ | |
}, | ||
}); | ||
|
||
if (error) { | ||
console.error(error); | ||
if (errorMessage) { | ||
console.error(errorMessage); | ||
} | ||
|
||
return ( | ||
<div> | ||
<ChangelogContext.Provider value={{ loading, error, data }}> | ||
{children} | ||
<ChangelogContext.Provider value={{ data }}> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ich würde den outer div entfernen. So forced to bei Benutzung eine Mutation im DOM |
||
{errorMessage && <Error error={errorMessage} />} | ||
{!errorMessage && loading && <Loading />} | ||
{!errorMessage && !loading && data && ( | ||
<CssVarsProvider>{children}</CssVarsProvider> | ||
)} | ||
</ChangelogContext.Provider> | ||
</div> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,18 @@ | ||
import { createContext, useContext } from "react"; | ||
import { Changelog, UpdateHiveHookResult } from "../../changelog.types.ts"; | ||
import { createContext, useContext } from 'react'; | ||
import { Changelog } from '../../changelog.types.ts'; | ||
|
||
export const ChangelogContext = createContext<{ | ||
loading: boolean; | ||
error?: string; | ||
export interface ChangelogContextProps { | ||
data?: Changelog[]; | ||
}>({ loading: true }); | ||
} | ||
|
||
export const useUpdateHiveContext: () => UpdateHiveHookResult = () => { | ||
export const ChangelogContext = createContext<ChangelogContextProps>({}); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wäre es sinnvoll data als empty array zu initilisieren? |
||
export const useUpdateHiveContext: () => ChangelogContextProps = () => { | ||
const context = useContext(ChangelogContext); | ||
|
||
if (!context) { | ||
throw new Error( | ||
"useChangelogContext must be used within a ChangelogContainer", | ||
'useChangelogContext must be used within a ChangelogContainer', | ||
); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import * as React from 'react'; | ||
import { useUpdateHiveContext } from '../ChangelogContext'; | ||
import { ChangeType } from '../../changelog.types.ts'; | ||
import { ChangeTypeMap, getTypeColor } from '../changelog.util.ts'; | ||
import ComponentList from './_internal/ComponentList.tsx'; | ||
import SimpleList from './_internal/SimpleList.tsx'; | ||
import { GroupBy } from './ChangelogList.types.ts'; | ||
|
||
interface Props { | ||
groupBy?: GroupBy; | ||
changeTypeMapper?: Record<ChangeType, string>; | ||
typeColorResolver?: (type: ChangeType) => string; | ||
} | ||
|
||
/** | ||
* Base component to render a list of changelogs. | ||
* | ||
* @param changeTypeMapper Overridable mapping of change types to displayable representations. | ||
* @param typeColorResolver Overridable function to resolve the color of a change type. | ||
* @param groupBy Group changelogs by component or show a simple list. | ||
* @constructor | ||
*/ | ||
export const ChangelogList: React.FC<Props> = ({ | ||
changeTypeMapper = ChangeTypeMap, | ||
typeColorResolver = getTypeColor, | ||
groupBy = GroupBy.COMPONENT, | ||
}) => { | ||
const { data } = useUpdateHiveContext(); | ||
|
||
return ( | ||
<div> | ||
{data && | ||
(groupBy === GroupBy.COMPONENT ? ( | ||
<ComponentList | ||
changelogs={data} | ||
changeTypeMapper={changeTypeMapper} | ||
typeColorResolver={typeColorResolver} | ||
/> | ||
) : ( | ||
<SimpleList changelogs={data} changeTypeMapper={changeTypeMapper} /> | ||
))} | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export enum GroupBy { | ||
COMPONENT = 'COMPONENT', | ||
NONE = 'NONE', | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import * as React from 'react'; | ||
import { useUpdateHiveContext } from '../ChangelogContext'; | ||
import { ChangeTypeMap } from '../changelog.util.ts'; | ||
import { ChangeType } from '../../changelog.types.ts'; | ||
import SimpleList from './_internal/SimpleList.tsx'; | ||
|
||
interface Props { | ||
changeTypeMapper?: Record<ChangeType, string>; | ||
} | ||
|
||
/** | ||
* Component which renders a minimal changelog list. | ||
* | ||
* The list is only ordered by creation. | ||
* | ||
* @param changeTypeMapper Overridable mapping of change types to displayable representations. | ||
*/ | ||
export const MinimalChangelogList: React.FC<Props> = ({ | ||
changeTypeMapper = ChangeTypeMap, | ||
}) => { | ||
const { data } = useUpdateHiveContext(); | ||
|
||
return ( | ||
<div> | ||
{data && ( | ||
<SimpleList changeTypeMapper={changeTypeMapper} changelogs={data} /> | ||
)} | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,78 @@ | ||||||
import { Box, List, ListItem, Typography } from '@mui/joy'; | ||||||
import * as React from 'react'; | ||||||
import { Changelog, ChangeType } from '../../../changelog.types.ts'; | ||||||
import { useMemo } from 'react'; | ||||||
import { | ||||||
ChangelogWithComponents, | ||||||
groupChangelogsByComponents, | ||||||
reorderChangelogs, | ||||||
} from '../../changelog.util.ts'; | ||||||
|
||||||
interface Props { | ||||||
changelogs: Changelog[]; | ||||||
changeTypeMapper: Record<ChangeType, string>; | ||||||
typeColorResolver: (type: ChangeType) => string; | ||||||
} | ||||||
|
||||||
const ComponentList: React.FC<Props> = ({ | ||||||
changelogs, | ||||||
changeTypeMapper, | ||||||
typeColorResolver, | ||||||
}) => { | ||||||
const componentChangelogs: ChangelogWithComponents[] = useMemo(() => { | ||||||
const reorderedChangelogs = reorderChangelogs(changelogs); | ||||||
return groupChangelogsByComponents(reorderedChangelogs); | ||||||
}, [changelogs]); | ||||||
|
||||||
return ( | ||||||
<div> | ||||||
{componentChangelogs.map((changelog, index) => ( | ||||||
<div key={`changelog-${index}`}> | ||||||
<Box sx={() => ({ marginBottom: '8px' })}> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Auch die anderen mal anschauen. Es gibt shorthandler und wenn du das theme objeckt nicht nutzt kannst du die funktion omitten |
||||||
<Typography level="h3" sx={() => ({ marginRight: '8px' })}> | ||||||
Version {changelog.version} | ||||||
</Typography> | ||||||
{changelog.description && ( | ||||||
<Typography>{changelog.description}</Typography> | ||||||
)} | ||||||
</Box> | ||||||
{changelog.entries.map((entry) => ( | ||||||
<> | ||||||
<Typography level="title-lg">{entry.component}</Typography> | ||||||
<List | ||||||
marker={'circle'} | ||||||
sx={() => ({ '--ListItem-minHeight': 20 })} | ||||||
> | ||||||
{entry.changelogs.map((entry, entryIndex) => ( | ||||||
<ListItem | ||||||
sx={() => ({ | ||||||
padding: '0px', | ||||||
})} | ||||||
key={`changelog-${index}-entry-${entryIndex}`} | ||||||
> | ||||||
<Box sx={() => ({ display: 'flex', flexDirection: 'row' })}> | ||||||
<Typography | ||||||
level="title-sm" | ||||||
sx={() => ({ | ||||||
marginRight: '8px', | ||||||
color: typeColorResolver(entry.changeType), | ||||||
})} | ||||||
> | ||||||
{changeTypeMapper[entry.changeType]} | ||||||
</Typography> | ||||||
<Typography level="body-sm"> | ||||||
{entry.description} | ||||||
</Typography> | ||||||
</Box> | ||||||
</ListItem> | ||||||
))} | ||||||
</List> | ||||||
</> | ||||||
))} | ||||||
</div> | ||||||
))} | ||||||
</div> | ||||||
); | ||||||
}; | ||||||
|
||||||
export default ComponentList; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import * as React from 'react'; | ||
import { Changelog, ChangeType } from '../../../changelog.types.ts'; | ||
import { Box, List, ListItem, Typography } from '@mui/joy'; | ||
import { reorderChangelogs } from '../../changelog.util.ts'; | ||
import { useMemo } from 'react'; | ||
|
||
interface Props { | ||
changeTypeMapper: Record<ChangeType, string>; | ||
changelogs: Changelog[]; | ||
} | ||
|
||
const SimpleList: React.FC<Props> = ({ changelogs, changeTypeMapper }) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Name würde ich überdenken. Gibt es auch eine "HardList"? "ComplicatedList"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mir ist auch nicht so ganz klar warum diese Komponente fast genauso wie ComponentList aussieht. Kann man vll etwas generisches aus beiden heraus lösen und diese hier mergen? |
||
const reorderedChangelogs = useMemo(() => { | ||
return reorderChangelogs(changelogs); | ||
}, [changelogs]); | ||
|
||
return ( | ||
<div> | ||
{reorderedChangelogs.map((changelog, index) => ( | ||
<div key={`changelog-${index}`}> | ||
<Box sx={() => ({ marginBottom: '8px' })}> | ||
<Typography level="h3" sx={() => ({ marginRight: '8px' })}> | ||
Version {changelog.version} | ||
</Typography> | ||
{changelog.description && ( | ||
<Typography>{changelog.description}</Typography> | ||
)} | ||
</Box> | ||
<List marker={'circle'} sx={() => ({ '--ListItem-minHeight': 20 })}> | ||
{changelog.entries.map((entry, entryIndex) => ( | ||
<ListItem | ||
sx={() => ({ | ||
padding: '0px', | ||
})} | ||
key={`changelog-${index}-entry-${entryIndex}`} | ||
> | ||
<Box sx={() => ({ display: 'flex', flexDirection: 'row' })}> | ||
<Typography | ||
level="title-sm" | ||
sx={() => ({ marginRight: '8px' })} | ||
> | ||
{changeTypeMapper[entry.changeType]} | ||
</Typography> | ||
<Typography level="body-sm">{entry.description}</Typography> | ||
</Box> | ||
</ListItem> | ||
))} | ||
</List> | ||
</div> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
export default SimpleList; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export { GroupBy } from './ChangelogList.types'; | ||
|
||
export { MinimalChangelogList } from './MinimalChangelogList'; | ||
export { ChangelogList } from './ChangelogList'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.