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

feat(web): translation management variants preview #5202

Merged
merged 43 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
57c8204
feat(web): translation management variants preview
LetItRock Feb 16, 2024
dd4638e
Merge branch 'translation-management-beta' into nv-3416-variants-preview
LetItRock Feb 18, 2024
dc64174
chore(web): sms preview fix loading state
LetItRock Feb 18, 2024
7836d48
feat: initial setup
BiswaViraj Feb 15, 2024
312ab0b
feat: header icons
BiswaViraj Feb 15, 2024
1ae3357
feat: reusable in app preview
BiswaViraj Feb 17, 2024
41b180f
feat: add overaly props
BiswaViraj Feb 17, 2024
e7e3da7
fix: payload
BiswaViraj Feb 17, 2024
31c425b
feat: editor preview in-app
BiswaViraj Feb 17, 2024
56f1132
feat: removed translation banner
BiswaViraj Feb 17, 2024
6c0e067
refactor: typo
BiswaViraj Feb 17, 2024
8ba87a0
fix: test
BiswaViraj Feb 17, 2024
af17bfd
fix: test content
BiswaViraj Feb 17, 2024
8c47d0c
fix: tests by getting the latest processedvariables
BiswaViraj Feb 17, 2024
181b2fe
feat: update props type
BiswaViraj Feb 18, 2024
7cf0f57
feat: light theme fills
BiswaViraj Feb 18, 2024
251f71e
feat: ligh theme fixes
BiswaViraj Feb 18, 2024
93987c0
feat: merge from variants pr
ainouzgali Feb 18, 2024
60c1f34
Merge remote-tracking branch 'origin/nv-3416-variants-preview' into n…
ainouzgali Feb 18, 2024
bfecffd
feat: fix dependency use effect warning
ainouzgali Feb 18, 2024
4fefa3a
feat: adjust to the changes in the variant pr
ainouzgali Feb 18, 2024
d4d445c
fix: test
BiswaViraj Feb 19, 2024
663ab20
fix: test
BiswaViraj Feb 19, 2024
3a73435
fix: test
BiswaViraj Feb 19, 2024
483a5a1
feat: remove docker checks
BiswaViraj Feb 20, 2024
cf4c72d
refactor: add test id
BiswaViraj Feb 20, 2024
6175c21
fix: fix some issues found in translations
ainouzgali Feb 19, 2024
170da26
chore: update ref
BiswaViraj Feb 20, 2024
1a061b1
feat: implement cta and avatar
BiswaViraj Feb 20, 2024
6ebf979
feat: fix test
BiswaViraj Feb 20, 2024
14f83f7
chore: update hash
BiswaViraj Feb 20, 2024
a07dbfb
fix: update test id
BiswaViraj Feb 20, 2024
df6b8b5
fix: test
BiswaViraj Feb 20, 2024
9e0bcc5
refactor: remove unused imports
BiswaViraj Feb 20, 2024
51e4cc4
feat: add fallback lng
ainouzgali Feb 20, 2024
2448447
Merge pull request #5217 from novuhq/nv-3511-implement-avatar-and-cta…
BiswaViraj Feb 20, 2024
d18248d
Merge branch 'nv-2993-reusable-in-app-preview-component' into nv-3520…
ainouzgali Feb 20, 2024
cde09aa
feat: update source
ainouzgali Feb 20, 2024
c627999
Merge pull request #5222 from novuhq/nv-3520-use-default-locale-of-th…
ainouzgali Feb 20, 2024
f23e851
Merge pull request #5204 from novuhq/nv-2993-reusable-in-app-preview-…
ainouzgali Feb 20, 2024
866d324
fix: disable api call for chat while typing
ainouzgali Feb 25, 2024
8624d82
Merge remote-tracking branch 'origin/translation-management-beta' int…
ainouzgali Feb 25, 2024
ac0f957
Merge remote-tracking branch 'origin/translation-management-beta' int…
ainouzgali Feb 25, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ export class ContentTemplatesController {
throw new ApiException('Translation module is not loaded');
}
const service = this.moduleRef.get(require('@novu/ee-translation')?.TranslationsService, { strict: false });
const { namespaces, resources } = await service.getTranslationsList(environmentId, organizationId);
const { namespaces, resources, defaultLocale } = await service.getTranslationsList(
environmentId,
organizationId
);

