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/new translation #1378

Open
wants to merge 75 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
a229242
Move old translations to new folder
magnurh-cx Nov 12, 2024
a179a71
Merge branch 'organize-api-hooks' into feat/new-translation
magnurh-cx Nov 13, 2024
d4df01c
backend service
magnurh-cx Nov 13, 2024
ed1004f
New global translations page
magnurh-cx Nov 13, 2024
b55d199
Populate and edit global translations
magnurh-cx Nov 18, 2024
8643c9d
Create new translation and update existing translation
magnurh-cx Nov 19, 2024
8379c9a
Use TextArea for longer inputs
magnurh-cx Nov 20, 2024
5a2fe8f
No support for editing Bokmål in first version
magnurh-cx Nov 20, 2024
66274a0
Fix keys - nb value for all tags except validering
magnurh-cx Nov 20, 2024
aad40e6
Sort translations
magnurh-cx Nov 20, 2024
8efb22d
Row for adding new translation
magnurh-cx Nov 21, 2024
b60cd00
Styling and refactoring
magnurh-cx Nov 21, 2024
fe3fd91
Move state management to reducer
magnurh-cx Nov 21, 2024
d302f06
Error handling and show error messages
magnurh-cx Nov 22, 2024
3cd47da
Open rows for editing on click + fix conflict error with new translation
magnurh-cx Nov 26, 2024
0141a6e
Load translations after saving and/or creating
magnurh-cx Nov 26, 2024
e3c48b0
Order items by newest first by default
magnurh-cx Nov 26, 2024
8ee21ef
prepare for reusing editTranslationsContext
magnurh-cx Nov 26, 2024
f0eb770
Decouple translationtable and global translations logic
magnurh-cx Nov 27, 2024
8837cd5
Generalize type
magnurh-cx Nov 27, 2024
14beab8
Form translations
magnurh-cx Nov 28, 2024
6700417
Show skeleton until values are loaded
magnurh-cx Dec 2, 2024
c12f418
Global translation override
magnurh-cx Dec 2, 2024
5503c24
Initialize and update global override
magnurh-cx Dec 4, 2024
7d3fa4b
Fix type errors
magnurh-cx Dec 5, 2024
640652f
Fix menu
magnurh-cx Dec 5, 2024
1978df6
fix test
magnurh-cx Dec 5, 2024
ae9bb71
Add simple cypress test
magnurh-cx Dec 6, 2024
403c5f3
More tests and destructure body on server for post
magnurh-cx Dec 10, 2024
08ee7f8
Move TranslationLang definition
magnurh-cx Dec 10, 2024
912ecab
Merge branch 'master' into feat/new-translation
magnurh-cx Dec 11, 2024
72c9b9c
Rename hooks
magnurh-cx Dec 11, 2024
5d7db6b
minor changes from feedback
magnurh-cx Dec 11, 2024
5fe8023
Re-organize routes
magnurh-cx Dec 11, 2024
9aca40a
Cypress tests
magnurh-cx Dec 12, 2024
d15ebc2
form translation cypress
magnurh-cx Dec 13, 2024
2d1f8e9
Error handling
magnurh-cx Dec 17, 2024
c3a0a2f
ensure loading state ends
magnurh-cx Dec 17, 2024
2045d49
Remove saveTranslations from FormTranslationsContext
magnurh-cx Dec 18, 2024
43b726b
Refactoring contexts
magnurh-cx Dec 19, 2024
8adafe4
Cypress fixes
magnurh-cx Dec 19, 2024
f9bf876
Clean up types
magnurh-cx Dec 19, 2024
7d8e3ae
Refactor bygger backend
magnurh-cx Dec 20, 2024
5e2220c
Split button columns
magnurh-cx Jan 2, 2025
a7d4231
Publish global translations
magnurh-cx Jan 3, 2025
aff50d3
fix content-type header check
magnurh-cx Jan 6, 2025
dc56a1b
Fix nn file name
magnurh-cx Jan 6, 2025
6473df3
Make sure that global translations is complete
magnurh-cx Jan 8, 2025
cb6cf53
Publish to github with dummy-tag
magnurh-cx Jan 9, 2025
b4bfd12
Use react-simple-wysiwig
magnurh-cx Jan 10, 2025
bbc68d6
Move wysiwyg to own component
magnurh-cx Jan 10, 2025
6fc7f07
Display rendered html
magnurh-cx Jan 10, 2025
32d59b1
Merge branch 'master' into feat/new-translation
magnurh-cx Jan 10, 2025
5179f7b
Merge branch 'master' into publish-forms-api-translations
magnurh-cx Jan 10, 2025
68d9c6f
Merge branch 'master' into feat/new-translation-html
magnurh-cx Jan 10, 2025
4361a04
Add custom link button
magnurh-cx Jan 13, 2025
025f403
Sanitize html and remove style attr
magnurh-cx Jan 13, 2025
476fbf5
Use DataCell instead of HeaderCell for html rows
magnurh-cx Jan 13, 2025
156770c
Close all rows if you save with no changes made
magnurh-cx Jan 13, 2025
8ccb9a5
Remove div choice
magnurh-cx Jan 13, 2025
d0d0092
Merge branch 'publish-forms-api-translations' into feat/new-translati…
magnurh-cx Jan 14, 2025
41c2978
Merge branch 'feat/new-translation' into feat/new-translation-html
magnurh-cx Jan 14, 2025
babb034
Merge branch 'feat/new-translation' into publish-forms-api-translations
magnurh-cx Jan 14, 2025
0756fbc
Export buttons
magnurh-cx Jan 14, 2025
7a33ef4
Validate input length and improve how validation errors are displayed
magnurh-cx Jan 16, 2025
119f271
Message and styling for error in wysiwyg
magnurh-cx Jan 16, 2025
b2fe09c
Endringer etter PR
magnurh-cx Jan 17, 2025
20b906c
Merge pull request #1396 from navikt/feat/new-translation-export
magnurh-cx Jan 17, 2025
5a6ac68
Update cypress
magnurh-cx Jan 17, 2025
d0b70fe
Default to p-tag for new inputs, similar to CKEditor
magnurh-cx Jan 17, 2025
f6eab6f
Merge remote-tracking branch 'origin/feat/new-translation-html' into …
magnurh-cx Jan 20, 2025
a0b6fea
Merge pull request #1393 from navikt/publish-forms-api-translations
magnurh-cx Jan 20, 2025
bba7974
Merge pull request #1394 from navikt/feat/new-translation-html
magnurh-cx Jan 20, 2025
453cd4f
Merge remote-tracking branch 'origin/feat/new-translation' into feat/…
magnurh-cx Jan 20, 2025
d40bf6a
Merge pull request #1402 from navikt/feat/new-translation-validate-le…
magnurh-cx Jan 20, 2025
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
@@ -0,0 +1,25 @@
import { Language } from '@navikt/skjemadigitalisering-shared-domain';
import express, { NextFunction, Request, Response } from 'express';
import config from '../../../config';
import { copyService } from '../../../services';

