Skip to content

Commit

Permalink
fix: Tolgee ui - add link to tolgee app TG-377
Browse files Browse the repository at this point in the history
  • Loading branch information
stepan662 committed Dec 15, 2021
1 parent 2266433 commit e45efdf
Show file tree
Hide file tree
Showing 13 changed files with 124 additions and 37 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
}
],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-empty-interface": "off"
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-namespace": "off"
}
}
41 changes: 41 additions & 0 deletions e2e/cypress/integration/next/ui.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,47 @@ context('UI Dialog', () => {
.click();
cy.contains('Quick translation');
cy.contains('Update');
cy.get('#_tolgee_platform_link')
.invoke('attr', 'href')
.should(
'contain',
'/projects/1/translations/single?key=sampleApp.hello_world!'
);
});

it('updates translation properly', () => {
visitWithApiKey([
'translations.view',
'keys.edit',
'translations.edit',
'screenshots.view',
'screenshots.upload',
'screenshots.delete',
]);
openUI();
cy.get('textarea').contains('Hello world!').click();
cy.focused().clear().type('Hello Czechia!');
cy.intercept({ path: '/v2/projects/keys/**', method: 'put' }, (req) => {
req.reply({
body: {
id: 1000000201,
name: 'sampleApp.hello_world!',
translations: {
en: {
id: 1000000301,
text: 'Hello Czechia!',
state: 'TRANSLATED',
},
de: { id: 1000000302, text: 'Hallo Welt!', state: 'TRANSLATED' },
},
tags: [],
screenshots: [],
},
});
}).as('updateTranslation');
cy.contains('Update').click();
cy.wait('@updateTranslation');
cy.get('span').contains('Hello Czechia!').should('be.visible');
});