await i18next.init({
resources,
Expand All @@ -153,6 +156,7 @@ export class ContentTemplatesController {
nsSeparator: '.',
lng: locale || 'en',
compatibilityJSON: 'v2',
fallbackLng: defaultLocale,
interpolation: {
formatSeparator: ',',
format: function (value, formatting, lng) {
Expand Down
18 changes: 9 additions & 9 deletions apps/web/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ Cypress.Commands.add('getBySelectorLike', (selector, ...args) => {
});

Cypress.Commands.add('waitLoadEnv', (beforeWait: () => void): void => {
cy.intercept('GET', 'http://127.0.0.1:1336/v1/environments').as('environments');
cy.intercept('GET', 'http://127.0.0.1:1336/v1/environments/me').as('environments-me');
cy.intercept('GET', '**/v1/environments').as('environments');
cy.intercept('GET', '**/v1/environments/me').as('environments-me');

beforeWait && beforeWait();

cy.wait(['@environments', '@environments-me']);
});

Cypress.Commands.add('waitLoadTemplatePage', (beforeWait: () => void): void => {
cy.intercept('GET', 'http://127.0.0.1:1336/v1/environments').as('environments');
cy.intercept('GET', 'http://127.0.0.1:1336/v1/organizations').as('organizations');
cy.intercept('GET', 'http://127.0.0.1:1336/v1/environments/me').as('environments-me');
cy.intercept('GET', 'http://127.0.0.1:1336/v1/notification-groups').as('notification-groups');
cy.intercept('GET', 'http://127.0.0.1:1336/v1/changes/count').as('changes-count');
cy.intercept('GET', 'http://127.0.0.1:1336/v1/integrations/active').as('active-integrations');
cy.intercept('GET', 'http://127.0.0.1:1336/v1/users/me').as('me');
cy.intercept('GET', '**/v1/environments').as('environments');
cy.intercept('GET', '**/v1/organizations').as('organizations');
cy.intercept('GET', '**/v1/environments/me').as('environments-me');
cy.intercept('GET', '**/v1/notification-groups').as('notification-groups');
cy.intercept('GET', '**/v1/changes/count').as('changes-count');
cy.intercept('GET', '**/v1/integrations/active').as('active-integrations');
cy.intercept('GET', '**/v1/users/me').as('me');
Comment on lines +26 to +32
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was failing to start the tests this way locally for me


beforeWait && beforeWait();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ describe('Creation functionality', function () {
.parent()
.click()
.find('textarea')
.type('<p>{{firstName}} someone assigned you to {{taskName}}', {
.type('<p>{{firstName}} someone assigned you to {{taskName}}</p>', {
parseSpecialCharSequences: false,
force: true,
});
cy.getByTestId('inAppRedirect').type('/example/test');
cy.getByTestId('editor-mode-switch').find('label').last().click();
cy.getByTestId('in-app-content-preview').contains('firstName someone assigned you to taskName');
cy.getByTestId('in-app-content-preview').contains('firstName someone assigned you to taskName', { timeout: 1000 });

goBack();
cy.getByTestId('notification-template-submit-btn').click();
Expand Down
13 changes: 8 additions & 5 deletions apps/web/cypress/tests/notification-editor/variants.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe('Workflow Editor - Variants', function () {
cy.getByTestId('add-new-condition').click();
cy.getByTestId('conditions-form-key').last().type('test');
cy.getByTestId('conditions-form-value').last().type('test');
cy.getByTestId('apply-conditions-btn').click();
cy.getByTestId('apply-conditions-btn').click({ force: true });
};

const checkTheVariantsList = (title: string, content: string) => {
Expand Down Expand Up @@ -350,7 +350,7 @@ describe('Workflow Editor - Variants', function () {
fillEditorContent(channel, true);
goBack();

cy.getByTestId('editor-sidebar-add-variant').should('be.visible').click();
cy.getByTestId('variant-sidebar-add-variant').should('be.visible').click();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extracted a separate sidebar for variants preview, and gave a different test ids

addConditions();
fillEditorContent(channel, true);
goBack();
Expand Down Expand Up @@ -592,11 +592,14 @@ describe('Workflow Editor - Variants', function () {
addConditions();
goBack();

cy.getByTestId('variants-list-sidebar').getByTestId('editor-sidebar-add-conditions').should('be.visible').click();
cy.getByTestId('variants-list-sidebar')
.getByTestId('variant-sidebar-add-conditions')
.should('be.visible')
.click();
addConditions();

cy.getByTestId('variants-list-sidebar')
.getByTestId('editor-sidebar-edit-conditions')
.getByTestId('variant-sidebar-edit-conditions')
.should('be.visible')
.contains('1');
});
Expand Down Expand Up @@ -838,7 +841,7 @@ describe('Workflow Editor - Variants', function () {
cy.reload();
cy.wait('@getWorkflow');

cy.getByTestId('editor-sidebar-delete').click();
cy.getByTestId('variant-sidebar-delete').click();

cy.get('.mantine-Modal-modal').contains('Delete step?');
cy.get('.mantine-Modal-modal button').contains('Delete step').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ describe('Translations Group Page', function () {

it('should upload translation file', function () {
createTranslationGroup();
cy.getByTestId('upload-menu').click();
cy.getByTestId('upload-files-dropdown-item').find('input').attachFile('translation.json');

cy.getByTestId('upload-files-container').find('input').attachFile('translation.json');
cy.getByTestId('upload-submit-btn').click();
cy.visit('/translations');
cy.getByTestId('test-group').click();
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function App() {
<Route path="providers" element={<ProvidersPage />} />
<Route path=":channel/:stepUuid" element={<ChannelStepEditor />} />
<Route path=":channel/:stepUuid/preview" element={<ChannelPreview />} />
<Route path=":channel/:stepUuid/variants" element={<VariantsPage />} />
<Route path=":channel/:stepUuid/variants/:variantUuid/preview" element={<VariantsPage />} />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the new preview variants route

<Route path=":channel/:stepUuid/variants/:variantUuid" element={<ChannelStepEditor />} />
<Route path=":channel/:stepUuid/variants/create" element={<VariantsPage />} />
</Route>
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/api/content-templates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IEmailBlock, MessageTemplateContentType } from '@novu/shared';
import { IEmailBlock, IMessageButton, IMessageCTA, MessageTemplateContentType } from '@novu/shared';
import { api } from './api.client';

export async function previewEmail({
Expand Down Expand Up @@ -26,7 +26,7 @@ export async function previewInApp({
locale,
}: {
content?: string;
cta: any;
cta?: IMessageCTA;
payload: string;
locale?: string;
}) {
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/api/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ export * from './useGetLocalesFromContent';
export * from './usePreviewEmail';
export * from './usePreviewSms';
export * from './usePreviewPush';
export * from './usePreviewChat';
export * from './usePreviewInApp';
2 changes: 1 addition & 1 deletion apps/web/src/api/hooks/useGetLocalesFromContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface ILocale {
}

type Payload = {
content: string | IEmailBlock[];
content?: string | IEmailBlock[];
};

export const useGetLocalesFromContent = () => {
Expand Down
45 changes: 45 additions & 0 deletions apps/web/src/api/hooks/usePreviewChat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useMutation, UseMutationOptions } from '@tanstack/react-query';
import { useCallback } from 'react';
import { errorMessage } from '@novu/design-system';
import type { IResponseError } from '@novu/shared';
import { IS_DOCKER_HOSTED } from '@novu/shared-web';

import { previewChat } from '../content-templates';

type PayloadType = {
content?: string;
payload: string;
locale?: string;
};

type ResultType = { content: string };

export const usePreviewChat = (options: UseMutationOptions<ResultType, IResponseError, PayloadType> = {}) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored a little the preview chat and extracted this to a separate hook

const { mutateAsync, isLoading } = useMutation<ResultType, IResponseError, PayloadType>(
({ content, payload, locale }) => previewChat({ content, payload, locale }),
{
onError: (e) => {
errorMessage(e.message || 'Unexpected error');
},
onSuccess: (result, variables, context) => {
options?.onSuccess?.(result, variables, context);
},
}
);

const getChatPreview = useCallback(
async ({ content, payload, locale }: PayloadType) => {
await mutateAsync({
content,
payload,
locale,
});
},
[mutateAsync]
);

return {
getChatPreview,
isLoading,
};
};
4 changes: 0 additions & 4 deletions apps/web/src/api/hooks/usePreviewEmail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ export const usePreviewEmail = (options: UseMutationOptions<ResultType, IRespons

const getEmailPreviewCallback = useCallback(
async ({ content, payload, contentType, layoutId, locale, subject }: PayloadType) => {
if (IS_DOCKER_HOSTED) {
return;
}

await mutateAsync({
content,
payload,
Expand Down
48 changes: 48 additions & 0 deletions apps/web/src/api/hooks/usePreviewInApp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { errorMessage } from '@novu/design-system';
import { IMessageButton, IMessageCTA } from '@novu/shared';
import { useMutation, UseMutationOptions } from '@tanstack/react-query';
import { useCallback } from 'react';
import { previewInApp } from '../content-templates';

type PayloadType = {
content?: string;
cta?: IMessageCTA;
payload: string;
locale?: string;
};

type ResultType = { content: string; ctaButtons: IMessageButton[] };

type ErrorType = { error: string; message: string; statusCode: number };

export const usePreviewInApp = (options: UseMutationOptions<ResultType, ErrorType, PayloadType> = {}) => {
const { mutateAsync, isLoading } = useMutation<ResultType, ErrorType, PayloadType>(
({ content, payload, locale, cta }) => previewInApp({ content, payload, locale, cta }),

{
onError: (e: any) => {
errorMessage(e.message || 'Unexpected error');
},
onSuccess: (result, variables, context) => {
options?.onSuccess?.(result, variables, context);
},
}
);

const getInAppPreviewCallback = useCallback(
async ({ content, payload, locale, cta }: PayloadType) => {
await mutateAsync({
content,
payload,
locale,
cta,
});
},
[mutateAsync]
);

return {
getInAppPreview: getInAppPreviewCallback,
isLoading,
};
};
8 changes: 2 additions & 6 deletions apps/web/src/api/hooks/usePreviewSms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,8 @@ export const usePreviewSms = (options: UseMutationOptions<ResultType, IResponseE
);

const getSmsPreview = useCallback(
({ content, payload, locale }: PayloadType) => {
if (IS_DOCKER_HOSTED) {
return;
}

return mutateAsync({
async ({ content, payload, locale }: PayloadType) => {
await mutateAsync({
content,
payload: JSON.parse(payload),
locale,
Expand Down
8 changes: 5 additions & 3 deletions apps/web/src/components/workflow/preview/chat/ChatContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import { NovuGreyIcon, PreviewEditOverlay } from '../common';
import { When } from '../../../utils/When';
import { useHover } from '../../../../hooks';

export function ChatContent({ isLoading, content, errorMsg }) {
export function ChatContent({ isLoading, content, errorMsg, showOverlay = true }) {
const { isHovered, onMouseEnter, onMouseLeave } = useHover();
const { colorScheme } = useMantineColorScheme();
const isDark = colorScheme === 'dark';

return (
<ContentAndOVerlayWrapperStyled onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
{isHovered && <PreviewEditOverlay />}
{isHovered && showOverlay && <PreviewEditOverlay />}
<Group
spacing={16}
align="flex-start"
noWrap
sx={{
position: 'relative',
...(isHovered && { filter: 'blur(2px)' }),
...(isHovered && showOverlay && { filter: 'blur(2px)' }),
}}
>
<When truthy={isLoading}>
Expand Down Expand Up @@ -76,4 +76,6 @@ const ContentAndOVerlayWrapperStyled = styled.div`
position: relative;
padding-top: 1.5rem;
padding-bottom: 1.25rem;
border-radius: 0.5rem;
overflow: hidden;
`;
Loading
Loading