const formioGlobalTranslationsRouter = express.Router();

formioGlobalTranslationsRouter.put(
'/:language/copy-from-prod',
async (req: Request, res: Response, next: NextFunction) => {
if (config.naisClusterName === 'prod-gcp' || !copyService) {
return res.sendStatus(405);
}
try {
const { language } = req.params;
const formioToken = req.getFormioToken?.();
await copyService.globalTranslations(language as Language, formioToken);
return res.sendStatus(201);
} catch (error) {
next(error);
}
},
);

export default formioGlobalTranslationsRouter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { FormsApiFormTranslation } from '@navikt/skjemadigitalisering-shared-domain';
import { RequestHandler } from 'express';
import { HttpError as OldHttpError } from '../../../fetchUtils';
import { formTranslationsService } from '../../../services';
import { HttpError } from '../helpers/errors';

const get: RequestHandler = async (req, res, next) => {
const { formPath } = req.params;
try {
const translations = await formTranslationsService.get(formPath);
res.json(translations);
} catch (error) {
next(error);
}
};

const post: RequestHandler = async (req, res, next) => {
const { formPath } = req.params;
const accessToken = req.headers.AzureAccessToken as string;
const { key, nb, nn, en, globalTranslationId } = req.body as FormsApiFormTranslation;
const body = globalTranslationId ? { key, globalTranslationId } : { key, nb, nn, en };
try {
const translation = await formTranslationsService.post(formPath, body, accessToken);
res.status(201).json(translation);
} catch (error) {
if (error instanceof OldHttpError) {
next(new HttpError(error.message, error.response.status));
} else {
next(error);
}
}
};

