Commit 9600a194 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov

moved user module to express, core folder unwrapped, moved i18n to separate module

parent 8286bc05
......@@ -20,6 +20,7 @@
"workspaces": [
"packages/ui-core",
"packages/ui-express",
"packages/i18n",
"packages/electron"
],
"devDependencies": {
......
{
"action": {
"submit": null
},
"label": {
"loadingData": "Loading data..."
}
}
{
"user": {
"public": {
"form": {
"login": {
"label": {
"password": null,
"username": null
}
}
}
}
}
}
{
"name": "@grin-global/i18n",
"version": "0.0.1",
"license": "Apache-2.0",
"scripts": {
"precompile": "yarn run i18n:generateI18n",
"i18n:generateI18n": "node src/generateI18n.ts",
"i18n:scanI18nDuplicates": "ts-node src/duplicateDetector.ts",
"i18n:i18nscan": "i18next-scanner --config i18next-scanner.config.js '../**/src/**/*.tsx'"
},
"dependencies": {
"@grin-global/ui-core": "file:../ui-core",
"axios": "^0.19.2",
"i18next": "^19.0.3",
"i18next-browser-languagedetector": "^4.0.1",
"i18next-express-middleware": "^1.9.1",
"i18next-sync-fs-backend": "^1.1.1",
"i18next-xhr-backend": "^3.2.2"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.4",
"@types/enzyme": "^3.10.5",
"@types/jest": "^25.1.2",
"@types/react": "16.9.19",
"@types/react-router": "5.1.4",
"@types/react-router-dom": "5.1.3",
"@types/redux-form": "8.2.0",
"@types/webpack-env": "^1.15.1",
"@typescript-eslint/eslint-plugin": "^2.17.0",
"@typescript-eslint/eslint-plugin-tslint": "^2.17.0",
"@typescript-eslint/parser": "^2.18.0",
"awesome-typescript-loader": "^5.2.1",
"babel-eslint": "^10.0.3",
"babel-plugin-module-resolver": "^4.0.0",
"babel-plugin-react-transform": "^3.0.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"babel-preset-typescript": "^7.0.0-alpha.19",
"eslint": "^6.8.0",
"eslint-config-airbnb": "^18.0.1",
"eslint-config-prettier": "^6.10.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.0",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prefer-arrow": "^1.1.7",
"eslint-plugin-react": "^7.18.0",
"file-system": "^2.2.2",
"i18next-scanner": "^2.10.3",
"lerna": "^3.20.2",
"rimraf": "^3.0.1",
"ts-node": "^8.6.2",
"tslint": "^6.0.0",
"tslint-loader": "^3.5.4",
"tslint-react": "^4.2.0",
"typescript": "^3.7.5"
}
}
import languages from '@/core/data/Languages';
import languages from '@grin-global/i18n/data/Languages';
export default function detectLocaleFromPath(virtualPath: string, path: string, index: number) {
if (virtualPath && path.startsWith(virtualPath)) {
......
......@@ -25,7 +25,7 @@ const duplicates = new Map<string, II18n[]>();
async function main() {
console.log('Running...');
const dupes = fastGlob(['./locales/en/common.json', './src/**/translations.json', './src/translations.json'])
const dupes = fastGlob(['./locales/en/common.json', '../../**/src/**/translations.json', '../../**/src/translations.json'])
.then((paths) => paths.map((path) => testFile(path)));
console.log('Awawiting results...', dupes);
......
......@@ -6,8 +6,8 @@ const mkdirp = require('mkdirp');
const rimraf = require('rimraf');
const getPrefix = (path) => path.substring(path.indexOf('./src/') + './src/'.length, path.indexOf('/translations.json'));
fg(['./src/**/translations.json', './src/translations.json'])
// TODO fix generated paths
fg(['../../**/src/**/translations.json', '../../**/src/translations.json'])
.then((entries) => entries.sort((a, b) => getPrefix(a).localeCompare(getPrefix(b))))
.then((entries) => {
let result = {};
......
......@@ -2,9 +2,9 @@
import i18n from 'i18next';
import axios from 'axios';
// eslint-disable-next-line no-restricted-imports
import optionsBase from '@/i18n/options-base';
import optionsBase from '@grin-global/i18n/options-base';
// eslint-disable-next-line no-restricted-imports
import langDetector from '@/i18n/langDetector';
import langDetector from '@grin-global/i18n/langDetector';
import XHR from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
......
// @ts-ignore
import i18n from 'i18next';
import * as path from 'path';
import optionsBase from '@/i18n/options-base';
import optionsBase from '@grin-global/i18n/options-base';
import Backend from 'i18next-sync-fs-backend';
import { initReactI18next } from 'react-i18next';
......
import detectLocaleFromPath from '@/i18n/detectLocaleFromPath';
import detectLocaleFromPath from '@grin-global/i18n/detectLocaleFromPath';
export default {
name: 'catalogLangDetector',
......
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": [
"*",
"src/*",
"server/*",
"node_modules/*"
],
"@grin-global/ui-core/*": [
"../ui-core/*",
"../ui-core/src/*"
],
"@grin-global/i18n/*": [
"../i18n/src/*"
]
},
"outDir": "../../target",
"module": "esnext",
"target": "esnext",
"sourceMap": false,
"inlineSourceMap": true,
"experimentalDecorators": false,
"noUnusedParameters": false,
"noUnusedLocals": true,
"jsx": "react",
"moduleResolution": "node",
"importHelpers": true,
"types": [
"node",
"webpack-env"
]
},
"exclude": [
"node_modules",
"build",
"typings/main",
"typings/main.d.ts"
]
}
{
"action": {
"OK": "OK",
"acceptAndPublish": "ACCEPT AND PUBLISH",
"add": "Add {{what, lowercase}}",
"applyFilters": "Apply filters",
"approve": "Approve",
"back": "Back",
"backTo": "Back to {{where, lowercase}}",
"backToDashboard": "Back to dashboard",
"backToList": "Back to list",
"cancel": "Cancel",
"clear": "Clear",
"close": "Close",
"collapse": "Collapse",
"confirm": "Confirm",
"copiedToClipboard": "Copied to clipboard",
"copyToClipboard": "Copy to clipboard",
"create": "Create",
"createNewVersion": "Create new version",
"delete": "Delete",
"deleteData": "Delete data",
"download": "Download",
"edit": "Edit",
"login": "Login",
"logout": "Logout",
"manage": "Manage",
"nextStep": "Next step",
"openSidebar": "Open sidebar",
"publish": "Publish",
"read": "Read",
"reject": "Reject",
"remove": "Remove {{what}}",
"reset": "Reset",
"return": "Return",
"save": "Save",
"saveChanges": "Save changes",
"search": "Search",
"sendToReview": "Send to review",
"show": "Show",
"un-publish": "Un-publish",
"unpublish": "Unpublish",
"view": "View",
"viewDetails": "View details",
"write": "Write"
},
"csv": {
"autoDetect": "Auto-detect ",
"autoDetectLabel": "Auto-detect CSV settings",
"comma": "Comma",
"configuration": "CSV configuration",
"escapeCharacter": "Escape character",
"other": "Other",
"quoteCharacter": "Quote character",
"semicolon": "Semicolon",
"separator": "Separator character",
"space": "Space",
"tab": "Tab",
"typeYourEscapeCharacter": "Type your escape character",
"typeYourQuoteCharacter": "Type your quote character",
"typeYourSeparator": "Type your separator"
},
"f": {
"NOTNULL": "Either",
"NULL": "Not provided",
"createdDate": "Created on",
"dataExists": "Data exists",
"dataNotProvided": "Data not provided",
"dateSearch": "Date search",
"dontCare": "Don't use filter",
"fromIncluding": "At least (min)",
"keyword": "Keyword search",
"lastModifiedDate": "Last modified",
"lastReminderDate": "Last reminder",
"noFilters": "No available filters",
"suggestedFilters": "Suggested filters",
"textSearch": "Text search",
"toIncluding": "At most (max)"
},
"fileUploader": {
"chooseFiles": "Choose files to upload",
"dragFiles": "Drag files here \n or",
"release": "Release to upload"
},
"label": {
"UUID": "UUID",
"allRightsReserved": "All rights reserved",
"andMore": "And {{otherMore, number}} more",
"availableToRegistered": "Available to registered users only",
"basicMarkdown": "Basic markdown supported",
"created": "Created",
"createdBy": "Created by {{who}}",
"createdDate": "Created date",
"dateNotProvided": "Date not provided",
"deleteDescription": "Deleting this will remove all related data.",
"description": "Description",
"editMarkdown": "Edit Markdown",
"either": "Either",
"enabled": "Enabled",
"errorHappen": "Error happened while processing request",
"false": "False",
"filters": "Filters",
"from": "From",
"fullMarkdown": "Full markdown supported",
"here": "here",
"item": "Item",
"item_plural": "Items",
"itemEditorWarn": "Don't use the ItemsEditor for more than 100 items!",
"lastModified": "Last modified",
"lastUpdated": "Last updated",
"lastUpdatedBy": "Last updated by {{who}}",
"list": "List",
"list_plural": "Lists",
"loading": "Loading {{what}}",
"loadingData": "Loading data...",
"missing": "Not specified",
"modified": "Modified",
"name": "Name",
"newVersionAvailable": "New version available",
"no": "No",
"noChanges": "No changes yet",
"noValue": "No value",
"nothingMatchesYourRequest": "Nothing matches your request",
"notApplicable": "N/A",
"notSpecified": "Not specified",
"other": "Other",
"prettyNumber": "{{value, number}}",
"previewMarkdown": "Preview markdown",
"registered": "Registered",
"saved": "Saved",
"sortBy": "Sort By",
"status": "Status",
"stepsForDataPublication": "Steps for data publication completion",
"title": "Title",
"to": "To",
"true": "True",
"untitled": "Untitled",
"useDefault": "Use default",
"version": "Version {{version, number}}",
"yes": "Yes",
"warning": "Warning"
},
"paginate": {
"numberOfItems": "{{count, number}} {{what, lowercase}}",
"estimatedNumberOfItems": "About {{count, number}} {{what, lowercase}}"
},
"permissions": {
"class": "Class",
"inheritedPermissions": "Permissions inherited from parent ACL object",
"inheritsPermissions": "Inherits permissions",
"label": "Permissions",
"managePermissions": "Manage permissions",
"objectID": "Object ID",
"objectIdentityId": "ACL OID ID",
"owner": "Owner",
"parentObjectIdentityId": "Parent OID ID",
"sid": "Sid",
"updateParentOID": "Update Parent OID ID"
},
"sort": {
"name": "Name",
"title": "Title",
"owner": "Owner",
"version": "Version",
"latestEdit": "Recently modified"
}
}
{
"core": {},
"user": {}
}
\ No newline at end of file
......@@ -4,10 +4,6 @@
"license": "Apache-2.0",
"scripts": {
"clean": "rimraf target",
"precompile": "yarn run clean && yarn run i18n:generateI18n",
"i18n:generateI18n": "node src/i18n/generateI18n.ts",
"i18n:scanI18nDuplicates": "ts-node src/i18n/duplicateDetector.ts",
"i18n:i18nscan": "i18next-scanner --config i18next-scanner.config.js 'src/**/*.tsx'",
"test": "jest"
},
"dependencies": {
......
import { CONFIGURE_APPLICATION, SET_LANG } from '@/core/constants/applicationConfig';
import { CONFIGURE_APPLICATION, SET_LANG } from '@grin-global/ui-core/constants/applicationConfig';
export const configure = (config: object) => ({
......
import * as cookies from 'es-cookie';
import * as jwt from 'jsonwebtoken';
import { call, put, select, takeEvery } from 'redux-saga/effects';
// actions
import { loginUserSuccess } from '@/user/action/public';
// action
import navigateTo from '@grin-global/ui-core/action/navigation';
// constants
import { LOGIN_APP, LOGIN_APP_SAGA } from '@/core/constants/login';
import { ROLE_CLIENT } from '@/core/constants/userRoles';
import {
LOGIN_APP, LOGIN_USER,
LOGIN_APP_SAGA, LOGIN_USER_SAGA, LOGOUT_USER_SAGA,
} from '@grin-global/ui-core/constants/login';
import { ROLE_CLIENT } from '@grin-global/ui-core/constants/userRoles';
// service
import { LoginService } from '@/core/service/LoginService';
import { LoginService } from '@grin-global/ui-core/service/LoginService';
// utilities
import { clearCookies, saveCookies } from '@/core/utilities';
import { log } from '@/core/utilities/debug';
import { configureBackendApi } from '@/core/utilities/requestUtils';
import { clearCookies, saveCookies } from '@grin-global/ui-core/utilities';
import { log } from '@grin-global/ui-core/utilities/debug';
import { configureBackendApi } from '@grin-global/ui-core/utilities/requestUtils';
export const loginSagas = [
takeEvery(LOGIN_APP_SAGA, loginAppSaga),
takeEvery(LOGIN_USER_SAGA, loginUserSaga),
takeEvery(LOGOUT_USER_SAGA, logoutUserSaga),
];
// #loginUser
export const loginUserAction = (username, password, needRedirect = false) => ({
type: LOGIN_USER_SAGA,
payload: {
username,
password,
needRedirect,
},
});
function* loginUserSaga(action) {
const { username, password, needRedirect } = action.payload;
// log('Trying login', username);
try {
yield call(loginRequest, username, password);
if (needRedirect) {
yield call(navigateTo, '/');
}
window.location.reload();
return false;
} catch (e) {
return ({ error: e, errorDescription: e.message });
}
}
function* loginRequest(username, password) {
const userData = yield call(LoginService.login, username, password);
const apiUrl = yield select((state) => state.applicationConfig.apiUrl);
const tokenData = jwt.decode(userData.access_token);
saveCookies(
{ access_token: userData.access_token, ...userData, ...tokenData },
userData.exp * 1000 || new Date().getTime() + userData.expires_in * 1000,
apiUrl,
);
return put(loginUserSuccess({ ...userData, ...tokenData }));
}
export const loginUserSuccess = (payload) => ({
type: LOGIN_USER,
...payload,
});
// #logoutUser
export const logoutUserAction = () => ({
type: LOGOUT_USER_SAGA,
});
function* logoutUserSaga() {
const token = yield select((state) => state.login.access_token);
yield call(LoginService.logout, token);
clearCookies();
const appTokenData = yield call(loginAppAction);
const apiUrl = yield select((state) => state.applicationConfig.apiUrl);
saveCookies(appTokenData, appTokenData.exp * 1000 || new Date().getTime() + appTokenData.expires_in * 1000, apiUrl);
window.location.replace('/');
}
export function checkAccessTokens(dispatch, getState) {
const cookieToken: string = typeof window !== 'undefined' && cookies.get('access_token');
......
import { all, takeEvery } from 'redux-saga/effects';
import { userPublicSagas } from '@/user/action/public';
import { loginSagas } from '@/core/action/login';
import { takeEvery } from 'redux-saga/effects';
import { loginSagas } from '@grin-global/ui-core/action/login';
export default function*() {
yield all([
process.env.NODE_ENV === 'development' ? takeEvery((action) => /^api\//.test(action.type), logApi) : {},
...loginSagas,
...userPublicSagas,
]);
}
export const coreSagas = [
process.env.NODE_ENV === 'development' ? takeEvery((action) => /^api\//.test(action.type), logApi) : {},
...loginSagas,
];
function* logApi(action) {
console.log('Api call to ', action.type);
......
export const LOGIN_USER = 'LOGIN_USER';
export const LOGIN_APP = 'LOGIN_APP';
export const LOGIN_APP_SAGA = 'saga/login/LOGIN_APP';
export const CHECK_TOKEN = 'CHECK_TOKEN';
export const VERIFY_GOOGLE_TOKEN = 'VERIFY_GOOGLE_TOKEN';
// saga
export const LOGIN_USER_SAGA = 'saga/login/LOGIN_USER';
export const LOGOUT_USER_SAGA = 'saga/login/LOGOUT_USER_SAGA';
export const LOGIN_APP_SAGA = 'saga/login/LOGIN_APP';
// form
export const USER_LOGIN_FORM = 'Form/Login/USER_LOGIN_FORM';
export const REGISTRATION_FORM = 'Form/Login/REGISTRATION_FORM';
export const FORGOT_PASSWORD_FORM = 'Form/user/FORGOT_PASSWORD';
export const RESET_PASSWORD_FORM = 'Form/user/RESET_PASSWORD';
......
export { default as ApiError } from '@/core/model/common/ApiError';
export { default as EmptyModel } from '@/core/model/common/EmptyModel';
export { default as BasicModel } from '@/core/model/common/BasicModel';
export { default as IVersionedEntity } from '@/core/model/common/IVersionedEntity';
export { default as VersionedModel } from '@/core/model/common/VersionedModel';
export { default as AuditedVersionedModel } from '@/core/model/common/AuditedVersionedModel';
export { default as UuidModel } from '@/core/model/common/UuidModel';
import AclSid from '@/core/model/acl/AclSid';
import AclSid from '@grin-global/ui-core/model/acl/AclSid';
/*
* Defined in Swagger as '#/definitions/AclEntry'
......
import AclClass from '@/core/model/acl/AclClass';
import AclSid from '@/core/model/acl/AclSid';
import SidPermissions from '@/core/model/acl/SidPermissions';
import AclClass from '@grin-global/ui-core/model/acl/AclClass';
import AclSid from '@grin-global/ui-core/model/acl/AclSid';
import SidPermissions from '@grin-global/ui-core/model/acl/SidPermissions';
/*
......
import AclSid from '@/core/model/acl/AclSid';
import AclSid from '@grin-global/ui-core/model/acl/AclSid';
/*
* Defined in Swagger as '#/definitions/SidPermissions'
......
import { VersionedModel } from '@/core/model/common';
import { VersionedModel } from '@grin-global/ui-core/model/common/index';
export default abstract class AuditedVersionedModel extends VersionedModel {
public createdBy: number;
......