it('make screenshot', () => {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/Properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const CURRENT_LANGUAGE_LOCAL_STORAGE_KEY = '__tolgee_currentLanguage';
export class Properties {
config: TolgeeConfig;
scopes?: Scope[];
projectId?: number;
_currentLanguage?: string;

get currentLanguage(): string {
Expand Down
14 changes: 12 additions & 2 deletions packages/core/src/Tolgee.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ describe('Tolgee', () => {
test('will set properties.scopes on run in development mode', async () => {
propertiesMock.mock.instances[0].config.mode = 'development';
await tolgee.run();
expect(coreServiceMock.mock.instances[0].getScopes).toBeCalledTimes(1);
expect(coreServiceMock.mock.instances[0].getApiKeyDetails).toBeCalledTimes(
1
);
expect(propertiesMock.mock.instances[0].scopes).toContain(
'translations.edit' as Scope
);
Expand All @@ -64,10 +66,18 @@ describe('Tolgee', () => {
);
});

test('will set properties.projectId on run in development mode', async () => {
propertiesMock.mock.instances[0].config.mode = 'development';
await tolgee.run();
expect(propertiesMock.mock.instances[0].projectId).toEqual(0);
});

test('will not set properties.scopes on run in production mode', async () => {
propertiesMock.mock.instances[0].config.mode = 'production';
await tolgee.run();
expect(coreServiceMock.mock.instances[0].getScopes).toBeCalledTimes(0);
expect(coreServiceMock.mock.instances[0].getApiKeyDetails).toBeCalledTimes(
0
);
expect(propertiesMock.mock.instances[0].scopes).toBeUndefined();
});

Expand Down
18 changes: 12 additions & 6 deletions packages/core/src/Tolgee.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { TolgeeConfig } from './TolgeeConfig';
import { InstantProps, TranslateProps, TranslationParams } from './types';
import {
InstantProps,
Scope,
TranslateProps,
TranslationParams,
} from './types';
import { NodeHelper } from './helpers/NodeHelper';
import { EventEmitterImpl } from './services/EventEmitter';
import { DependencyStore } from './services/DependencyStore';
Expand Down Expand Up @@ -80,7 +85,7 @@ export class Tolgee {

public async run(): Promise<void> {
if (this.properties.config.mode === 'development') {
await this.loadScopes();
await this.loadApiKeyDetails();
}

await this.translationService.loadTranslations();
Expand Down Expand Up @@ -133,7 +138,7 @@ export class Tolgee {
}

if (this.properties.config.mode === 'development' && !noWrap) {
await this.loadScopes();
await this.loadApiKeyDetails();
await this.translationService.loadTranslations();
return this.dependencyStore.textService.wrap(key, params, defaultValue);
}
Expand Down Expand Up @@ -195,10 +200,11 @@ export class Tolgee {
);
};

private async loadScopes() {
private async loadApiKeyDetails() {
if (this.properties.scopes === undefined) {
this.properties.scopes =
await this.dependencyStore.coreService.getScopes();
const details = await this.dependencyStore.coreService.getApiKeyDetails();
this.properties.scopes = details.scopes as Scope[];
this.properties.projectId = details.projectId;
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/__testFixtures/setupAfterEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ expect.extend({
};
},
} as any);

declare global {
namespace jest {
interface Matchers<R> {
toBeFoundIn(contextNode: Node): R;
}
}
}
7 changes: 3 additions & 4 deletions packages/core/src/services/CoreService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { ApiHttpService } from './ApiHttpService';
import { mocked } from 'ts-jest/utils';
import { Properties } from '../Properties';
import { Scope } from '../types';
import { ApiHttpError } from '../Errors/ApiHttpError';
import { DependencyStore } from './DependencyStore';

describe('CoreService', () => {
Expand Down Expand Up @@ -75,9 +74,9 @@ describe('CoreService', () => {

test('will switch to production mode on error', async () => {
mocked(mockedFetchJson).mockImplementation(async () => {
throw new ApiHttpError(new Response());
throw new Error();
});
await coreService.getScopes();
await coreService.getApiKeyDetails();
expect(getMockedInstance(Properties).config.mode).toEqual('production');
// eslint-disable-next-line no-console
expect(console.error).toBeCalledTimes(2);
Expand All @@ -88,7 +87,7 @@ describe('CoreService', () => {
scopes: ['translations.view', 'translations.edit'],
};
mocked(mockedFetchJson).mockImplementation(async () => mockedReturn);
expect(await coreService.getScopes()).toEqual(mockedReturn.scopes);
expect(await coreService.getApiKeyDetails()).toEqual(mockedReturn);
});
});

Expand Down
8 changes: 5 additions & 3 deletions packages/core/src/services/CoreService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { Properties } from '../Properties';
import { ApiHttpService } from './ApiHttpService';
import { Scope } from '../types';
import { LanguageModel, PagedModelLanguageModel } from '../types/DTOs';
import { components } from '../types/apiSchema.generated';

export type ApiKeyModel = components['schemas']['ApiKeyModel'];

export class CoreService {
private languagePromise: Promise<PagedModelLanguageModel>;
Expand Down Expand Up @@ -35,10 +38,9 @@ export class CoreService {
return languages._embedded.languages;
}

async getScopes() {
async getApiKeyDetails(): Promise<ApiKeyModel> {
try {
return (await this.apiHttpService.fetchJson(`v2/api-keys/current`))
.scopes;
return await this.apiHttpService.fetchJson(`v2/api-keys/current`);
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
Expand Down
7 changes: 5 additions & 2 deletions packages/core/src/services/__mocks__/CoreService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ const moduleMock = jest.genMockFromModule('../CoreService');

export const CoreService = classMock<Module.CoreService>(
() => ({
getScopes: jest.fn(async () => {
return ['translations.edit', 'keys.edit'] as Scope[];
getApiKeyDetails: jest.fn(async () => {
return {
scopes: ['translations.edit', 'keys.edit'] as Scope[],
projectId: 0,
} as Module.ApiKeyModel;
}),
}),
(moduleMock as typeof Module).CoreService
Expand Down
11 changes: 2 additions & 9 deletions packages/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,6 @@
"@testFixtures/*": ["./__testFixtures/*"]
}
},
"include": ["src", "typings"],
"exclude": [
"../../../node_modules",
"**/*.spec.ts",
"**/*.test.ts",
"**/__testFixtures/*",
"**/__mocks__/*",
"@testFixtures/*"
]
"include": ["src"],
"exclude": ["node_modules"]
}
9 changes: 0 additions & 9 deletions packages/core/typings/index.d.ts

This file was deleted.

27 changes: 26 additions & 1 deletion packages/ui/src/KeyDialog/KeyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ const ScContainer = styled('div')`
const ScHeading = styled('div')`
display: flex;
align-items: center;
gap: 5px;
`;

const ScHeadingTitle = styled('div')`
display: flex;
margin: 0px;
margin-right: 5px;
font-size: 19px;
`;

Expand Down Expand Up @@ -80,6 +80,31 @@ export const KeyForm = () => {
return (
<ScContainer {...{ [RESTRICTED_ASCENDANT_ATTRIBUTE]: 'true' }}>
<ScHeading>
<a
href={context.linkToPlatform}
target="_blank"
rel="noreferrer noopener"
id="_tolgee_platform_link"
>
<svg
width="100%"
height="100%"
viewBox="0 0 200 200"
xmlns="http://www.w3.org/2000/svg"
opacity="0.99"
fill="#822B55"
style={{
fillRule: 'evenodd',
clipRule: 'evenodd',
strokeLinejoin: 'round',
strokeMiterlimit: 2,
height: 23,
}}
>
<path d="M97.16,7.27a16.94,16.94,0,0,0-1.9,24.47,16.36,16.36,0,0,0,5,3.83,3.23,3.23,0,0,1-2.9,5.77,23.14,23.14,0,0,1-11.41-13C73.83,31.1,63.46,37.09,52.82,46.51c-27.44,24.3-34.35,61.74-16.38,85.26-4.57,5.79-8,12.22-8.9,18.69a20.88,20.88,0,0,0,5.62,18c9.18,9.61,21.42,7.13,31.26,5.14,6.58-1.34,12.8-2.6,16.5-.23,3.22,2.07,3.47,3.87,3.61,4.45,2.1,9.32-5.79,13.89-7.67,16.27a1.48,1.48,0,0,0,1.13,2.4c3.48,0,9-1.18,12.34-4.08s7.16-7.9,5.89-16.32c-.08-.5-.18-1-.32-1.58-.86-3.35-3.1-7.57-8.61-11.09-7.72-4.95-17-3.07-25.22-1.41-9.76,2-16,2.85-20.37-1.71a9.13,9.13,0,0,1-2.46-8.19c.54-3.77,2.65-7.89,5.62-11.86,21.71,16.89,56.87,13.47,82.67-9.39a75.34,75.34,0,0,0,20.81-28.09A23.14,23.14,0,0,1,134.8,89a3.23,3.23,0,0,1,6.08-2.19,16.37,16.37,0,0,0,3.2,5.39,16.85,16.85,0,1,0,11.48-28,3.23,3.23,0,0,1-.51-6.44,23.41,23.41,0,0,1,12.88,2.69c2.6-14.08,3.34-31.41-2.06-37.51-4.08-4.61-20.62-8-35.18-7.76A23.48,23.48,0,0,1,130.8,25a3.23,3.23,0,0,1-6.33-1.28A16.94,16.94,0,0,0,97.16,7.27Zm63.25,21a5.29,5.29,0,0,1-.57,6.19c-1.29,1.14-2.72-.51-4.1-2.06s-3.1-3.42-1.81-4.56A5.74,5.74,0,0,1,160.41,28.27Z"></path>
</svg>
</a>

<ScHeadingTitle>Quick translation</ScHeadingTitle>

{!context.useBrowserWindow && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export type DialogContextType = {
screenshotsUploading: boolean;
screenshots?: ScreenshotInterface[];
removeScreenshot: (id: number) => void;
linkToPlatform: string | undefined;
} & DialogProps;

export const TranslationDialogContext =
Expand All @@ -87,6 +88,11 @@ export const TranslationDialogContextProvider: FunctionComponent<DialogProps> =
useState(false);
const coreService = props.dependencies.coreService;
const properties = props.dependencies.properties;
const linkToPlatform =
properties.projectId !== undefined
? `${properties.config.apiUrl}/projects/${properties.projectId}/translations/single?key=${props.input}`
: undefined;

const translationService = props.dependencies.translationService;
const screenshotService = props.dependencies.screenshotService;
const [container, setContainer] = useState(
Expand Down Expand Up @@ -346,6 +352,7 @@ export const TranslationDialogContextProvider: FunctionComponent<DialogProps> =
screenshotsUploading,
screenshots,
removeScreenshot,
linkToPlatform,
};

return (
Expand Down

0 comments on commit e45efdf

Please sign in to comment.