const put: RequestHandler = async (req, res, next) => {
const { formPath, id } = req.params;
const { revision, nb, nn, en, globalTranslationId } = req.body as FormsApiFormTranslation;
const accessToken = req.headers.AzureAccessToken as string;
const body = globalTranslationId ? { globalTranslationId } : { nb, nn, en };
try {
const translation = await formTranslationsService.put(formPath, id, body, revision!, accessToken);
res.json(translation);
} catch (error) {
if (error instanceof OldHttpError) {
next(new HttpError(error.message, error.response.status));
} else {
next(error);
}
}
};

const formTranslations = {
get,
post,
put,
};
export default formTranslations;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Router } from 'express';
import formTranslations from './form-translations';

const formsApiFormTranslationsRouter = Router({ mergeParams: true });

formsApiFormTranslationsRouter.get('/', formTranslations.get);
formsApiFormTranslationsRouter.post('/', formTranslations.post);
formsApiFormTranslationsRouter.put('/:id', formTranslations.put);

export default formsApiFormTranslationsRouter;
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { FormsApiGlobalTranslation } from '@navikt/skjemadigitalisering-shared-domain';
import { RequestHandler } from 'express';
import { HttpError as OldHttpError } from '../../../fetchUtils';
import { globalTranslationsService } from '../../../services';
import { HttpError } from '../helpers/errors';

const get: RequestHandler = async (req, res, next) => {
try {
const translations = await globalTranslationsService.get();
res.json(translations);
} catch (error) {
next(error);
}
};

const post: RequestHandler = async (req, res, next) => {
const accessToken = req.headers.AzureAccessToken as string;
const { key, tag, nb, nn, en } = req.body as FormsApiGlobalTranslation;
const body = { key, tag, nb, nn, en };
try {
const translation = await globalTranslationsService.post(body, accessToken);
res.status(201).json(translation);
} catch (error) {
if (error instanceof OldHttpError) {
next(new HttpError(error.message, error.response.status));
} else {
next(error);
}
}
};

const put: RequestHandler = async (req, res, next) => {
const { id } = req.params;
const { revision, nb, nn, en } = req.body as FormsApiGlobalTranslation;
const accessToken = req.headers.AzureAccessToken as string;
const body = { nb, nn, en };
try {
const translation = await globalTranslationsService.put(id, body, revision!, accessToken);
res.json(translation);
} catch (error) {
if (error instanceof OldHttpError) {
next(new HttpError(error.message, error.response.status));
} else {
next(error);
}
}
};

const globalTranslations = {
get,
post,
put,
};
export default globalTranslations;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Router } from 'express';
import globalTranslations from './global-translations';

const formsApiGlobalTranslationsRouter = Router();

formsApiGlobalTranslationsRouter.get('/', globalTranslations.get);
formsApiGlobalTranslationsRouter.post('/', globalTranslations.post);
formsApiGlobalTranslationsRouter.put('/:id', globalTranslations.put);

export default formsApiGlobalTranslationsRouter;
5 changes: 4 additions & 1 deletion packages/bygger-backend/src/routers/api/forms/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import express from 'express';
import authorizedPublisher from '../helpers/authorizedPublisher';
import formsApiFormTranslationsRouter from '../forms-api-form-translations';
import authHandlers from '../helpers/authHandlers';
import form from './form';
import forms from './forms';

const formsRouter = express.Router();
const { authorizedPublisher, formsApiAuthHandler } = authHandlers;

formsRouter.get('/', forms.get);
formsRouter.get('/:formPath', form.get);
formsRouter.put('/:formPath', authorizedPublisher, form.put);
formsRouter.put('/:formPath/overwrite-with-prod', authorizedPublisher, form.copyFromProd);
formsRouter.put('/:formPath/form-settings', authorizedPublisher, form.putFormSettings);
formsRouter.use('/:formPath/translations', formsApiAuthHandler, formsApiFormTranslationsRouter);

