mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-15 10:48:31 +00:00
Fixes : 14333 - Changed announcements startTime and endTime from seconds to milliseconds. (#16438)
* Improvement: Changed announcements startTime and endTime from seconds to milliseconds. * Improvement: Changed announcements startTime and endTime from seconds to milliseconds. * supported announcement milleseconds change from UI * fix sonar issue * remove unwanted code --------- Co-authored-by: Ashish Gupta <ashish@getcollate.io> Co-authored-by: Mohit Yadav <105265192+mohityadav766@users.noreply.github.com>
This commit is contained in:
parent
612de36ffb
commit
7558ccc432
@ -31,7 +31,7 @@ public class FeedFilter {
|
|||||||
condition1 = String.format("type = '%s'", threadType.value());
|
condition1 = String.format("type = '%s'", threadType.value());
|
||||||
if (ThreadType.Announcement.equals(threadType) && activeAnnouncement != null) {
|
if (ThreadType.Announcement.equals(threadType) && activeAnnouncement != null) {
|
||||||
// Add activeAnnouncement filter
|
// Add activeAnnouncement filter
|
||||||
long now = System.currentTimeMillis() / 1000; // epoch time in seconds
|
long now = System.currentTimeMillis(); // epoch time in milliseconds
|
||||||
String condition2 =
|
String condition2 =
|
||||||
activeAnnouncement
|
activeAnnouncement
|
||||||
? String.format("%s BETWEEN announcementStart AND announcementEnd", now)
|
? String.format("%s BETWEEN announcementStart AND announcementEnd", now)
|
||||||
|
@ -36,6 +36,8 @@ import static org.openmetadata.service.jdbi3.UserRepository.TEAMS_FIELD;
|
|||||||
import static org.openmetadata.service.util.EntityUtil.compareEntityReference;
|
import static org.openmetadata.service.util.EntityUtil.compareEntityReference;
|
||||||
|
|
||||||
import io.jsonwebtoken.lang.Collections;
|
import io.jsonwebtoken.lang.Collections;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -112,6 +114,8 @@ public class FeedRepository {
|
|||||||
public static final String DELETED_USER_DISPLAY = "User was deleted";
|
public static final String DELETED_USER_DISPLAY = "User was deleted";
|
||||||
public static final String DELETED_TEAM_NAME = "DeletedTeam";
|
public static final String DELETED_TEAM_NAME = "DeletedTeam";
|
||||||
public static final String DELETED_TEAM_DISPLAY = "Team was deleted";
|
public static final String DELETED_TEAM_DISPLAY = "Team was deleted";
|
||||||
|
private static final long MAX_SECONDS_TIMESTAMP = 2147483647L;
|
||||||
|
|
||||||
private final CollectionDAO dao;
|
private final CollectionDAO dao;
|
||||||
private static final MessageDecorator<FeedMessage> FEED_MESSAGE_FORMATTER =
|
private static final MessageDecorator<FeedMessage> FEED_MESSAGE_FORMATTER =
|
||||||
new FeedMessageDecorator();
|
new FeedMessageDecorator();
|
||||||
@ -864,6 +868,12 @@ public class FeedRepository {
|
|||||||
if (startTime >= endTime) {
|
if (startTime >= endTime) {
|
||||||
throw new IllegalArgumentException(ANNOUNCEMENT_INVALID_START_TIME);
|
throw new IllegalArgumentException(ANNOUNCEMENT_INVALID_START_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts start and end times to milliseconds if they are in seconds.
|
||||||
|
if (startTime <= MAX_SECONDS_TIMESTAMP && endTime <= MAX_SECONDS_TIMESTAMP) {
|
||||||
|
convertStartAndEndTimeToMilliseconds(thread);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO fix this - overlapping announcements should be allowed
|
// TODO fix this - overlapping announcements should be allowed
|
||||||
List<String> announcements =
|
List<String> announcements =
|
||||||
dao.feedDAO()
|
dao.feedDAO()
|
||||||
@ -874,6 +884,26 @@ public class FeedRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void convertStartAndEndTimeToMilliseconds(Thread thread) {
|
||||||
|
Optional.ofNullable(thread.getAnnouncement())
|
||||||
|
.ifPresent(
|
||||||
|
announcement -> {
|
||||||
|
Optional.ofNullable(announcement.getStartTime())
|
||||||
|
.ifPresent(
|
||||||
|
startTime ->
|
||||||
|
announcement.setStartTime(convertSecondsToMilliseconds(startTime)));
|
||||||
|
Optional.ofNullable(announcement.getEndTime())
|
||||||
|
.ifPresent(
|
||||||
|
endTime -> announcement.setEndTime(convertSecondsToMilliseconds(endTime)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long convertSecondsToMilliseconds(long seconds) {
|
||||||
|
return LocalDateTime.ofEpochSecond(seconds, 0, ZoneOffset.UTC)
|
||||||
|
.toInstant(ZoneOffset.UTC)
|
||||||
|
.toEpochMilli();
|
||||||
|
}
|
||||||
|
|
||||||
private void validateAssignee(Thread thread) {
|
private void validateAssignee(Thread thread) {
|
||||||
if (thread != null && ThreadType.Task.equals(thread.getType())) {
|
if (thread != null && ThreadType.Task.equals(thread.getType())) {
|
||||||
String createdByUserName = thread.getCreatedBy();
|
String createdByUserName = thread.getCreatedBy();
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.openmetadata.service.migration.mysql.v141;
|
||||||
|
|
||||||
|
import static org.openmetadata.service.migration.utils.v141.MigrationUtil.migrateAnnouncementsTimeFormat;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.openmetadata.service.migration.api.MigrationProcessImpl;
|
||||||
|
import org.openmetadata.service.migration.utils.MigrationFile;
|
||||||
|
|
||||||
|
public class Migration extends MigrationProcessImpl {
|
||||||
|
|
||||||
|
public Migration(MigrationFile migrationFile) {
|
||||||
|
super(migrationFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public void runDataMigration() {
|
||||||
|
migrateAnnouncementsTimeFormat(handle, false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package org.openmetadata.service.migration.postgres.v141;
|
||||||
|
|
||||||
|
import static org.openmetadata.service.migration.utils.v141.MigrationUtil.migrateAnnouncementsTimeFormat;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.openmetadata.service.migration.api.MigrationProcessImpl;
|
||||||
|
import org.openmetadata.service.migration.utils.MigrationFile;
|
||||||
|
|
||||||
|
public class Migration extends MigrationProcessImpl {
|
||||||
|
public Migration(MigrationFile migrationFile) {
|
||||||
|
super(migrationFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public void runDataMigration() {
|
||||||
|
migrateAnnouncementsTimeFormat(handle, true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package org.openmetadata.service.migration.utils.v141;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jdbi.v3.core.Handle;
|
||||||
|
import org.openmetadata.schema.entity.feed.Thread;
|
||||||
|
import org.openmetadata.schema.type.AnnouncementDetails;
|
||||||
|
import org.openmetadata.service.util.JsonUtils;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class MigrationUtil {
|
||||||
|
private static final long MAX_SECONDS_TIMESTAMP = 2147483647L;
|
||||||
|
|
||||||
|
public static void migrateAnnouncementsTimeFormat(Handle handle, boolean postgresDbFlag) {
|
||||||
|
// Fetch all threads of type Announcement from the database
|
||||||
|
List<Thread> threads = fetchAnnouncementThreads(handle);
|
||||||
|
|
||||||
|
threads.forEach(
|
||||||
|
thread -> {
|
||||||
|
Optional<AnnouncementDetails> announcementOpt =
|
||||||
|
Optional.ofNullable(thread.getAnnouncement());
|
||||||
|
boolean updated =
|
||||||
|
announcementOpt
|
||||||
|
.map(
|
||||||
|
announcement -> {
|
||||||
|
boolean startUpdated =
|
||||||
|
Optional.ofNullable(announcement.getStartTime())
|
||||||
|
.filter(MigrationUtil::isInSeconds)
|
||||||
|
.map(MigrationUtil::convertSecondsToMilliseconds)
|
||||||
|
.map(
|
||||||
|
startTime -> {
|
||||||
|
announcement.setStartTime(startTime);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.orElse(false);
|
||||||
|
|
||||||
|
boolean endUpdated =
|
||||||
|
Optional.ofNullable(announcement.getEndTime())
|
||||||
|
.filter(MigrationUtil::isInSeconds)
|
||||||
|
.map(MigrationUtil::convertSecondsToMilliseconds)
|
||||||
|
.map(
|
||||||
|
endTime -> {
|
||||||
|
announcement.setEndTime(endTime);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.orElse(false);
|
||||||
|
|
||||||
|
return startUpdated || endUpdated;
|
||||||
|
})
|
||||||
|
.orElse(false);
|
||||||
|
|
||||||
|
// If we made any updates, persist the changes back to the database
|
||||||
|
if (updated) {
|
||||||
|
if (postgresDbFlag) {
|
||||||
|
updateThreadPostgres(handle, thread);
|
||||||
|
} else {
|
||||||
|
updateThreadMySql(handle, thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Thread> fetchAnnouncementThreads(Handle handle) {
|
||||||
|
String query = "SELECT json FROM thread_entity WHERE type = 'Announcement'";
|
||||||
|
|
||||||
|
return handle
|
||||||
|
.createQuery(query)
|
||||||
|
.map((rs, ctx) -> JsonUtils.readValue(rs.getString("json"), Thread.class))
|
||||||
|
.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isInSeconds(Long timestamp) {
|
||||||
|
return timestamp != null && timestamp <= MAX_SECONDS_TIMESTAMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateThreadMySql(Handle handle, Thread thread) {
|
||||||
|
String updateQuery = "UPDATE thread_entity SET json = :json WHERE id = :id";
|
||||||
|
handle
|
||||||
|
.createUpdate(updateQuery)
|
||||||
|
.bind("json", JsonUtils.pojoToJson(thread))
|
||||||
|
.bind("id", thread.getId().toString())
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateThreadPostgres(Handle handle, Thread thread) {
|
||||||
|
String updateQuery = "UPDATE thread_entity SET json = CAST(:json AS jsonb) WHERE id = :id";
|
||||||
|
handle
|
||||||
|
.createUpdate(updateQuery)
|
||||||
|
.bind("json", JsonUtils.pojoToJson(thread))
|
||||||
|
.bind("id", thread.getId().toString())
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long convertSecondsToMilliseconds(long seconds) {
|
||||||
|
return LocalDateTime.ofEpochSecond(seconds, 0, ZoneOffset.UTC)
|
||||||
|
.toInstant(ZoneOffset.UTC)
|
||||||
|
.toEpochMilli();
|
||||||
|
}
|
||||||
|
}
|
@ -991,8 +991,9 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
|
|||||||
USER.getName(), about, "Announcement One", announcementDetails, USER_AUTH_HEADERS);
|
USER.getName(), about, "Announcement One", announcementDetails, USER_AUTH_HEADERS);
|
||||||
String originalJson = JsonUtils.pojoToJson(thread);
|
String originalJson = JsonUtils.pojoToJson(thread);
|
||||||
|
|
||||||
long startTs = now.plusDays(6L).toEpochSecond(ZoneOffset.UTC);
|
long startTs = now.plusDays(6L).toInstant(ZoneOffset.UTC).toEpochMilli();
|
||||||
long endTs = now.plusDays(7L).toEpochSecond(ZoneOffset.UTC);
|
long endTs = now.plusDays(7L).toInstant(ZoneOffset.UTC).toEpochMilli();
|
||||||
|
|
||||||
announcementDetails.withStartTime(startTs).withEndTime(endTs);
|
announcementDetails.withStartTime(startTs).withEndTime(endTs);
|
||||||
Thread updated = thread.withAnnouncement(announcementDetails);
|
Thread updated = thread.withAnnouncement(announcementDetails);
|
||||||
|
|
||||||
@ -1045,8 +1046,8 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
|
|||||||
|
|
||||||
// create announcement with start time > end time
|
// create announcement with start time > end time
|
||||||
announcementDetails
|
announcementDetails
|
||||||
.withStartTime(now.plusDays(58L).toEpochSecond(ZoneOffset.UTC))
|
.withStartTime(now.plusDays(58L).toInstant(ZoneOffset.UTC).toEpochMilli())
|
||||||
.withEndTime(now.plusDays(57L).toEpochSecond(ZoneOffset.UTC));
|
.withEndTime(now.plusDays(57L).toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
Thread updated2 = thread2.withAnnouncement(announcementDetails);
|
Thread updated2 = thread2.withAnnouncement(announcementDetails);
|
||||||
assertResponse(
|
assertResponse(
|
||||||
() -> patchThread(thread2.getId(), originalJson, updated2, USER_AUTH_HEADERS),
|
() -> patchThread(thread2.getId(), originalJson, updated2, USER_AUTH_HEADERS),
|
||||||
@ -1055,8 +1056,8 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
|
|||||||
|
|
||||||
// create announcement with overlaps
|
// create announcement with overlaps
|
||||||
announcementDetails
|
announcementDetails
|
||||||
.withStartTime(now.plusDays(52L).toEpochSecond(ZoneOffset.UTC))
|
.withStartTime(now.plusDays(52L).toInstant(ZoneOffset.UTC).toEpochMilli())
|
||||||
.withEndTime(now.plusDays(56L).toEpochSecond(ZoneOffset.UTC));
|
.withEndTime(now.plusDays(56L).toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
Thread updated3 = thread2.withAnnouncement(announcementDetails);
|
Thread updated3 = thread2.withAnnouncement(announcementDetails);
|
||||||
assertResponse(
|
assertResponse(
|
||||||
() -> patchThread(thread2.getId(), originalJson, updated3, USER_AUTH_HEADERS),
|
() -> patchThread(thread2.getId(), originalJson, updated3, USER_AUTH_HEADERS),
|
||||||
@ -1064,8 +1065,8 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
|
|||||||
ANNOUNCEMENT_OVERLAP);
|
ANNOUNCEMENT_OVERLAP);
|
||||||
|
|
||||||
announcementDetails
|
announcementDetails
|
||||||
.withStartTime(now.plusDays(53L).plusHours(2L).toEpochSecond(ZoneOffset.UTC))
|
.withStartTime(now.plusDays(53L).plusHours(2L).toInstant(ZoneOffset.UTC).toEpochMilli())
|
||||||
.withEndTime(now.plusDays(54L).toEpochSecond(ZoneOffset.UTC));
|
.withEndTime(now.plusDays(54L).toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
Thread updated4 = thread2.withAnnouncement(announcementDetails);
|
Thread updated4 = thread2.withAnnouncement(announcementDetails);
|
||||||
assertResponse(
|
assertResponse(
|
||||||
() -> patchThread(thread2.getId(), originalJson, updated4, USER_AUTH_HEADERS),
|
() -> patchThread(thread2.getId(), originalJson, updated4, USER_AUTH_HEADERS),
|
||||||
@ -1073,8 +1074,8 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
|
|||||||
ANNOUNCEMENT_OVERLAP);
|
ANNOUNCEMENT_OVERLAP);
|
||||||
|
|
||||||
announcementDetails
|
announcementDetails
|
||||||
.withStartTime(now.plusDays(52L).plusHours(12L).toEpochSecond(ZoneOffset.UTC))
|
.withStartTime(now.plusDays(52L).plusHours(12L).toInstant(ZoneOffset.UTC).toEpochMilli())
|
||||||
.withEndTime(now.plusDays(54L).toEpochSecond(ZoneOffset.UTC));
|
.withEndTime(now.plusDays(54L).toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
Thread updated5 = thread2.withAnnouncement(announcementDetails);
|
Thread updated5 = thread2.withAnnouncement(announcementDetails);
|
||||||
assertResponse(
|
assertResponse(
|
||||||
() -> patchThread(thread2.getId(), originalJson, updated5, USER_AUTH_HEADERS),
|
() -> patchThread(thread2.getId(), originalJson, updated5, USER_AUTH_HEADERS),
|
||||||
@ -1082,8 +1083,8 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
|
|||||||
ANNOUNCEMENT_OVERLAP);
|
ANNOUNCEMENT_OVERLAP);
|
||||||
|
|
||||||
announcementDetails
|
announcementDetails
|
||||||
.withStartTime(now.plusDays(54L).plusHours(12L).toEpochSecond(ZoneOffset.UTC))
|
.withStartTime(now.plusDays(54L).plusHours(12L).toInstant(ZoneOffset.UTC).toEpochMilli())
|
||||||
.withEndTime(now.plusDays(56L).toEpochSecond(ZoneOffset.UTC));
|
.withEndTime(now.plusDays(56L).toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
Thread updated6 = thread2.withAnnouncement(announcementDetails);
|
Thread updated6 = thread2.withAnnouncement(announcementDetails);
|
||||||
assertResponse(
|
assertResponse(
|
||||||
() -> patchThread(thread2.getId(), originalJson, updated6, USER_AUTH_HEADERS),
|
() -> patchThread(thread2.getId(), originalJson, updated6, USER_AUTH_HEADERS),
|
||||||
@ -1980,7 +1981,7 @@ public class FeedResourceTest extends OpenMetadataApplicationTest {
|
|||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
return new AnnouncementDetails()
|
return new AnnouncementDetails()
|
||||||
.withDescription(description)
|
.withDescription(description)
|
||||||
.withStartTime(now.plusDays(start).toEpochSecond(ZoneOffset.UTC))
|
.withStartTime(now.plusDays(start).toInstant(ZoneOffset.UTC).toEpochMilli())
|
||||||
.withEndTime(now.plusDays(end).toEpochSecond(ZoneOffset.UTC));
|
.withEndTime(now.plusDays(end).toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
findByTestId,
|
findByTestId,
|
||||||
findByText,
|
findByText,
|
||||||
fireEvent,
|
fireEvent,
|
||||||
|
getByTestId,
|
||||||
render,
|
render,
|
||||||
} from '@testing-library/react';
|
} from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -25,6 +26,10 @@ const mockCancel = jest.fn();
|
|||||||
|
|
||||||
const mockUpdate = jest.fn();
|
const mockUpdate = jest.fn();
|
||||||
|
|
||||||
|
jest.mock('../../../../utils/FeedUtils', () => ({
|
||||||
|
formatDateTime: jest.fn().mockReturnValue('Jan 1, 1970, 12:00 AM'),
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('../../../../utils/FeedUtils', () => ({
|
jest.mock('../../../../utils/FeedUtils', () => ({
|
||||||
getFrontEndFormat: jest.fn(),
|
getFrontEndFormat: jest.fn(),
|
||||||
MarkdownToHTMLConverter: {
|
MarkdownToHTMLConverter: {
|
||||||
@ -67,6 +72,26 @@ describe('Test FeedCardBody component', () => {
|
|||||||
expect(messagePreview).toBeInTheDocument();
|
expect(messagePreview).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Check if FeedCardBody render announcement data', async () => {
|
||||||
|
const { container } = render(
|
||||||
|
<FeedCardBody
|
||||||
|
{...mockFeedCardBodyProps}
|
||||||
|
announcementDetails={{
|
||||||
|
description: 'description',
|
||||||
|
startTime: 1717070243489,
|
||||||
|
endTime: 1717070248489,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
{
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const announcementData = getByTestId(container, 'announcement-data');
|
||||||
|
|
||||||
|
expect(announcementData).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('Should render editor if editpost is true', async () => {
|
it('Should render editor if editpost is true', async () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<FeedCardBody {...mockFeedCardBodyProps} isEditPost />,
|
<FeedCardBody {...mockFeedCardBodyProps} isEditPost />,
|
||||||
|
@ -16,7 +16,7 @@ import classNames from 'classnames';
|
|||||||
import { isUndefined } from 'lodash';
|
import { isUndefined } from 'lodash';
|
||||||
import React, { FC, useEffect, useMemo, useState } from 'react';
|
import React, { FC, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { formatDateTimeFromSeconds } from '../../../../utils/date-time/DateTimeUtils';
|
import { formatDateTime } from '../../../../utils/date-time/DateTimeUtils';
|
||||||
import {
|
import {
|
||||||
getFrontEndFormat,
|
getFrontEndFormat,
|
||||||
MarkdownToHTMLConverter,
|
MarkdownToHTMLConverter,
|
||||||
@ -104,12 +104,12 @@ const FeedCardBody: FC<FeedBodyProp> = ({
|
|||||||
<>
|
<>
|
||||||
<div className={classNames('feed-message', isEditPost ? '' : className)}>
|
<div className={classNames('feed-message', isEditPost ? '' : className)}>
|
||||||
{!isUndefined(announcementDetails) ? (
|
{!isUndefined(announcementDetails) ? (
|
||||||
<Space direction="vertical" size={4}>
|
<Space data-testid="announcement-data" direction="vertical" size={4}>
|
||||||
<Typography.Text className="feed-body-schedule text-xs text-grey-muted">
|
<Typography.Text className="feed-body-schedule text-xs text-grey-muted">
|
||||||
{t('label.schedule')}{' '}
|
{t('label.schedule')}{' '}
|
||||||
{formatDateTimeFromSeconds(announcementDetails.startTime)}{' '}
|
{formatDateTime(announcementDetails.startTime)}{' '}
|
||||||
{t('label.to-lowercase')}{' '}
|
{t('label.to-lowercase')}{' '}
|
||||||
{formatDateTimeFromSeconds(announcementDetails.endTime)}
|
{formatDateTime(announcementDetails.endTime)}{' '}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<Typography.Text className="font-medium">
|
<Typography.Text className="font-medium">
|
||||||
{postMessage}
|
{postMessage}
|
||||||
|
@ -192,9 +192,9 @@ const FeedCardBodyV1 = ({
|
|||||||
{showSchedule && (
|
{showSchedule && (
|
||||||
<Typography.Text className="feed-body-schedule text-xs text-grey-muted">
|
<Typography.Text className="feed-body-schedule text-xs text-grey-muted">
|
||||||
{t('label.schedule')}{' '}
|
{t('label.schedule')}{' '}
|
||||||
{formatDateTime(announcement.startTime * 1000)}{' '}
|
{formatDateTime(announcement.startTime)}{' '}
|
||||||
{t('label.to-lowercase')}{' '}
|
{t('label.to-lowercase')}{' '}
|
||||||
{formatDateTime(announcement.endTime * 1000)}
|
{formatDateTime(announcement.endTime)}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -64,8 +64,8 @@ const AddAnnouncementModal: FC<Props> = ({
|
|||||||
endTime,
|
endTime,
|
||||||
description,
|
description,
|
||||||
}: CreateAnnouncement) => {
|
}: CreateAnnouncement) => {
|
||||||
const startTimeMs = startTime.unix();
|
const startTimeMs = startTime.valueOf();
|
||||||
const endTimeMs = endTime.unix();
|
const endTimeMs = endTime.valueOf();
|
||||||
|
|
||||||
if (startTimeMs >= endTimeMs) {
|
if (startTimeMs >= endTimeMs) {
|
||||||
showErrorToast(t('message.announcement-invalid-start-time'));
|
showErrorToast(t('message.announcement-invalid-start-time'));
|
||||||
|
@ -86,8 +86,8 @@ const EditAnnouncementModal: FC<Props> = ({
|
|||||||
initialValues={{
|
initialValues={{
|
||||||
title: announcementTitle,
|
title: announcementTitle,
|
||||||
description: announcement.description,
|
description: announcement.description,
|
||||||
startTime: moment.unix(announcement.startTime),
|
startTime: moment(announcement.startTime),
|
||||||
endTime: moment.unix(announcement.endTime),
|
endTime: moment(announcement.endTime),
|
||||||
}}
|
}}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
validateMessages={VALIDATION_MESSAGES}
|
validateMessages={VALIDATION_MESSAGES}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import { isActiveAnnouncement } from './AnnouncementsUtils';
|
||||||
|
|
||||||
|
describe('Test isActiveAnnouncement utility', () => {
|
||||||
|
jest.useFakeTimers('modern').setSystemTime(new Date('2024-02-05'));
|
||||||
|
|
||||||
|
it('should return true for active announcement', () => {
|
||||||
|
const result = isActiveAnnouncement(
|
||||||
|
new Date('2024-02-03').getTime(),
|
||||||
|
new Date('2024-02-10').getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return false for inActive announcements', () => {
|
||||||
|
const result = isActiveAnnouncement(
|
||||||
|
new Date('2024-02-01').getTime(),
|
||||||
|
new Date('2024-02-04').getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
@ -35,8 +35,14 @@ export const ANNOUNCEMENT_ENTITIES = [
|
|||||||
EntityType.SEARCH_SERVICE,
|
EntityType.SEARCH_SERVICE,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
@param startTime: number -> Milliseconds
|
||||||
|
@param endTime: number -> Milliseconds
|
||||||
|
@returns boolean
|
||||||
|
|
||||||
|
*/
|
||||||
export const isActiveAnnouncement = (startTime: number, endTime: number) => {
|
export const isActiveAnnouncement = (startTime: number, endTime: number) => {
|
||||||
const currentTime = Date.now() / 1000;
|
const currentTime = Date.now();
|
||||||
|
|
||||||
return currentTime > startTime && currentTime < endTime;
|
return currentTime > startTime && currentTime < endTime;
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
customFormatDateTime,
|
customFormatDateTime,
|
||||||
formatDate,
|
formatDate,
|
||||||
formatDateTime,
|
formatDateTime,
|
||||||
formatDateTimeFromSeconds,
|
|
||||||
formatDateTimeLong,
|
formatDateTimeLong,
|
||||||
formatTimeDurationFromSeconds,
|
formatTimeDurationFromSeconds,
|
||||||
isValidDateFormat,
|
isValidDateFormat,
|
||||||
@ -47,10 +46,6 @@ describe('DateTimeUtils tests', () => {
|
|||||||
expect(formatDate(0)).toBe(`Jan 1, 1970`);
|
expect(formatDate(0)).toBe(`Jan 1, 1970`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`formatDateTimeFromSeconds should formate date and time both`, () => {
|
|
||||||
expect(formatDateTimeFromSeconds(0)).toBe(`Jan 1, 1970, 12:00 AM`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`formatDateShort should formate date and time both`, () => {
|
it(`formatDateShort should formate date and time both`, () => {
|
||||||
expect(formatDateTimeLong(0)).toBe(`Thu 1th January, 1970, 12:00 AM`);
|
expect(formatDateTimeLong(0)).toBe(`Thu 1th January, 1970, 12:00 AM`);
|
||||||
});
|
});
|
||||||
|
@ -27,18 +27,6 @@ export const formatDateTime = (date?: number) => {
|
|||||||
return dateTime.toLocaleString(DateTime.DATETIME_MED);
|
return dateTime.toLocaleString(DateTime.DATETIME_MED);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param date EPOCH seconds
|
|
||||||
* @returns Formatted date for valid input. Format: MMM DD, YYYY, HH:MM AM/PM
|
|
||||||
*/
|
|
||||||
export const formatDateTimeFromSeconds = (date?: number) => {
|
|
||||||
if (isNil(date)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return formatDateTime(date * 1000);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param date EPOCH millis
|
* @param date EPOCH millis
|
||||||
* @returns Formatted date for valid input. Format: MMM DD, YYYY
|
* @returns Formatted date for valid input. Format: MMM DD, YYYY
|
||||||
|
Loading…
x
Reference in New Issue
Block a user