Skip to content
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
475 changes: 252 additions & 223 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"clsx": "^2.0.0",
"dayjs": "^1.11.3",
"final-form": "^4.20.7",
"next": "^16.1.6",
"next": "^16.2.6",
"parse-duration": "^2.1.4",
"query-string": "^8.1.0",
"react": "^18.2.0",
Expand Down
2 changes: 1 addition & 1 deletion middleware.ts → proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { jiraAuthEndpoints } from 'entities/auth/model/jira/endpoints';
/**
* refreshes token, using Jira's OAuth API
*/
export async function middleware(request: NextRequest) {
export async function proxy(request: NextRequest) {
try {
const { clientId, refreshToken } = await request.json();

Expand Down
1 change: 1 addition & 0 deletions public/local/api/locale-en.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"track.calendar.unit.period": "Period of",
"track.calendar.today": "Today",
"track.calendar.showWeekends": "Show weekends",
"track.calendar.onlyWithTimeSpent": "Only issues with worklogs",
"track.delete.confirm": "Are you sure you want to delete track?",
"track.delete.title": "Delete track",
"track.duration.placeholder": "Put your duration here",
Expand Down
1 change: 1 addition & 0 deletions public/local/api/locale-ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"track.calendar.unit.period": "Период",
"track.calendar.today": "Сегодня",
"track.calendar.showWeekends": "Показать выходные",
"track.calendar.onlyWithTimeSpent": "Только задачи с треками",
"track.delete.confirm": "Вы уверены, что хотите удалить трек?",
"track.delete.title": "Удалить трек",
"track.duration.placeholder": "Укажите длительность",
Expand Down
1 change: 1 addition & 0 deletions src/entities/issue/common/model/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type TIssuesCommonParams = {
language?: TLocale | null;
utcOffsetInMinutes: number | undefined;
tracker: TTrackerConfig;
onlyWithTimeSpent?: boolean;
};

export type TGetUserIssuesParams = TIssuesCommonParams & {
Expand Down
3 changes: 2 additions & 1 deletion src/entities/issue/yandex/model/createYandexIssueRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const getUserIssuesQuery = ({
sortBy,
sortOrder,
utcOffsetInMinutes,
onlyWithTimeSpent,
}: TGetUserIssuesParams) => {
const formattedFrom = DateWrapper.getDateFormat(
DateWrapper.getDate({ date: from, utcOffsetInMinutes }),
Expand Down Expand Up @@ -49,7 +50,7 @@ const getUserIssuesQuery = ({
const keysParam = new YandexQParam('Key', includeIssues);

const queryBuilder = new QueryBuilder(
new QLogic.OR(keysParam, userIssuesForPeriodParam),
onlyWithTimeSpent ? keysParam : new QLogic.OR(keysParam, userIssuesForPeriodParam),
new YandexQParam('Status', statusList),
new YandexQParam('Summary', summary),
new YandexQParam('Queue', queue),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,16 @@ interface ITrackCalendarHeaderProps {
upperRowControls?: ReactNode;
filters?: ReactNode;
trackerName: string;
extraControls?: ReactNode[];
}

export function TrackCalendarHeader({ isEdit, trackerName, filters, upperRowControls }: ITrackCalendarHeaderProps) {
export function TrackCalendarHeader({
isEdit,
trackerName,
filters,
upperRowControls,
extraControls,
}: ITrackCalendarHeaderProps) {
const { push } = useRouter();

return (
Expand Down Expand Up @@ -53,7 +60,7 @@ export function TrackCalendarHeader({ isEdit, trackerName, filters, upperRowCont
</Col>
</Row>

<TrackCalendarHeaderControlBar>{filters}</TrackCalendarHeaderControlBar>
<TrackCalendarHeaderControlBar extraControls={extraControls}>{filters}</TrackCalendarHeaderControlBar>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,53 @@ import { RangePicker } from 'components/RangePicker';
import { useMessage } from 'entities/locale/lib/hooks';
import { DateWrapper } from 'features/date/lib/DateWrapper';
import type { RangePickerProps } from 'antd/es/date-picker';
import type { PropsWithChildren } from 'react';
import type { PropsWithChildren, ReactNode } from 'react';
import { memo, useMemo } from 'react';
import { useFilters } from 'features/filters/lib/useFilters';
import { DATE_FORMAT_DATE } from 'features/date/lib/constants';
import styles from './TrackCalendarHeaderControlBar.module.scss';

export const TrackCalendarHeaderControlBar = memo(({ children }: PropsWithChildren) => {
const message = useMessage();

const { from, to, showWeekends, updateRangeFilter, updateWeekendVisibility, utcOffsetInMinutes } = useFilters();
const fromDate = useMemo(() => DateWrapper.getDate({ date: from, utcOffsetInMinutes }), [from, utcOffsetInMinutes]);
const toDate = useMemo(() => DateWrapper.getDate({ date: to, utcOffsetInMinutes }), [to, utcOffsetInMinutes]);

const handleDateChange = (dates: RangePickerProps['value']) =>
updateRangeFilter({
from: dates?.[0] ? DateWrapper.getDateFormat(dates[0].startOf('day')) : undefined,
to: dates?.[1] ? DateWrapper.getDateFormat(dates[1].endOf('day')) : undefined,
});

const handleWeekendsVisibilityChange = () => {
updateWeekendVisibility(String(Number(!showWeekends)));
};

return (
<Space direction="vertical" size={5} style={{ width: '100%' }}>
<div className={styles.bar}>
<RangePicker
variant="borderless"
allowClear={false}
value={[fromDate, toDate]}
onChange={handleDateChange}
format={DATE_FORMAT_DATE}
/>

<div className={styles.divider} />

{children}
</div>

<Text fs={13}>
<Checkbox checked={showWeekends} onChange={handleWeekendsVisibilityChange}>
<Typography.Text type="secondary">{message('track.calendar.showWeekends')}</Typography.Text>
</Checkbox>
</Text>
</Space>
);
});
export const TrackCalendarHeaderControlBar = memo(
({ children, extraControls }: PropsWithChildren<{ extraControls?: ReactNode[] }>) => {
const message = useMessage();

const { from, to, showWeekends, updateRangeFilter, updateWeekendVisibility, utcOffsetInMinutes } = useFilters();
const fromDate = useMemo(() => DateWrapper.getDate({ date: from, utcOffsetInMinutes }), [from, utcOffsetInMinutes]);
const toDate = useMemo(() => DateWrapper.getDate({ date: to, utcOffsetInMinutes }), [to, utcOffsetInMinutes]);

const handleDateChange = (dates: RangePickerProps['value']) =>
updateRangeFilter({
from: dates?.[0] ? DateWrapper.getDateFormat(dates[0].startOf('day')) : undefined,
to: dates?.[1] ? DateWrapper.getDateFormat(dates[1].endOf('day')) : undefined,
});

const handleWeekendsVisibilityChange = () => {
updateWeekendVisibility(String(Number(!showWeekends)));
};

return (
<Space direction="vertical" size={5} style={{ width: '100%' }}>
<div className={styles.bar}>
<RangePicker
variant="borderless"
allowClear={false}
value={[fromDate, toDate]}
onChange={handleDateChange}
format={DATE_FORMAT_DATE}
/>

<div className={styles.divider} />

{children}
</div>

<Text fs={13}>
<Checkbox checked={showWeekends} onChange={handleWeekendsVisibilityChange}>
<Typography.Text type="secondary">{message('track.calendar.showWeekends')}</Typography.Text>
</Checkbox>
{extraControls}
</Text>
</Space>
);
},
);
12 changes: 11 additions & 1 deletion src/entities/track/yandex/ui/YandexTimesheet/YandexTimesheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import { YandexIssueStatusSelectConnected } from 'entities/issue/yandex/ui/Yande
import { QueueSelect } from 'entities/queue/common/ui/QueueSelect/QueueSelect';
import { IssueSummarySearch } from 'entities/issue/common/ui/IssueSummarySearch/IssueSummarySearch';
import { Message } from 'entities/locale/ui/Message';
import { Button } from 'antd';
import { useMessage } from 'entities/locale/lib/hooks';
import { Button, Checkbox, Typography } from 'antd';
import { YANDEX_ISSUE_SORTING_KEY } from 'entities/issue/yandex/model/constants';
import { useLogoutTracker } from 'entities/tracker/lib/useLogoutTracker';

Expand All @@ -33,6 +34,7 @@ type TProps = {
};

export const YandexTimesheet: FC<TProps> = ({ language, tracker, uId }) => {
const message = useMessage();
const logout = useLogoutTracker(tracker);

const {
Expand All @@ -45,9 +47,11 @@ export const YandexTimesheet: FC<TProps> = ({ language, tracker, uId }) => {
queue,
utcOffsetInMinutes,
userId: userIdFromFilter,
onlyWithTimeSpent,
updateIssueStatus,
updateSummary,
updateQueue,
updateOnlyWithTimeSpent,
} = useFilters();

const { pinnedIssues, pinIssue, unpinIssue } = usePinnedIssues(tracker.orgId);
Expand All @@ -70,6 +74,7 @@ export const YandexTimesheet: FC<TProps> = ({ language, tracker, uId }) => {
sortOrder: sorting.sortOrder,
utcOffsetInMinutes,
tracker,
onlyWithTimeSpent,
});

const { currentData: queueList, isFetching: isFetchingQueueList } = yandexQueueApi.useGetQueuesQuery({ tracker });
Expand Down Expand Up @@ -112,6 +117,11 @@ export const YandexTimesheet: FC<TProps> = ({ language, tracker, uId }) => {
<IssueSummarySearch defaultValue={summary} onSearch={updateSummary} />
</>
}
extraControls={[
<Checkbox checked={onlyWithTimeSpent} onChange={(e) => updateOnlyWithTimeSpent(e.target.checked)}>
<Typography.Text type="secondary">{message('track.calendar.onlyWithTimeSpent')}</Typography.Text>
</Checkbox>,
]}
/>
<TrackCalendar
tracker={tracker}
Expand Down
3 changes: 3 additions & 0 deletions src/features/filters/lib/useFilterValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useSorting } from 'features/filters/lib/useSorting';
import { useSummaryFilter } from 'features/filters/lib/useSummaryFilter';
import { useQueueFilter } from 'features/filters/lib/useQueueFilter';
import { useTimeOffsetFilter } from 'features/filters/lib/useTimeOffsetFilter';
import { useOnlyWithTimeSpentFilter } from './useOnlyWithTimeSpentFilter';

export const useFilterValues = () => {
const utcOffsetInMinutes = useTimeOffsetFilter();
Expand All @@ -16,6 +17,7 @@ export const useFilterValues = () => {
const summary = useSummaryFilter();
const queue = useQueueFilter();
const sorting = useSorting();
const onlyWithTimeSpent = useOnlyWithTimeSpentFilter();

return {
from,
Expand All @@ -29,5 +31,6 @@ export const useFilterValues = () => {
queue,
sorting,
utcOffsetInMinutes,
onlyWithTimeSpent,
};
};
16 changes: 15 additions & 1 deletion src/features/filters/lib/useFilters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ export const useFilters = () => {
const filterValues = useFilterValues();

const simpleUpdateFilter = useCallback(
(name: string, nextValue: string | string[]) => {
(name: string, nextValue: string | string[] | boolean) => {
if (!nextValue) {
const { [name]: _, ...restQuery } = router.query;
router.replace({ query: restQuery });
return;
}

router.replace({
query: {
...router.query,
Expand Down Expand Up @@ -82,6 +88,13 @@ export const useFilters = () => {
[simpleUpdateFilter],
);

const updateOnlyWithTimeSpent = useCallback(
(nextOnlyWithTimeSpent: boolean) => {
simpleUpdateFilter('only_with_time_spent', nextOnlyWithTimeSpent);
},
[simpleUpdateFilter],
);

const updateSorting = useCallback(
(sortBy: string, order: TSortOrder) => {
router.replace({
Expand Down Expand Up @@ -119,5 +132,6 @@ export const useFilters = () => {
updateQueue,
updateSorting,
updateTimeOffset,
updateOnlyWithTimeSpent,
};
};
7 changes: 7 additions & 0 deletions src/features/filters/lib/useOnlyWithTimeSpentFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { useRouter } from 'next/router';

export const useOnlyWithTimeSpentFilter = () => {
const router = useRouter();

return router.query.only_with_time_spent as boolean | undefined;
};
Loading