export default formsRouter;

This file was deleted.

6 changes: 4 additions & 2 deletions packages/bygger-backend/src/routers/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import deprecatedPublishForm from './deprecated-publish-form';
import deprecatedUnpublishForm from './deprecated-unpublish-form';
import enhetsliste from './enhetsliste';
import formDiff from './formDiff';
import formioGlobalTranslationsRouter from './formio-global-translations';
import formsRouter from './forms';
import globalTranslationsRouter from './global-translations';
import formsApiGlobalTranslationsRouter from './forms-api-global-translations';
import apiErrorHandler from './helpers/apiErrorHandler';
import authHandlers from './helpers/authHandlers';
import importRouter from './import';
Expand Down Expand Up @@ -45,8 +46,9 @@ apiRouter.post('/migrate/update', authorizedPublisher, migrateUpdate);
apiRouter.get('/form/:formPath/diff', formDiff);
apiRouter.use('/forms', formsRouter);
apiRouter.use('/recipients', formsApiAuthHandler, recipientsRouter);
apiRouter.use('/translations', formsApiAuthHandler, formsApiGlobalTranslationsRouter);
apiRouter.use('/import', importRouter);
apiRouter.use('/global-translations', authorizedPublisher, globalTranslationsRouter);
apiRouter.use('/global-translations', authorizedPublisher, formioGlobalTranslationsRouter);
magnurh-cx marked this conversation as resolved.
Show resolved Hide resolved
apiRouter.post('/log/:level', rateLimiter(60000, 60), log);

apiRouter.use(apiErrorHandler);
Expand Down
2 changes: 1 addition & 1 deletion packages/bygger-backend/src/services/RecipientService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Recipient } from '@navikt/skjemadigitalisering-shared-domain';
import { fetchWithErrorHandling } from '../fetchUtils';

