Skip to content

Commit

Permalink
misc
Browse files Browse the repository at this point in the history
  • Loading branch information
olemp committed Jan 24, 2025
1 parent 64dd5c2 commit 21bb29a
Show file tree
Hide file tree
Showing 21 changed files with 104 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export const AutocompleteControl: FormInputControlComponent<
'label',
'description',
'required',
'hidden'
'hidden',
'title'
)}
>
<div ref={ref} className={styles.container}>
Expand Down
2 changes: 2 additions & 0 deletions client/components/FormControl/AutocompleteControl/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { OptionProps } from '@fluentui/react-components'
import { IDynamicSearchBoxProps } from 'components/DynamicSearchBox'
import { FluentIconName } from 'utils/getFluentIcon'
import { FormInputControlBase } from '../types'
import { HTMLAttributes } from 'react'

/**
* @category Autocomplete
Expand All @@ -28,6 +29,7 @@ export type AutocompleteControlSelectCallback<T = any> = (
*/
export interface IAutocompleteControlProps<T = any>
extends FormInputControlBase,
Pick<HTMLAttributes<HTMLDivElement>, 'title'>,
Pick<IDynamicSearchBoxProps, 'placeholder' | 'autoFocus'> {
/**
* Provide the key of the selected item. This will be used to clear
Expand Down
2 changes: 1 addition & 1 deletion client/components/FormControl/Field/FieldContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const FieldContainer: StyledComponent<IFieldProps> = (props) => {
{(context) => (
<Field
className={mergeClasses(FieldContainer.className, props.className)}
{..._.pick(props, 'onKeyDown')}
{..._.pick(props, 'onKeyDown', 'title')}
{...getValidationProps(context, props.name)}
>
<FieldLabel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,26 @@ import { FormInputControlComponent } from '../types'
import styles from './ProjectPickerControl.module.scss'
import { IProjectPickerControlProps } from './types'
import { useProjectPickerControl } from './useProjectPickerControl'
import _ from 'lodash'

/**
* @category Reusable Component
*/
export const ProjectPickerControl: FormInputControlComponent<
IProjectPickerControlProps
> = (props) => {
const { onSelected } = useProjectPickerControl(props)
const { onSelected, filterFunc } = useProjectPickerControl(props)
return (
<SearchProject
hidden={props.hidden}
label={props.label}
description={props.description}
placeholder={props.placeholder}
filterFunc={(project) =>
project?.customer?.key === props.model.value('customerKey')
}
{..._.pick(
props,
'hidden',
'label',
'description',
'placeholder',
'disabledText'
)}
filterFunc={filterFunc}
onSelected={onSelected}
selectedKey={props.model.value(props.name)}
/>
Expand Down
5 changes: 4 additions & 1 deletion client/components/FormControl/ProjectPickerControl/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ import { FormInputControlBase } from '../types'

export interface IProjectPickerControlProps
extends FormInputControlBase,
Pick<ISearchProjectProps, 'label' | 'placeholder' | 'description'>,
Pick<
ISearchProjectProps,
'label' | 'placeholder' | 'description' | 'disabledText'
>,
Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable unicorn/prevent-abbreviations */
import { ISearchProjectProps } from 'components/SearchProject/types'
import { IProjectPickerControlProps } from './types'

Expand All @@ -10,5 +11,12 @@ export function useProjectPickerControl(props: IProjectPickerControlProps) {
const onSelected: ISearchProjectProps['onSelected'] = (project) => {
props.model.set(props.name, project.tag)
}
return { onSelected }

const filterFunc: ISearchProjectProps['filterFunc'] = (project) => {
return (
project?.customer?.key === props.model.value('customerKey') ||
project?.customerKey === props.model.value('customerKey')
)
}
return { onSelected, filterFunc }
}
1 change: 1 addition & 0 deletions client/components/SearchProject/SearchProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const SearchProject: ReusableComponent<ISearchProjectProps> = (
<AutocompleteControl
{...props}
disabled={disabled}
title={disabled && props.disabledText}
items={items}
onSelected={(item) => props.onSelected(item?.data)}
autoFocus={props.autoFocus}
Expand Down
5 changes: 5 additions & 0 deletions client/components/SearchProject/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ export interface ISearchProjectProps
* @param project Project to filter
*/
filterFunc?: (project?: Project) => boolean

/**
* Tooltip to display when the component is disabled.
*/
disabledText?: string
}
5 changes: 3 additions & 2 deletions client/components/SearchProject/useSearchProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { arrayMap } from 'utils'
import { ISuggestionItem } from '../FormControl/AutocompleteControl'
import $projects from './projects.gql'
import { ISearchProjectProps } from './types'
import _ from 'lodash'

/**
* Component logic hook for `<SearchProject />`. Handles
Expand Down Expand Up @@ -35,8 +36,8 @@ export function useSearchProject(props: ISearchProjectProps) {
data: project,
iconName: project.icon
})),
[data]
[projects]
)

return [items, loading] as const
return [items, loading || _.isEmpty(items)] as const
}
3 changes: 2 additions & 1 deletion client/i18n/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@
"parentProject": "Parent Project",
"parentProjectDescription": "Select a parent project to which this project belongs. This is particularly useful for organizing projects hierarchically and maintaining connections between related projects.",
"parentLabel": "Parent Project",
"childrenLabel": "Child Projects"
"childrenLabel": "Child Projects",
"parentProjectDisabledText": "You can only select a parent project under the same customer, and there's no customer selected, or no projects under the selected customer."
},
"customers": {
"inactiveText": "This customer has been marked as inactive.",
Expand Down
3 changes: 2 additions & 1 deletion client/i18n/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@
"parentProject": "Overordnet prosjekt",
"parentProjectDescription": "Velg et overordnet prosjekt som dette prosjektet skal tilhøre. Dette er spesielt nyttig for å organisere prosjekter hierarkisk og opprettholde sammenhenger mellom relaterte prosjekter.",
"parentLabel": "Overordnet prosjekt",
"childrenLabel": "Underordnede prosjekter"
"childrenLabel": "Underordnede prosjekter",
"parentProjectDisabledText": "Du kan bare velge et overordnet prosjekt under samme kunde, og det er ikke valgt noen kunde, eller er det ingen prosjekter under den valgte kunden."
},
"customers": {
"inactiveText": "Denne kunden er markert som inaktiv.",
Expand Down
3 changes: 2 additions & 1 deletion client/i18n/nn.json
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@
"parentProject": "Overordna prosjekt",
"parentProjectDescription": "Vel eit overordna prosjekt som dette prosjektet høyrer til. Dette er særleg nyttig for å organisere prosjekt hierarkisk og oppretthalde samanhengar mellom relaterte prosjekt.",
"parentLabel": "Overordna prosjekt",
"childrenLabel": "Underordna prosjekter"
"childrenLabel": "Underordna prosjekter",
"parentProjectDisabledText": "Du kan bare velge et overordnet prosjekt under samme kunde, og det er ikke valgt noen kunde, eller er det ingen prosjekter under den valgte kunden."
},
"customers": {
"inactiveText": "Denne kunden er markert som inaktiv.",
Expand Down
8 changes: 1 addition & 7 deletions client/pages/Projects/ProjectDetails/ProjectDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { StyledComponent } from 'types'
import styles from './ProjectDetails.module.scss'
import { ProjectHeader } from './ProjectHeader'
import { useProjectDetails } from './useProjectDetails'
import { ProjectInformation } from './ProjectInformation'

/**
* Displays the details of a project, including a list of time entries.
Expand All @@ -17,15 +16,10 @@ export const ProjectDetails: StyledComponent = () => {
return (
<div className={ProjectDetails.className}>
<ProjectHeader />
<ProjectInformation />
<Tabs items={tabs} level={3} />
</div>
)
}

ProjectDetails.displayName = 'ProjectDetails'
ProjectDetails.className = styles.projectDetails

export * from './ProjectHeader'
export * from './ProjectInformation'
export * from './ProjectTimeEntries'
ProjectDetails.className = styles.projectDetails
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ export function useProjectHeaderBreadcrumb() {
const history = useHistory()
const detailsTab = useSwitchCase(urlParameters.detailsTab, {
projects: t('customers.projectsHeaderText'),
timeEntries: t('projects.timeEntriesHeaderText'),
default: t('customers.informationHeaderText')
})

const breadcrumbItems = useBreadcrumb(
return useBreadcrumb(
[
{
value: t('navigation.ProjectsPage'),
Expand All @@ -46,5 +47,4 @@ export function useProjectHeaderBreadcrumb() {
],
[state.selected, detailsTab]
)
return breadcrumbItems
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
} from 'components'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { LabelObject as Label, StyledComponent, SubscriptionProjectsSettings } from 'types'
import {
LabelObject as Label,
StyledComponent,
SubscriptionProjectsSettings
} from 'types'
import _ from 'underscore'
import { useProjectsContext } from '../../context'
import styles from './ProjectInformation.module.scss'
Expand All @@ -25,7 +29,8 @@ import { useSubscriptionSettings } from 'AppContext'
export const ProjectInformation: StyledComponent = () => {
const { t } = useTranslation()
const context = useProjectsContext()
const settings = useSubscriptionSettings<SubscriptionProjectsSettings>('projects')
const settings =
useSubscriptionSettings<SubscriptionProjectsSettings>('projects')

return (
<div className={ProjectInformation.className}>
Expand Down Expand Up @@ -64,7 +69,9 @@ export const ProjectInformation: StyledComponent = () => {
))}
</InformationProperty>
<InformationProperty
hidden={!context.state.selected?.parent || !settings?.enableSimpleHierachy}
hidden={
!context.state.selected?.parent || !settings?.enableSimpleHierachy
}
title={t('projects.parentLabel')}
onRenderValue={() => (
<ProjectLink
Expand All @@ -79,7 +86,10 @@ export const ProjectInformation: StyledComponent = () => {
isDataLoaded={!context.loading}
/>
<InformationProperty
hidden={_.isEmpty(context.state.selected?.children) || !settings?.enableSimpleHierachy}
hidden={
_.isEmpty(context.state.selected?.children) ||
!settings?.enableSimpleHierachy
}
title={t('projects.childrenLabel')}
onRenderValue={() => (
<div style={{ display: 'flex', flexDirection: 'row', gap: 20 }}>
Expand Down
3 changes: 3 additions & 0 deletions client/pages/Projects/ProjectDetails/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export * from './ProjectDetails'
export * from './ProjectHeader'
export * from './ProjectInformation'
export * from './ProjectTimeEntries'
8 changes: 8 additions & 0 deletions client/pages/Projects/ProjectDetails/useProjectDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { useProjectsContext } from '../context'
import { ProjectTimeEntries } from './ProjectTimeEntries'
import { ProjectInformation } from './ProjectInformation'

/**
* Component logic hook that returns an object with tabs for the project details page.
Expand All @@ -14,6 +15,13 @@ export function useProjectDetails() {
const context = useProjectsContext()
const tabs: TabItems = useMemo(
() => ({
information: [
ProjectInformation,
{
text: t('projects.informationHeaderText'),
iconName: 'Info'
}
],
timeEntries: [
ProjectTimeEntries,
{
Expand Down
4 changes: 3 additions & 1 deletion client/pages/Projects/ProjectForm/BasicInfo/BasicInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { SubscriptionProjectsSettings } from 'types'
export const BasicInfo: ProjectFormTabComponent = () => {
const { t } = useTranslation()
const { model, register, isEditMode } = useFormContext()
const settings = useSubscriptionSettings<SubscriptionProjectsSettings>('projects')
const settings =
useSubscriptionSettings<SubscriptionProjectsSettings>('projects')
const customerContext = useCustomersContext()
const isCustomerContext = !!customerContext
return (
Expand Down Expand Up @@ -97,6 +98,7 @@ export const BasicInfo: ProjectFormTabComponent = () => {
hidden={!settings?.enableSimpleHierachy}
label={t('projects.parentProject')}
description={t('projects.parentProjectDescription')}
disabledText={t('projects.parentProjectDisabledText')}
/>
<CreateOutlookCategory />
</FormGroup>
Expand Down
32 changes: 16 additions & 16 deletions client/pages/Projects/ProjectList/useColumns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const ColumnWrapper = ({ project, children }) => (
*/
export function useColumns(props: IProjectListProps): IListColumn[] {
const { t } = useTranslation()
const settings = useSubscriptionSettings<SubscriptionProjectsSettings>('projects')
const settings =
useSubscriptionSettings<SubscriptionProjectsSettings>('projects')
const context = useProjectsContext()
const outlookCategories = mapProperty(
context?.state?.outlookCategories,
Expand Down Expand Up @@ -87,20 +88,16 @@ export function useColumns(props: IProjectListProps): IListColumn[] {
isMultiline: true
}
),
createColumnDef<Project>(
'parent',
t('projects.parentLabel'),
{
hidden: !settings?.enableSimpleHierachy,
renderAs: 'projectLink',
createRenderProps: (project) => ({
project: project.parent,
onClick: () =>
context.dispatch &&
context.dispatch(SET_SELECTED_PROJECT(project.parent?.tag))
})
}
),
createColumnDef<Project>('parent', t('projects.parentLabel'), {
hidden: !settings?.enableSimpleHierachy,
renderAs: 'projectLink',
createRenderProps: (project) => ({
project: project.parent,
onClick: () =>
context.dispatch &&
context.dispatch(SET_SELECTED_PROJECT(project.parent?.tag))
})
}),
createColumnDef<Project>(
'labels',
t('common.labelFieldLabel'),
Expand All @@ -113,7 +110,10 @@ export function useColumns(props: IProjectListProps): IListColumn[] {
</>
)
)
].filter((col) => col.hidden !== true && !(props.hideColumns || []).includes(col.key)),
].filter(
(col) =>
col.hidden !== true && !(props.hideColumns || []).includes(col.key)
),
[props.hideColumns, outlookCategories]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import 'reflect-metadata'
import { Field, InputType, ObjectType } from 'type-graphql'

/**
* A type that describes Subscription projects settings. This type is used
* to describe the settings for projects in a subscription. These settings
* are used to configure the behavior of projects in the subscription.
*
* @category GraphQL ObjectType
*/

@ObjectType({
description: 'A type that describes Subscription projects settings'
})
Expand All @@ -28,6 +31,10 @@ export class SubscriptionProjectsSettings {
@Field({ nullable: true, defaultValue: false })
enableProjectRoles?: boolean

/**
* Enable simple hierarchy for projects. If this is enabled, projects
* can be organized in a simple hierarchy of parent and child projects.
*/
@Field({ nullable: true, defaultValue: false })
enableSimpleHierachy?: boolean
}
Expand Down Expand Up @@ -58,6 +65,10 @@ export class SubscriptionProjectsSettingsInput {
@Field({ nullable: true, defaultValue: false })
enableProjectRoles?: boolean

/**
* Enable simple hierarchy for projects. If this is enabled, projects
* can be organized in a simple hierarchy of parent and child projects.
*/
@Field({ nullable: true, defaultValue: false })
enableSimpleHierachy?: boolean
}
2 changes: 1 addition & 1 deletion server/graphql/resolvers/subscription/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export * from './SubscriptionSettings'
export * from './SubscriptionTeamsSettings'
export * from './SubscriptionVacationSettings'
export * from './SubscriptionTimesheetSettings'
export * from './SubscriptionProjectsSettings'
export * from './SubscriptionProjectsSettings'

0 comments on commit 21bb29a

Please sign in to comment.