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

Support for locking weeks for editing #1251

Merged
merged 13 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion .changelog/0.13.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
- Initial support for enhancing the resource management capabilities within the Projects module of our time entry system. [#1237](https://github.com/Puzzlepart/did/issues/1237)
- Showing week hours summary based on user work week [#1138](https://github.com/Puzzlepart/did/issues/1138)
- Manager included in user sync [#1244](https://github.com/Puzzlepart/did/issues/1244)
- Support for simple project hierarchy [#1245](https://github.com/Puzzlepart/did/issues/1245)
- Support for locking weeks from the admin UI [#1249](https://github.com/Puzzlepart/did/issues/1249)
- Enhancements to the Project Role Management [#1245](https://github.com/Puzzlepart/did/issues/1245)
- Add Parent Project to reports and Excel export [#1253](https://github.com/Puzzlepart/did/issues/1253)
- Add Parent Project to reports and Excel export [#1253](https://github.com/Puzzlepart/did/issues/1253)
1 change: 1 addition & 0 deletions client/components/Tabs/TabHeader/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FluentIconName } from 'utils'
export interface ITabHeaderProps {
text: string
iconName?: FluentIconName
iconColor?: string
description?: string
disabled?: boolean
}
4 changes: 3 additions & 1 deletion client/components/Tabs/useTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ export const useTabs: ComponentLogicHook<ITabsProps, UseTabsReturnType> = (
)
}
if (typeof header === 'object') {
tabProps.icon = getFluentIcon(header?.iconName)
tabProps.icon = getFluentIcon(header?.iconName, {
color: header.iconColor
})
tabProps.disabled = header?.disabled
}
return <Tab key={key} {...tabProps} />
Expand Down
23 changes: 18 additions & 5 deletions client/i18n/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
"goToNextWeek": "Go to next period",
"weekHoursSummaryText": "**{{hours}}** this week. {{splitWeekInfoText}}",
"hoursNotMatchedText": "**{{hours}}** unmatched this period. All events must be matched before you can confirm your timesheet.",
"allHoursMatchedText": "**All hours matched!** Are you ready to confirm the period?",
"allHoursMatchedText": "All hours matched! Are you ready to confirm the period?",
"allHoursMatchedPeriodLockedText": "All hours matched, but the period is locked and no changes can be made to it at this time.",
"periodConfirmedText": "**{{hours}}** confirmed this period. Click **Unconfirm hours** if you want to do some adjustments.",
"periodLockedConfirmedText": "**{{hours}}** confirmed this period. The period is locked and no changes can be made to it.",
"ignoredEventsText": "You have {{ignored_count}} ignored event(s).",
"undoIgnoreTooltip": "Undo all ignored events.",
"unresolvedErrorText": "You have {{count}} unresolved errors. You need to resolve them before confirming the hours",
Expand Down Expand Up @@ -81,7 +83,8 @@
"balanceAdjustedMessage": "Your time bank has been updated. You now have {{balance}} hours remaining in the time bank.",
"resetTimebankText": "Reset timebank",
"balanceAdjustmentNotAvailable": "You need to confirm your hours for the week before adjusting timebank balance. If the week is split, both periods needs to be confirmed."
}
},
"periodLockedText": "The period is locked by an administrator, and no changes can be made to it until it is unlocked."
},
"projects": {
"inactiveText": "This project has been marked as inactive.",
Expand Down Expand Up @@ -281,13 +284,22 @@
"employmentStartDateDescription": "The date the user's employment starts. If the user is already employed, set this date to the first day of employment.",
"searchUsersLabel": "Search users..."
},
"missingSubmissions": {
"headerText": "Missing submissions",
"weekStatus": {
"headerText": "Week status",
"teamsReminderMessageTemplate": "You must confirm the following weeks in did: {{periods}}",
"teamsReminderButtonText": "Send reminder in Teams",
"teamsReminderMessageSinglePeriodTemplate": "You must confirm week {{period}} in did.",
"teamsReminderTopicTemplate": "Week {{name}} in did",
"teamsReminderButtonTooltiop": "Send reminder in Teams to all users missing week {{name}}"
"teamsReminderButtonTooltiop": "Send reminder in Teams to all users missing week {{name}}",
"unlockWeekButtonText": "Unlock week",
"lockWeekButtonText": "Lock week",
"weekUnlocked": "Week {{period}} was successfully unlocked.",
"weekLocked": "Week {{period}} was successfully locked, and time entries can no longer be logged for this week.",
"confirmLockTitle": "Lock week",
"confirmLockSubText": "Are you sure you want to lock week {{period}}?",
"lockReasonPlaceholder": "Optionally enter the reason for locking this week...",
"weekOpenTooltip": "Week {{weekNumber}} is open. Tap to lock, and optionally add a reason.",
"weekLockedTooltip": "Week {{weekNumber}} was locked {{lockedAt}}."
},
"teams": "Teams",
"teamsEnabledLabel": "Enable Teams functionality",
Expand Down Expand Up @@ -739,6 +751,7 @@
"managerLabel": "Manager",
"hourlyRateLabel": "Hourly Rate",
"noManagerLabel": "No Manager Assigned",
"reason": "Reason",
"parentProject": "Parent Project"
},
"navigation": {
Expand Down
21 changes: 17 additions & 4 deletions client/i18n/nb.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"weekHoursSummaryText": "Du har totalt **{{hours}}** denne perioden. {{splitWeekInfoText}}",
"hoursNotMatchedText": "Du har **{{hours}}** som ikke er koblet mot et prosjekt. Alle avtaler må stemme overens før du kan bekrefte timene dine.",
"allHoursMatchedText": "Alle timene dine er matchet! Er du klar til å bekrefte perioden din?",
"allHoursMatchedPeriodLockedText": "Alle timene dine er matchet, men perioden er låst og endringer kan ikke gjøres for øyeblikket.",
"periodConfirmedText": "Perioden er bekreftet med {{hours}}. Klikk **Angre bekreft timer** dersom du vil gjøre noen justeringer.",
"ignoredEventsText": "Du har {{ignored_count}} manuelt ignorert(e) kalenderoppføringe(r).",
"undoIgnoreTooltip": "Angre alle ignorerte hendelser.",
Expand Down Expand Up @@ -80,7 +81,9 @@
"balanceAdjustedMessage": "Tidsbanken din er oppdatert. Du har nå {{balance}} timer gjenværende i tidsbanken.",
"resetTimebankText": "Nullstill tidsbank",
"balanceAdjustmentNotAvailable": "Du må bekrefte timene dine for uken før du justerer timebanksaldoen. Hvis uken er delt, må begge periodene bekreftes."
}
},
"periodLockedText": "Perioden er låst av en administrator, og det er ikke mulig å gjøre endringer før den låses opp.",
"periodLockedConfirmedText": "**{{hours}}** bekreftet denne perioden. Perioden er låst og det kan ikke gjøres endringer for den."
},
"projects": {
"inactiveText": "Dette prosjektet er markert som inaktivt.",
Expand Down Expand Up @@ -280,13 +283,22 @@
"headerText": "Roller og tillatelser",
"deleteSuccess": "Rollen {{name}} ble slettet."
},
"missingSubmissions": {
"headerText": "Manglende bekreftelser",
"weekStatus": {
"headerText": "Ukestatus",
"teamsReminderMessageTemplate": "Du må bekrefte følgende uker i did: {{periods}}",
"teamsReminderButtonText": "Send påminnelse i Teams",
"teamsReminderMessageSinglePeriodTemplate": "Du må bekreft uke {{period}} i did.",
"teamsReminderTopicTemplate": "Uke {{name}} i did",
"teamsReminderButtonTooltiop": "Send påminnelse i Teams til alle brukere som ikke har bekreftet uke {{name}}"
"teamsReminderButtonTooltiop": "Send påminnelse i Teams til alle brukere som ikke har bekreftet uke {{name}}",
"unlockWeekButtonText": "Lås opp uke",
"lockWeekButtonText": "Lås uke",
"weekLocked": "Uke {{period}} ble låst, og timer kan ikke lenger føres for denne uken.",
"weekUnlocked": "Uke {{period}} ble låst opp.",
"confirmLockSubText": "Er du sikker på at du vil låse uke {{period}}?",
"lockReasonPlaceholder": "Skriv eventuelt grunnen til å låse uken...",
"confirmLockTitle": "Lås uke",
"weekOpenTooltip": "Uke {{weekNumber}} er åpen. Trykk for å låse, og legg eventuelt til en årsak.",
"weekLockedTooltip": "Uke {{weekNumber}} ble låst {{lockedAt}}."
},
"reportLinks": {
"headerText": "Rapportkoblinger",
Expand Down Expand Up @@ -736,6 +748,7 @@
"managerLabel": "Leder",
"hourlyRateLabel": "Timepris",
"noManagerLabel": "Ingen leder tildelt",
"reason": "Årsak",
"parentProject": "Overordnet prosjekt"
},
"navigation": {
Expand Down
20 changes: 16 additions & 4 deletions client/i18n/nn.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"weekHoursSummaryText": "Du har totalt **{{hours}}** denne perioda. {{splitWeekInfoText}}",
"hoursNotMatchedText": "Du har **{{hours}}** som ikkje er kopla mot eit prosjekt. Alle avtalar må stemme overeins før du kan stadfeste timane dine.",
"allHoursMatchedText": "Alle timane dine er matcha. Er du klar til å stadfeste perioda di?",
"allHoursMatchedPeriodLockedText": "Alle timane dine er matcha, men perioda er låst og endringer kan ikkje gjerast for øyeblikket.",
"periodConfirmedText": "Perioda er stadfesta med {{hours}}. Klikk **Angre stadfesting** dersom du treng å justere timeføringa.",
"ignoredEventsText": "Du har {{ignored_count}} manuelt ignorert(e) kalenderoppføring(er).",
"undoIgnoreTooltip": "Angre alle ignorerte hendelser.",
Expand Down Expand Up @@ -83,7 +84,8 @@
"balanceAdjustedMessage": "Tidsbanken din er oppdatert. Du har nå {{balance}} timer gjenværende i tidsbanken.",
"resetTimebankText": "Nullstill tidsbank",
"balanceAdjustmentNotAvailable": "Du må bekrefte timene dine for uken før du justerer timebanksaldoen. Hvis uken er delt, må begge periodene bekreftes."
}
},
"periodLockedConfirmedText": "**{{hours}}** bekreftet denne perioden. Perioden er låst og det kan ikke gjøres endringer for den."
},
"projects": {
"inactiveText": "Dette prosjektet er markert som inaktivt.",
Expand Down Expand Up @@ -281,13 +283,22 @@
"headerText": "Roller og tillatelser",
"deleteSuccess": "Rollen {{name}} vart sletta."
},
"missingSubmissions": {
"headerText": "Manglende bekreftelser",
"weekStatus": {
"headerText": "Ukestatus",
"teamsReminderMessageTemplate": "Du må bekrefte følgende uker i did: {{periods}}",
"teamsReminderButtonText": "Send påminnelse i Teams",
"teamsReminderMessageSinglePeriodTemplate": "Du må bekreft uke {{period}} i did.",
"teamsReminderTopicTemplate": "Uke {{name}} i did",
"teamsReminderButtonTooltiop": "Send påminning i Teams til alle brukarar som ikkje har bekreftet veke {{name}}"
"teamsReminderButtonTooltiop": "Send påminning i Teams til alle brukarar som ikkje har bekreftet veke {{name}}",
"unlockWeekButtonText": "Lås opp uke",
"lockWeekButtonText": "Lås veke",
"weekLocked": "Veke {{period}} blei låst, og timar kan ikkje lenger førast for denne veka.",
"weekUnlocked": "Veke {{period}} ble låst opp.",
"confirmLockSubText": "Er du sikker på at du vil låse veke {{period}}?",
"lockReasonPlaceholder": "Skriv eventuelt grunnen til å låse veka...",
"confirmLockTitle": "Lås veke",
"weekOpenTooltip": "Veke {{weekNumber}} er åpen. Trykk for å låse, og legg eventuelt til en årsak.",
"weekLockedTooltip": "Veke {{weekNumber}} ble låst {{lockedAt}}."
},
"reportLinks": {
"headerText": "Rapportkoblinger",
Expand Down Expand Up @@ -737,6 +748,7 @@
"managerLabel": "Leder",
"hourlyRateLabel": "Timepris",
"noManagerLabel": "Ingen leder tildelt",
"reason": "Årsak",
"parentProject": "Overordna prosjekt"
},
"navigation": {
Expand Down
7 changes: 2 additions & 5 deletions client/pages/Admin/Admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { ApiTokens } from './ApiTokens'
import { Labels } from './Labels'
import { MissingSubmissions } from './MissingSubmissions'
import { WeekStatus } from './WeekStatus'
import { ReportLinks } from './ReportLinks'
import { RolesPermissions } from './RolesPermissions'
import { SubscriptionSettings } from './SubscriptionSettings'
Expand All @@ -22,10 +22,7 @@ export const Admin: FC = () => {
RolesPermissions,
t('admin.rolesPermissions.headerText')
],
missingsubmissions: [
MissingSubmissions,
t('admin.missingSubmissions.headerText')
],
weekStatus: [WeekStatus, t('admin.weekStatus.headerText')],
labels: [Labels, t('common.labelsText')],
subscription: [
SubscriptionSettings,
Expand Down
2 changes: 1 addition & 1 deletion client/pages/Admin/ApiTokens/useApiTokens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function useApiTokens() {
* @returns - A Promise that resolves when the API token is deleted.
*/
const onDelete = useCallback(async () => {
const response = await getResponse({
const { response } = await getResponse({
title: t('admin.apiTokens.confirmDeleteTitle'),
subText: t('admin.apiTokens.confirmDeleteSubText', {
...selectedToken,
Expand Down
2 changes: 1 addition & 1 deletion client/pages/Admin/Labels/useLabels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function useLabels() {
* or an error toast if not.
*/
const onDelete = useCallback(async () => {
const response = await getResponse({
const { response } = await getResponse({
title: t('admin.labels.confirmDeleteTitle'),
subText: t('admin.labels.confirmDeleteSubText', selectedLabel),
responses: [[t('common.yes'), true, true], [t('common.no')]]
Expand Down
3 changes: 0 additions & 3 deletions client/pages/Admin/MissingSubmissions/List/List.module.scss

This file was deleted.

This file was deleted.

21 changes: 0 additions & 21 deletions client/pages/Admin/MissingSubmissions/MissingSubmissions.tsx

This file was deleted.

2 changes: 0 additions & 2 deletions client/pages/Admin/MissingSubmissions/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion client/pages/Admin/ReportLinks/useReportLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export function useReportLinks() {
* Callback function for deleting a report link.
*/
const onDelete = useCallback(async () => {
const response = await getResponse({
const { response } = await getResponse({
title: t('admin.reportLinks.confirmDeleteTitle'),
subText: t('admin.reportLinks.confirmDeleteSubText', selectedLink),
responses: [
Expand Down
2 changes: 1 addition & 1 deletion client/pages/Admin/RolesPermissions/useRoles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function useRoles() {
* On delete role
*/
const onDelete = useCallback(async () => {
const response = await getResponse({
const { response } = await getResponse({
title: t('admin.roles.confirmDeleteTitle'),
subText: t('admin.roles.confirmDeleteSubText', selectedRole),
responses: [[t('common.yes'), true, true], [t('common.no')]]
Expand Down
10 changes: 10 additions & 0 deletions client/pages/Admin/WeekStatus/List/List.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.list {
margin: 0;

.actions {
display: flex;
align-items: center;
flex-direction: row;
gap: 10px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import { MissingSubmissionUser } from '../MissingSubmissionUser'
import { TeamsReminderButton } from '../TeamsReminderButton'
import styles from './List.module.scss'
import { IListProps } from './types'
import styles from './List.module.scss'
import { LockWeekButton } from '../LockWeekButton'

export const List: TabComponent<IListProps> = ({ users, period }) => {
const { t } = useTranslation()
Expand All @@ -19,15 +20,15 @@ export const List: TabComponent<IListProps> = ({ users, period }) => {
}
return (
<div className={List.className}>
<TeamsReminderButton
title={t(
'admin.missingSubmissions.teamsReminderButtonTooltiop',
period
)}
period={period}
users={period.users}
topic={t('admin.missingSubmissions.teamsReminderTopicTemplate', period)}
/>
<div className={styles.actions}>
<TeamsReminderButton
title={t('admin.weekStatus.teamsReminderButtonTooltiop', period)}
period={period}
users={period.users}
topic={t('admin.weekStatus.teamsReminderTopicTemplate', period)}
/>
<LockWeekButton period={period} />
</div>
{period.users.map((user, index) => (
<MissingSubmissionUser key={index} user={user} period={period} />
))}
Expand Down
1 change: 1 addition & 0 deletions client/pages/Admin/WeekStatus/List/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './List'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.lockWeekButton {
margin: 15px 0;
}
51 changes: 51 additions & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/LockWeekButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Button, Tooltip } from '@fluentui/react-components'
import React from 'react'
import { StyledComponent } from 'types'
import styles from './LockWeekButton.module.scss'
import { ILockWeekButtonProps } from './types'
import { useLockWeekButton } from './useLockWeekButton'
import $date from 'DateUtils'
import { useTranslation } from 'react-i18next'

export const LockWeekButton: StyledComponent<ILockWeekButtonProps> = (
props
) => {
const { t } = useTranslation()
const { text, icon, onClick, lockedPeriod, confirmationDialog } =
useLockWeekButton(props)
return (
<div className={LockWeekButton.className}>
<Tooltip
relationship='description'
content={
lockedPeriod ? (
<div>
<p>
{t('admin.weekStatus.weekLockedTooltip', {
...props.period,
lockedAt: $date.formatDate(
lockedPeriod.lockedAt,
'DD.MM.YYYY HH:mm'
)
})}
</p>
<p hidden={!lockedPeriod?.reason}>
<b>{t('common.reason')}:</b> {lockedPeriod?.reason}
</p>
</div>
) : (
<p>{t('admin.weekStatus.weekOpenTooltip', props.period)}</p>
)
}
>
<Button appearance='subtle' icon={icon} onClick={onClick}>
{text}
</Button>
</Tooltip>
{confirmationDialog}
</div>
)
}

LockWeekButton.displayName = 'LockWeekButton'
LockWeekButton.className = styles.lockWeekButton
1 change: 1 addition & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './LockWeekButton'
6 changes: 6 additions & 0 deletions client/pages/Admin/WeekStatus/LockWeekButton/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IButtonProps } from '@fluentui/react'
import { IMissingSubmissionPeriod } from '../types'

export interface ILockWeekButtonProps extends IButtonProps {
period: IMissingSubmissionPeriod
}
Loading