export class RecipientService {
export default class RecipientService {
readonly formsApiUrl: string;
readonly recipientsUrl: string;

Expand Down
10 changes: 9 additions & 1 deletion packages/bygger-backend/src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { createCopyService } from './copy/CopyService';
import { FormioService } from './formioService';
import PublisherService from './PublisherService';
import PusherService from './PusherService';
import { RecipientService } from './RecipientService';
import RecipientService from './RecipientService';
import ReportService from './ReportService';
import createFormTranslationsService from './translation/FormTranslationService';
import createGlobalTranslationService from './translation/GlobalTranslationsService';

const formioApiServiceUrl = getFormioApiServiceUrl();
const prodFormioApiServiceUrl = getFormioApiProdServiceUrl();
Expand All @@ -23,6 +25,10 @@ const reportService = new ReportService(formioService);

const pusherService = new PusherService();

const formTranslationsService = createFormTranslationsService(config.formsApi.url);

const globalTranslationsService = createGlobalTranslationService(config.formsApi.url);

const copyService = prodFormioApiServiceUrl
? createCopyService(new FormioService(prodFormioApiServiceUrl), formioService)
: null;
Expand All @@ -31,6 +37,8 @@ export {
backendInstance,
copyService,
formioService,
formTranslationsService,
globalTranslationsService,
publisherService,
pusherService,
recipientService,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { FormsApiFormTranslation } from '@navikt/skjemadigitalisering-shared-domain';
import { fetchWithErrorHandling } from '../../fetchUtils';
import { FormTranslationPostBody, FormTranslationPutBody, FormTranslationService } from './types';
import { createHeaders } from './utils';

const createFormTranslationsService = (formsApiUrl: string): FormTranslationService => {
const formsApiTranslationsUrl = `${formsApiUrl}/v1/forms`;
const translationsPath = 'translations';

return {
get: async (formPath: string): Promise<FormsApiFormTranslation[]> => {
const response = await fetchWithErrorHandling(`${formsApiTranslationsUrl}/${formPath}/${translationsPath}`, {
headers: createHeaders(),
});
return response.data as FormsApiFormTranslation[];
},
post: async (
formPath: string,
translation: FormTranslationPostBody,
accessToken: string,
): Promise<FormsApiFormTranslation> => {
const response = await fetchWithErrorHandling(`${formsApiTranslationsUrl}/${formPath}/${translationsPath}`, {
method: 'POST',
headers: createHeaders(accessToken),
body: JSON.stringify(translation),
});
return response.data as FormsApiFormTranslation;
},

put: async (
formPath: string,
id: string,
body: FormTranslationPutBody,
revision: number,
accessToken: string,
): Promise<FormsApiFormTranslation> => {
const response = await fetchWithErrorHandling(
`${formsApiTranslationsUrl}/${formPath}/${translationsPath}/${id}`,
{
method: 'PUT',
headers: createHeaders(accessToken, revision),
body: JSON.stringify(body),
},
);
return response.data as FormsApiFormTranslation;
},
};
};

export default createFormTranslationsService;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { FormsApiGlobalTranslation } from '@navikt/skjemadigitalisering-shared-domain';
import { fetchWithErrorHandling } from '../../fetchUtils';
import { GlobalTranslationPostBody, GlobalTranslationPutBody, GlobalTranslationService } from './types';
import { createHeaders } from './utils';

const createGlobalTranslationService = (formsApiUrl: string): GlobalTranslationService => {
const globalTranslationsPath: string = '/v1/global-translations';

return {
get: async (): Promise<FormsApiGlobalTranslation[]> => {
const response = await fetchWithErrorHandling(`${formsApiUrl}${globalTranslationsPath}`, {
headers: createHeaders(),
});
return response.data as FormsApiGlobalTranslation[];
},
post: async (body: GlobalTranslationPostBody, accessToken?: string): Promise<FormsApiGlobalTranslation> => {
const response = await fetchWithErrorHandling(`${formsApiUrl}${globalTranslationsPath}`, {
method: 'POST',
headers: createHeaders(accessToken),
body: JSON.stringify(body),
});
return response.data as FormsApiGlobalTranslation;
},
put: async (
id: string,
body: GlobalTranslationPutBody,
revision: number,
accessToken: string,
): Promise<FormsApiGlobalTranslation> => {
const response = await fetchWithErrorHandling(`${formsApiUrl}${globalTranslationsPath}/${id}`, {
method: 'PUT',
headers: createHeaders(accessToken, revision),
body: JSON.stringify(body),
});
return response.data as FormsApiGlobalTranslation;
},
};
};

export default createGlobalTranslationService;
38 changes: 38 additions & 0 deletions packages/bygger-backend/src/services/translation/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { FormsApiFormTranslation, FormsApiGlobalTranslation } from '@navikt/skjemadigitalisering-shared-domain';

type FormTranslationPostBody = Pick<FormsApiFormTranslation, 'key' | 'nb' | 'nn' | 'en' | 'globalTranslationId'>;
type FormTranslationPutBody = Pick<FormsApiFormTranslation, 'nb' | 'nn' | 'en' | 'globalTranslationId'>;
type GlobalTranslationPostBody = Pick<FormsApiGlobalTranslation, 'key' | 'tag' | 'nb' | 'nn' | 'en'>;
type GlobalTranslationPutBody = Pick<FormsApiGlobalTranslation, 'nb' | 'nn' | 'en'>;

type FormTranslationService = {
get: (formPath: string) => Promise<FormsApiFormTranslation[]>;
post: (formPath: string, body: FormTranslationPostBody, accessToken: string) => Promise<FormsApiFormTranslation>;
put: (
formPath: string,
id: string,
body: FormTranslationPutBody,
revision: number,
accessToken: string,
) => Promise<FormsApiFormTranslation>;
};

type GlobalTranslationService = {
get: () => Promise<FormsApiGlobalTranslation[]>;
post: (body: GlobalTranslationPostBody, accessToken: string) => Promise<FormsApiGlobalTranslation>;
put: (
id: string,
body: GlobalTranslationPutBody,
revision: number,
accessToken: string,
) => Promise<FormsApiGlobalTranslation>;
};

export type {
FormTranslationPostBody,
FormTranslationPutBody,
FormTranslationService,
GlobalTranslationPostBody,
GlobalTranslationPutBody,
GlobalTranslationService,
};
Loading
Loading