diff --git a/package.json b/package.json
index 355018894c1..f98d3933751 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,7 @@
"@uiw/react-codemirror": "^4.25.1",
"d3-scale": "^4.0.2",
"d3-time-format": "^4.1.0",
- "date-fns": "^2.28.0",
+ "date-fns": "^4.1.0",
"highlight.js": "^11.11.1",
"history": "^4.9.0",
"immer": "^10.1.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 07593a652af..10f403d9e12 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -61,8 +61,8 @@ importers:
specifier: ^4.1.0
version: 4.1.0
date-fns:
- specifier: ^2.28.0
- version: 2.30.0
+ specifier: ^4.1.0
+ version: 4.1.0
highlight.js:
specifier: ^11.11.1
version: 11.11.1
@@ -3896,10 +3896,6 @@ packages:
date-fns-jalali@4.1.0-0:
resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==}
- date-fns@2.30.0:
- resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
- engines: {node: '>=0.11'}
-
date-fns@4.1.0:
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
@@ -10911,10 +10907,6 @@ snapshots:
date-fns-jalali@4.1.0-0: {}
- date-fns@2.30.0:
- dependencies:
- '@babel/runtime': 7.28.2
-
date-fns@4.1.0: {}
debug@4.4.1:
diff --git a/web/packages/teleport/src/AccessRequests/types.ts b/web/packages/teleport/src/AccessRequests/types.ts
deleted file mode 100644
index 7d06636b86e..00000000000
--- a/web/packages/teleport/src/AccessRequests/types.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * Teleport
- * Copyright (C) 2023 Gravitational, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { RequestableResourceKind } from 'shared/components/AccessRequests/NewRequest/resource';
-import type { Option } from 'shared/components/Select';
-
-export type DurationOption = Option;
-
-export interface Resource {
- id: {
- kind: RequestableResourceKind;
- name: string;
- clusterName: string;
- subResourceName?: string;
- };
- details?: {
- hostname?: string;
- friendlyName?: string;
- };
-}
-
-type RequestState = 'NONE' | 'PENDING' | 'APPROVED' | 'DENIED' | 'APPLIED' | '';
-
-export interface ResourceId {
- kind: RequestableResourceKind;
- name: string;
- clusterName: string;
- subResourceName?: string;
-}
-
-export interface AccessRequest {
- id: string;
- created: Date;
- expires: Date;
- maxDuration?: Date;
- requestReason: string;
- resolveReason: string;
- resources: Resource[];
- reviews: string[];
- roles: string[];
- sessionTTL?: Date;
- state: RequestState;
- suggestedReviewers: string[] | null;
- thresholdNames: string[];
- user: string;
-}
-
-export interface CreateAccessRequest {
- reason?: string;
- roles?: string[];
- resourceIds?: ResourceId[];
- suggestedReviewers?: string[];
- maxDuration?: Date;
- dryRun?: boolean;
-}
-
-interface AccessRequestResourceBase {
- id: string;
- type: 'app' | 'node' | 'kubernetes' | 'desktop' | 'database';
-}
-
-interface AccessRequestGenericResource extends AccessRequestResourceBase {
- type: 'app' | 'kubernetes' | 'desktop' | 'database';
-}
-
-interface AccessRequestNodeResource extends AccessRequestResourceBase {
- type: 'node';
- friendlyName: string;
-}
-
-export type AccessRequestResource =
- | AccessRequestGenericResource
- | AccessRequestNodeResource;
diff --git a/web/packages/teleport/src/AccessRequests/utils.test.ts b/web/packages/teleport/src/AccessRequests/utils.test.ts
deleted file mode 100644
index d80825cfdb8..00000000000
--- a/web/packages/teleport/src/AccessRequests/utils.test.ts
+++ /dev/null
@@ -1,423 +0,0 @@
-/**
- * Teleport
- * Copyright (C) 2023 Gravitational, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import { Duration } from 'date-fns';
-
-import {
- middleValues,
- requestTtlMiddleValues,
- roundToNearestTenMinutes,
-} from 'teleport/AccessRequests/utils';
-
-// Generate testing response
-function generateResponse(
- currentDate: Date,
- values: Array<{
- days: number;
- hours: number;
- minutes: number;
- }>
-) {
- const defaultValues = {
- years: 0,
- months: 0,
- minutes: 0,
- seconds: 0,
- };
- const result = [];
- for (let i = 0; i < values.length; i++) {
- const { days, hours, minutes } = values[i];
- const duration = {
- ...defaultValues,
- days,
- hours,
- minutes,
- };
- let d = new Date(currentDate);
- d.setDate(currentDate.getDate() + days);
- d.setHours(currentDate.getHours() + hours);
- d.setMinutes(currentDate.getMinutes() + minutes);
- const timestamp = d.getTime();
- result.push({
- timestamp,
- duration,
- });
- }
- return result;
-}
-
-describe('generate middle times', () => {
- const cases: {
- name: string;
- created: string;
- sessionTTL: string;
- maxDuration: string;
- expected: Array<{
- days: number;
- hours: number;
- minutes: number;
- }>;
- }[] = [
- {
- name: '3 days max',
- created: '2021-09-01T00:00:00.000Z',
- sessionTTL: '2021-09-01T01:00:00.000Z',
- maxDuration: '2021-09-04T00:00:00.000Z',
- expected: [
- {
- days: 0,
- hours: 1,
- minutes: 0,
- },
- {
- days: 1,
- hours: 0,
- minutes: 0,
- },
- {
- days: 2,
- hours: 0,
- minutes: 0,
- },
- {
- days: 3,
- hours: 0,
- minutes: 0,
- },
- ],
- },
- {
- name: '1 day max',
- created: '2021-09-01T00:00:00.000Z',
- sessionTTL: '2021-09-01T01:00:00.000Z',
- maxDuration: '2021-09-02T00:00:00.000Z',
- expected: [
- {
- days: 0,
- hours: 1,
- minutes: 0,
- },
- {
- days: 1,
- hours: 0,
- minutes: 0,
- },
- ],
- },
- {
- name: 'session ttl is 10 min',
- created: '2021-09-01T00:00:00.000Z',
- sessionTTL: '2021-09-01T00:10:00.000Z',
- maxDuration: '2021-09-03T00:00:00.000Z',
- expected: [
- {
- days: 0,
- hours: 0,
- minutes: 10,
- },
- {
- days: 1,
- hours: 0,
- minutes: 0,
- },
- {
- days: 2,
- hours: 0,
- minutes: 0,
- },
- ],
- },
- {
- name: '10 minutes min - real values',
- created: '2023-09-21T20:50:52.669012121Z',
- sessionTTL: '2023-09-21T21:00:52.669081473Z',
- maxDuration: '2023-09-27T20:50:52.669081473Z',
- expected: [
- {
- days: 0,
- hours: 0,
- minutes: 10,
- },
- {
- days: 1,
- hours: 0,
- minutes: 0,
- },
- {
- days: 2,
- hours: 0,
- minutes: 0,
- },
- {
- days: 3,
- hours: 0,
- minutes: 0,
- },
- {
- days: 4,
- hours: 0,
- minutes: 0,
- },
- {
- days: 5,
- hours: 0,
- minutes: 0,
- },
- {
- days: 6,
- hours: 0,
- minutes: 0,
- },
- ],
- },
- {
- name: 'only one option generated',
- created: '2023-09-21T10:00:52.669012121Z',
- sessionTTL: '2023-09-21T15:00:52.669081473Z',
- maxDuration: '2023-09-21T15:00:52.669081473Z',
- expected: [
- {
- days: 0,
- hours: 5,
- minutes: 0,
- },
- ],
- },
- {
- name: 'generate all options if max duration is grater than session ttl but less than 1d',
- created: '2023-09-21T10:00:52.669012121Z',
- sessionTTL: '2023-09-21T15:00:52.669081473Z',
- maxDuration: '2023-09-21T17:00:52.669081473Z',
- expected: [
- {
- days: 0,
- hours: 5,
- minutes: 0,
- },
- {
- days: 0,
- hours: 7,
- minutes: 0,
- },
- ],
- },
- ];
-
- test.each(cases)(
- '$name',
- ({ sessionTTL, maxDuration, created, expected }) => {
- const result = middleValues(
- new Date(created),
- new Date(sessionTTL),
- new Date(maxDuration)
- );
- expect(result).toEqual(generateResponse(new Date(created), expected));
- }
- );
-});
-
-describe('generate request TTL middle times', () => {
- const cases: {
- name: string;
- created: string;
- sessionTTL: string;
- expected: Array<{
- days: number;
- hours: number;
- minutes: number;
- }>;
- }[] = [
- {
- name: 'max session TTL',
- created: '2021-09-01T00:00:00.000Z',
- sessionTTL: '2021-09-02T06:00:00.000Z',
- expected: [
- {
- days: 0,
- hours: 1,
- minutes: 0,
- },
- {
- days: 0,
- hours: 2,
- minutes: 0,
- },
- {
- days: 0,
- hours: 3,
- minutes: 0,
- },
- {
- days: 0,
- hours: 4,
- minutes: 0,
- },
- {
- days: 0,
- hours: 6,
- minutes: 0,
- },
- {
- days: 0,
- hours: 8,
- minutes: 0,
- },
- {
- days: 0,
- hours: 12,
- minutes: 0,
- },
- {
- days: 0,
- hours: 18,
- minutes: 0,
- },
- {
- days: 1,
- hours: 0,
- minutes: 0,
- },
- {
- days: 1,
- hours: 6,
- minutes: 0,
- },
- ],
- },
- {
- name: 'shortest session TTL',
- created: '2021-09-01T00:00:00.000Z',
- sessionTTL: '2021-09-01T00:30:00.000Z',
- expected: [
- {
- days: 0,
- hours: 0,
- minutes: 30,
- },
- ],
- },
- {
- name: 'session TTL in middle',
- created: '2021-09-01T00:00:00.000Z',
- sessionTTL: '2021-09-01T08:30:00.000Z',
- expected: [
- {
- days: 0,
- hours: 1,
- minutes: 0,
- },
- {
- days: 0,
- hours: 2,
- minutes: 0,
- },
- {
- days: 0,
- hours: 3,
- minutes: 0,
- },
- {
- days: 0,
- hours: 4,
- minutes: 0,
- },
- {
- days: 0,
- hours: 6,
- minutes: 0,
- },
- {
- days: 0,
- hours: 8,
- minutes: 0,
- },
- ],
- },
- ];
- test.each(cases)('$name', ({ sessionTTL, created, expected }) => {
- const result = requestTtlMiddleValues(
- new Date(created),
- new Date(sessionTTL)
- );
- expect(result).toEqual(generateResponse(new Date(created), expected));
- });
-});
-
-describe('round to nearest 10 minutes', () => {
- const cases: {
- name: string;
- input: Duration;
- expected: Duration;
- }[] = [
- {
- name: 'round up',
- input: { minutes: 9, seconds: 0 },
- expected: { minutes: 10, seconds: 0 },
- },
- {
- name: 'round down',
- input: { minutes: 11, seconds: 0 },
- expected: { minutes: 10, seconds: 0 },
- },
- {
- name: 'round to 10',
- input: { minutes: 15, seconds: 0 },
- expected: { minutes: 20, seconds: 0 },
- },
- {
- name: 'do not round to 0',
- input: { minutes: 1, seconds: 0 },
- expected: { minutes: 10, seconds: 0 },
- },
- {
- name: 'round minutes to 0 when days or hours are present',
- input: { hours: 3, minutes: 1, seconds: 0 },
- expected: { hours: 3, minutes: 0, seconds: 0 },
- },
- {
- name: 'do not round to 0',
- input: { minutes: 0, seconds: 0 },
- expected: { minutes: 10, seconds: 0 },
- },
- {
- name: 'seconds are removed',
- input: { minutes: 9, seconds: 10 },
- expected: { minutes: 10, seconds: 0 },
- },
- {
- name: "duration doesn't change when days are present",
- input: { days: 1, minutes: 9, seconds: 10 },
- expected: { days: 1, minutes: 10, seconds: 0 },
- },
- {
- name: 'add 60 minutes to undefined hour and set minutes to 0',
- input: { minutes: 60 },
- expected: { hours: 1, minutes: 0, seconds: 0 },
- },
- {
- name: 'add 60 minutes to existing hour and set minutes to 0',
- input: { hours: 3, minutes: 60 },
- expected: { hours: 4, minutes: 0, seconds: 0 },
- },
- ];
-
- test.each(cases)('$name', ({ input, expected }) => {
- const result = roundToNearestTenMinutes(input);
- expect(result).toEqual(expected);
- });
-});
diff --git a/web/packages/teleport/src/AccessRequests/utils.ts b/web/packages/teleport/src/AccessRequests/utils.ts
deleted file mode 100644
index ecc69c4cf1b..00000000000
--- a/web/packages/teleport/src/AccessRequests/utils.ts
+++ /dev/null
@@ -1,160 +0,0 @@
-/**
- * Teleport
- * Copyright (C) 2023 Gravitational, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-import {
- addDays,
- addHours,
- Duration,
- intervalToDuration,
- isAfter,
- isBefore,
-} from 'date-fns';
-
-type TimeDuration = {
- timestamp: number;
- duration: Duration;
-};
-
-// Round the duration to the nearest 10 minutes
-// Example:
-// 9m -> 10m
-// 10m -> 10m
-// 11m -> 10m
-// 15m -> 20m
-// 1d -> 1d
-// 1d 1h -> 1d 1h
-// The only exception is 0m, which is rounded to 10m
-export function roundToNearestTenMinutes(date: Duration): Duration {
- let minutes = date.minutes;
- let roundedMinutes = Math.round(minutes / 10) * 10; // Round to the nearest 10
- if (roundedMinutes === 0 && !date.days && !date.hours) {
- // Do not round down to 0. This
- roundedMinutes = 10;
- }
-
- // 60 minutes == 1 hour
- // Prevent displaying time as eg: `5 hrs and 60 mins`
- // to `6 hrs`.
- if (roundedMinutes === 60) {
- if (!date.hours) {
- date.hours = 0;
- }
- date.hours += 1;
- roundedMinutes = 0;
- }
- date.minutes = roundedMinutes;
- date.seconds = 0;
-
- return date;
-}
-
-// Generate a list of middle values between start and end. The first value is the
-// session TTL that is rounded to the nearest hour. The rest of the values are
-// rounded to the nearest day. Example:
-//
-// created: 2021-09-01T00:00:00.000Z
-// start: 2021-09-01T01:00:00.000Z
-// end: 2021-09-03T00:00:00.000Z
-// now: 2021-09-01T00:00:00.000Z
-//
-// returns: [1h, 1d, 2d, 3d]
-export function middleValues(
- created: Date,
- start: Date,
- end: Date
-): TimeDuration[] {
- const getInterval = (d: Date) =>
- roundToNearestTenMinutes(
- intervalToDuration({
- start: created,
- end: d,
- })
- );
-
- const points: Date[] = [start];
-
- if (isAfter(addDays(created, 1), end)) {
- // Add all possible options to the list. This covers the case when the
- // max duration is less than 24 hours.
- if (isBefore(addHours(points[points.length - 1], 1), end)) {
- points.push(end);
- }
-
- return points.map(d => ({
- timestamp: d.getTime(),
- duration: getInterval(d),
- }));
- }
-
- points.push(addDays(created, 1));
-
- // I also prefer while(true), but our linter doesn't
- for (;;) {
- const next = addHours(points[points.length - 1], 24);
- // Allow next == end
- if (next > end) {
- break;
- }
- points.push(next);
- }
-
- return points.map(d => ({
- timestamp: d.getTime(),
- duration: getInterval(d),
- }));
-}
-
-// Generate a list of middle values between now and the request TTL.
-export function requestTtlMiddleValues(
- created: Date,
- requestTtl: Date
-): TimeDuration[] {
- const getInterval = (d: Date) =>
- roundToNearestTenMinutes(
- intervalToDuration({
- start: created,
- end: d,
- })
- );
-
- if (isAfter(addHours(created, 1), requestTtl)) {
- return [
- {
- timestamp: requestTtl.getTime(),
- duration: getInterval(requestTtl),
- },
- ];
- }
-
- const points: Date[] = [];
- // Staggered hour options, up to 1 week.
- const hourOptions = [1, 2, 3, 4, 6, 8, 12, 18, 24, 30, 168];
-
- for (const h of hourOptions) {
- const t = addHours(created, h);
- if (isAfter(t, requestTtl)) {
- break;
- }
- points.push(t);
- }
-
- return points.map(d => ({
- timestamp: d.getTime(),
- duration: getInterval(d),
- }));
-}
diff --git a/web/packages/teleport/src/BotInstances/List/BotInstancesList.tsx b/web/packages/teleport/src/BotInstances/List/BotInstancesList.tsx
index bade432d179..1a162d7a294 100644
--- a/web/packages/teleport/src/BotInstances/List/BotInstancesList.tsx
+++ b/web/packages/teleport/src/BotInstances/List/BotInstancesList.tsx
@@ -16,9 +16,9 @@
* along with this program. If not, see .
*/
-import format from 'date-fns/format';
-import formatDistanceToNowStrict from 'date-fns/formatDistanceToNowStrict';
-import parseISO from 'date-fns/parseISO';
+import { format } from 'date-fns/format';
+import { formatDistanceToNowStrict } from 'date-fns/formatDistanceToNowStrict';
+import { parseISO } from 'date-fns/parseISO';
import styled from 'styled-components';
import { Info } from 'design/Alert/Alert';
diff --git a/web/packages/teleport/src/Bots/Details/Instance.tsx b/web/packages/teleport/src/Bots/Details/Instance.tsx
index aaac1f31452..0ada9f58faf 100644
--- a/web/packages/teleport/src/Bots/Details/Instance.tsx
+++ b/web/packages/teleport/src/Bots/Details/Instance.tsx
@@ -16,9 +16,9 @@
* along with this program. If not, see .
*/
-import format from 'date-fns/format';
-import formatDistanceToNowStrict from 'date-fns/formatDistanceToNowStrict';
-import parseISO from 'date-fns/parseISO';
+import { format } from 'date-fns/format';
+import { formatDistanceToNowStrict } from 'date-fns/formatDistanceToNowStrict';
+import { parseISO } from 'date-fns/parseISO';
import { ReactElement } from 'react';
import styled from 'styled-components';
diff --git a/web/packages/teleport/src/lib/locks/ResourceLockIndicator.tsx b/web/packages/teleport/src/lib/locks/ResourceLockIndicator.tsx
index 95145ccab0b..cd2a4f1256b 100644
--- a/web/packages/teleport/src/lib/locks/ResourceLockIndicator.tsx
+++ b/web/packages/teleport/src/lib/locks/ResourceLockIndicator.tsx
@@ -16,8 +16,8 @@
* along with this program. If not, see .
*/
-import format from 'date-fns/format';
-import parseISO from 'date-fns/parseISO';
+import { format } from 'date-fns/format';
+import { parseISO } from 'date-fns/parseISO';
import styled from 'styled-components';
import Flex from 'design/Flex/Flex';
diff --git a/web/packages/teleport/src/lib/locks/ResourceUnlockDialog.tsx b/web/packages/teleport/src/lib/locks/ResourceUnlockDialog.tsx
index 4f9923bd073..7df9d2ad292 100644
--- a/web/packages/teleport/src/lib/locks/ResourceUnlockDialog.tsx
+++ b/web/packages/teleport/src/lib/locks/ResourceUnlockDialog.tsx
@@ -16,8 +16,8 @@
* along with this program. If not, see .
*/
-import format from 'date-fns/format';
-import parseISO from 'date-fns/parseISO';
+import { format } from 'date-fns/format';
+import { parseISO } from 'date-fns/parseISO';
import { MouseEventHandler } from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';