Replace UI module with Next.js
This commit is contained in:
parent
8aeff18162
commit
616205fe73
91 changed files with 3570 additions and 722 deletions
.devcontainer
.gitignorecreate.jspackage.jsonsource
__
.devcontainer
.editorconfig.env.tsconfig.jsonJenkinsfilegitignorenpmrcpackage.jsonpnpm-workspace.yamlprettierrcsonar-project.propertiescommon
rest
selenium
.eslintrc.tsconfig.json
config
cucumber.jsglobal.d.tspackage.jsonsrc
ui
.eslintrc.tsconfig.jsonREADME.md
config/tests
docker
jest.config.jsnext.config.jsnightwatch.jspackage.jsonpnpm-lock.yamlpostcss.config.jsscripts
src
app
components
constants
features
hooks
index.tsxpages
providers
redux
styles
components
global.csspostcss.config.jstailwind.config.jstailwind.config.tstheme.jstheme.tsvariables.csstypes
utils
tests
|
@ -3,16 +3,13 @@
|
|||
"workspaceFolder": "/home/project/seedling",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "seedling",
|
||||
"postCreateCommand": "sudo chown iamuser:iamuser -R /home/project",
|
||||
"postCreateCommand": "sudo chown iamuser:iamuser /home/project",
|
||||
"runServices": [
|
||||
"selenium"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"Fooxly.themeswitch",
|
||||
"EditorConfig.EditorConfig",
|
||||
"rvest.vs-code-prettier-eslint",
|
||||
"wix.vscode-import-cost",
|
||||
"mia-hall.vscode-git-branch-sidebar"
|
||||
]
|
||||
"extensions": []
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,42 @@
|
|||
version: "3"
|
||||
|
||||
name: seedling
|
||||
|
||||
volumes:
|
||||
node_modules:
|
||||
pnpm-store:
|
||||
|
||||
networks:
|
||||
net:
|
||||
name: seedling_net
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 10.2.1.0/24
|
||||
gateway: 10.2.1.1
|
||||
|
||||
services:
|
||||
seedling:
|
||||
build:
|
||||
context: .
|
||||
container_name: seedling
|
||||
volumes:
|
||||
- ../:/home/project/seedling
|
||||
- ../:/home/project/seedling:delegated
|
||||
- node_modules:/home/project/seedling/node_modules
|
||||
- pnpm-store:/home/project/seedling/.pnpm-store
|
||||
command: sleep infinity
|
||||
command: sleep infinity
|
||||
networks:
|
||||
net:
|
||||
ipv4_address: 10.2.1.2
|
||||
|
||||
selenium:
|
||||
image: seleniarm/standalone-chromium:114.0
|
||||
container_name: seedling-selenium
|
||||
shm_size: 2gb
|
||||
environment:
|
||||
- SE_VNC_NO_PASSWORD=1
|
||||
ports:
|
||||
- 7900:7900
|
||||
- 5900:5900
|
||||
- 4444:4444
|
||||
networks:
|
||||
net:
|
||||
ipv4_address: 10.2.1.4
|
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -1,10 +1,9 @@
|
|||
build/
|
||||
dist/
|
||||
app/
|
||||
node_modules/
|
||||
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
.pnpm/
|
||||
.pnpm-store/
|
||||
node_modules/
|
||||
.pnpm-store/
|
||||
output/
|
||||
|
|
11
create.js
11
create.js
|
@ -15,6 +15,7 @@ const contextDir = `${argv._[0] ?? defaultContextDir}`;
|
|||
const appsDir = `${contextDir}/apps`;
|
||||
const uiDir = `${contextDir}/apps/${appName}-ui`;
|
||||
const restDir = `${contextDir}/apps/${appName}-rest`;
|
||||
const testDir = `${contextDir}/apps/${appName}-selenium`;
|
||||
|
||||
// prepare structure folders
|
||||
if (!fs.existsSync(uiDir)) {
|
||||
|
@ -26,11 +27,13 @@ if (!fs.existsSync(uiDir)) {
|
|||
fs.mkdirSync(`${uiDir}/src`);
|
||||
fs.mkdirSync(restDir);
|
||||
fs.mkdirSync(`${restDir}/src`);
|
||||
fs.mkdirSync(testDir);
|
||||
fs.mkdirSync(`${testDir}/src`);
|
||||
}
|
||||
|
||||
// copy folder content
|
||||
try {
|
||||
fs.cpSync(`${rootDir}/source/common/`, contextDir, {
|
||||
fs.cpSync(`${rootDir}/source/__/`, contextDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
});
|
||||
|
@ -42,6 +45,10 @@ try {
|
|||
force: true,
|
||||
recursive: true,
|
||||
});
|
||||
fs.cpSync(`${rootDir}/source/selenium/`, testDir, {
|
||||
force: true,
|
||||
recursive: true,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
@ -56,6 +63,8 @@ fs.renameSync(`${contextDir}/prettierrc`, `${contextDir}/.prettierrc`);
|
|||
fs.renameSync(`${contextDir}/.tsconfig.json`, `${contextDir}/tsconfig.json`);
|
||||
fs.renameSync(`${uiDir}/.tsconfig.json`, `${uiDir}/tsconfig.json`);
|
||||
fs.renameSync(`${restDir}/.tsconfig.json`, `${restDir}/tsconfig.json`);
|
||||
fs.renameSync(`${testDir}/.tsconfig.json`, `${testDir}/tsconfig.json`);
|
||||
fs.renameSync(`${testDir}/src/.tsconfig.json`, `${testDir}/src/tsconfig.json`);
|
||||
|
||||
// replace in files
|
||||
replaceInFiles.sync({
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
"seedling": "./create.js"
|
||||
},
|
||||
"scripts": {
|
||||
"create": "pnpm ci:build",
|
||||
"ci:build": "node create.js --name app --port 90 ./app",
|
||||
"ci:build": "pnpm build",
|
||||
"build": "node create.js --name app --port 90 ./output",
|
||||
"release": "pnpm version --no-git-tag-version"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
42
source/__/.devcontainer/docker-compose.yml
Normal file
42
source/__/.devcontainer/docker-compose.yml
Normal file
|
@ -0,0 +1,42 @@
|
|||
version: "3"
|
||||
|
||||
volumes:
|
||||
node_modules:
|
||||
pnpm-store:
|
||||
|
||||
networks:
|
||||
net:
|
||||
name: $(appName)_net
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 10.2.0.0/24
|
||||
gateway: 10.2.0.1
|
||||
|
||||
services:
|
||||
seedling:
|
||||
build:
|
||||
context: .
|
||||
container_name: $(appName)
|
||||
volumes:
|
||||
- ../:/home/project/$(appName)
|
||||
- node_modules:/home/project/seedling/node_modules
|
||||
- pnpm-store:/home/project/seedling/.pnpm-store
|
||||
command: sleep infinity
|
||||
networks:
|
||||
net:
|
||||
ipv4_address: 10.2.0.2
|
||||
|
||||
selenium:
|
||||
image: seleniarm/standalone-chromium:114.0
|
||||
container_name: $(appName)-selenium
|
||||
shm_size: 2gb
|
||||
environment:
|
||||
- SE_VNC_NO_PASSWORD=1
|
||||
ports:
|
||||
- 7900:7900
|
||||
- 5900:5900
|
||||
- 4444:4444
|
||||
networks:
|
||||
net:
|
||||
ipv4_address: 10.2.0.4
|
14
source/__/.tsconfig.json
Normal file
14
source/__/.tsconfig.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strictNullChecks": true,
|
||||
"resolveJsonModule": true,
|
||||
"module": "commonjs",
|
||||
"target": "es6"
|
||||
},
|
||||
"exclude": [
|
||||
"./node_modules"
|
||||
]
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
build/
|
||||
dist/
|
||||
node_modules/
|
||||
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
node_modules/
|
||||
.pnpm-store/
|
|
@ -4,9 +4,10 @@
|
|||
"author": "Roman Jaroš",
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"dev": "pnpm -r dev",
|
||||
"dev": "pnpm -r --parallel --stream dev",
|
||||
"test": "pnpm -r test",
|
||||
"test:e2e": "pnpm -r test:e2e"
|
||||
"test:e2e": "pnpm -r test:e2e",
|
||||
"selenium:smoke": "pnpm -r selenium:smoke"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
|
@ -1,18 +0,0 @@
|
|||
version: "3"
|
||||
|
||||
name: $(appName)
|
||||
|
||||
volumes:
|
||||
node_modules:
|
||||
pnpm-store:
|
||||
|
||||
services:
|
||||
seedling:
|
||||
build:
|
||||
context: .
|
||||
container_name: $(appName)
|
||||
volumes:
|
||||
- ../:/home/project/$(appName)
|
||||
- node_modules:/home/project/seedling/node_modules
|
||||
- pnpm-store:/home/project/seedling/.pnpm-store
|
||||
command: sleep infinity
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"outDir": "build",
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
},
|
||||
"exclude": [
|
||||
"./node_modules",
|
||||
"./src/**/__tests__/*.tsx"
|
||||
]
|
||||
}
|
|
@ -1,9 +1,16 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": true,
|
||||
"strictFunctionTypes": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"allowJs": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./"
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
/** @type {import('jest').Config} */
|
||||
|
||||
const config = {
|
||||
moduleFileExtensions: ['js', 'json', 'ts'],
|
||||
rootDir: 'src',
|
||||
testRegex: '.*\\.spec\\.ts$',
|
||||
transform: {
|
||||
'^.+\\.(t|j)s$': 'ts-jest',
|
||||
},
|
||||
collectCoverageFrom: ['**/*.(t|j)s'],
|
||||
coverageDirectory: '../coverage',
|
||||
testEnvironment: 'node',
|
||||
moduleFileExtensions: ['js', 'json', 'ts'],
|
||||
rootDir: 'src',
|
||||
testRegex: '.\\.test\\.ts$',
|
||||
transform: {
|
||||
'^.+\\.(t|j)s$': 'ts-jest',
|
||||
},
|
||||
collectCoverageFrom: ['**/*.(t|j)s'],
|
||||
coverageDirectory: '../coverage',
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"scripts": {
|
||||
"nest": "nest",
|
||||
"build": "nest build",
|
||||
"dev": "nest start --watch",
|
||||
"dev": "nest start --watch --preserveWatchOutput",
|
||||
"dev:debug": "nest start --debug --watch",
|
||||
"start": "node dist/main",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
|
@ -16,7 +16,7 @@
|
|||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
"test:e2e": "jest --config ./test/jest.config.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/axios": "3.0.1",
|
||||
|
|
|
@ -4,7 +4,7 @@ const config = {
|
|||
moduleFileExtensions: ['js', 'json', 'ts'],
|
||||
rootDir: '.',
|
||||
testEnvironment: 'node',
|
||||
testRegex: '.e2e-spec.ts$',
|
||||
testRegex: '.spec.ts$',
|
||||
transform: {
|
||||
'^.+\\.(t|j)s$': 'ts-jest',
|
||||
},
|
83
source/selenium/.eslintrc
Normal file
83
source/selenium/.eslintrc
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"plugins": [
|
||||
"typescript",
|
||||
"@typescript-eslint",
|
||||
"typescript-sort-keys",
|
||||
"simple-import-sort",
|
||||
"import"
|
||||
],
|
||||
"settings": {
|
||||
"import/parsers": {
|
||||
"@typescript-eslint/parser": [
|
||||
".ts",
|
||||
".tsx"
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.js"
|
||||
],
|
||||
"parser": "esprima",
|
||||
"rules": {
|
||||
"@typescript-eslint/no-var-requires": 0
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": [],
|
||||
"rules": {
|
||||
"max-len": "off",
|
||||
"no-useless-escape": "off",
|
||||
"object-curly-spacing": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-multi-spaces": "error",
|
||||
"no-console": [
|
||||
"error",
|
||||
{
|
||||
"allow": [
|
||||
"info",
|
||||
"warn",
|
||||
"error"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-unused-vars": 2,
|
||||
"@typescript-eslint/interface-name-prefix": 0,
|
||||
"@typescript-eslint/no-empty-interface:": 0,
|
||||
"@typescript-eslint/explicit-function-return-type": 0,
|
||||
"@typescript-eslint/explicit-member-accessibility": 2,
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/no-empty-function": 0,
|
||||
"typescript-sort-keys/interface": "error",
|
||||
"typescript-sort-keys/string-enum": "error",
|
||||
"sort-imports": "off",
|
||||
"import/no-duplicates": "error",
|
||||
"import/order": "off",
|
||||
"simple-import-sort/imports": [
|
||||
"error",
|
||||
{
|
||||
"groups": [
|
||||
[
|
||||
"^\\u0000"
|
||||
],
|
||||
[
|
||||
"^[^.]"
|
||||
],
|
||||
[
|
||||
"^\\."
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
14
source/selenium/.tsconfig.json
Normal file
14
source/selenium/.tsconfig.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"./global.d.ts"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
6
source/selenium/config/.ci.env
Normal file
6
source/selenium/config/.ci.env
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Cucumber
|
||||
SELENIUM_SERVER_URL="http://10.0.1.22:4444"
|
||||
|
||||
# Application
|
||||
# HOST_IP="" - defined in Jenkins node
|
||||
APP_PORT="9092"
|
6
source/selenium/config/.local.env
Normal file
6
source/selenium/config/.local.env
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Cucumber
|
||||
SELENIUM_SERVER_URL="http://10.2.1.4:4444"
|
||||
|
||||
# Application
|
||||
HOST_IP="http://10.2.1.2"
|
||||
APP_PORT="3000"
|
24
source/selenium/cucumber.js
Normal file
24
source/selenium/cucumber.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
const argv = require('minimist')(process.argv);
|
||||
|
||||
const common = [
|
||||
'src/features/home.feature',
|
||||
'src/features/*.feature',
|
||||
'--require-module ts-node/register',
|
||||
'--require src/steps/**/*.ts',
|
||||
'-f summary',
|
||||
'-f json:report/report.json',
|
||||
'-f @qavajs/html-formatter:report/report.html',
|
||||
].join(' ');
|
||||
|
||||
module.exports = (async function () {
|
||||
if (argv['p'] === 'ci') {
|
||||
require('dotenv').config({ path: './config/.ci.env' });
|
||||
} else {
|
||||
require('dotenv').config({ path: './config/.local.env' });
|
||||
}
|
||||
|
||||
return {
|
||||
default: common,
|
||||
ci: common,
|
||||
};
|
||||
})();
|
11
source/selenium/global.d.ts
vendored
Normal file
11
source/selenium/global.d.ts
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
APP_PORT: string;
|
||||
HOST_IP: string;
|
||||
SELENIUM_SERVER_URL: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default global;
|
38
source/selenium/package.json
Normal file
38
source/selenium/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "$(appName)-selenium",
|
||||
"version": "0.1.0",
|
||||
"author": "Roman Jaroš",
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"selenium:smoke": "cucumber-js"
|
||||
},
|
||||
"dependencies": {
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@qavajs/html-formatter": "0.15.3",
|
||||
"@types/chai": "4.3.11",
|
||||
"@types/selenium-webdriver": "4.1.21",
|
||||
"@typescript-eslint/eslint-plugin": "6.15.0",
|
||||
"@typescript-eslint/parser": "6.15.0",
|
||||
"@cucumber/cucumber": "10.0.1",
|
||||
"dotenv": "16.3.1",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-config-next": "14.0.4",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "10.0.0",
|
||||
"eslint-plugin-typescript": "0.14.0",
|
||||
"eslint-plugin-typescript-sort-keys": "3.1.0",
|
||||
"chai": "4.3.10",
|
||||
"cucumber-tsflow": "4.3.1",
|
||||
"minimist": "1.2.8",
|
||||
"prettier": "3.1.1",
|
||||
"selenium-webdriver": "4.16.0",
|
||||
"ts-loader": "9.5.1",
|
||||
"ts-node": "10.9.2"
|
||||
},
|
||||
"peerDependencies": {}
|
||||
}
|
13
source/selenium/src/.tsconfig.json
Normal file
13
source/selenium/src/.tsconfig.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": false,
|
||||
"typeRoots": [
|
||||
"../"
|
||||
]
|
||||
},
|
||||
"ts-node": {
|
||||
"transpileOnly": true
|
||||
}
|
||||
}
|
17
source/selenium/src/common/BasePage.ts
Normal file
17
source/selenium/src/common/BasePage.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { By } from 'selenium-webdriver';
|
||||
|
||||
export class BasePage {
|
||||
protected url: string;
|
||||
|
||||
public title?: string;
|
||||
public root: By;
|
||||
|
||||
public buttons?: Record<string, By>;
|
||||
public fields?: Record<string, By>;
|
||||
public forms?: Record<string, By>;
|
||||
public messages?: Record<string, By>;
|
||||
|
||||
public getPageUrl() {
|
||||
return `${process.env.HOST_IP}:${process.env.APP_PORT}` + this.url;
|
||||
}
|
||||
}
|
13
source/selenium/src/common/BaseStep.ts
Normal file
13
source/selenium/src/common/BaseStep.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { setDefaultTimeout } from '@cucumber/cucumber';
|
||||
import { ThenableWebDriver } from 'selenium-webdriver';
|
||||
|
||||
import { WebDriver } from './WebDriver';
|
||||
|
||||
export class BaseStep {
|
||||
protected driver: ThenableWebDriver;
|
||||
|
||||
public constructor() {
|
||||
this.driver = new WebDriver().getDriver();
|
||||
setDefaultTimeout(10 * 60 * 1000);
|
||||
}
|
||||
}
|
25
source/selenium/src/common/WebDriver.ts
Normal file
25
source/selenium/src/common/WebDriver.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { binding } from 'cucumber-tsflow';
|
||||
import { Builder, Capabilities, ThenableWebDriver } from 'selenium-webdriver';
|
||||
|
||||
const capabilities = Capabilities.chrome();
|
||||
capabilities.set('chromeOptions', { w3c: false });
|
||||
|
||||
@binding()
|
||||
export class WebDriver {
|
||||
protected readonly driver: ThenableWebDriver;
|
||||
private static instance: WebDriver;
|
||||
|
||||
public constructor() {
|
||||
if (WebDriver.instance) {
|
||||
return WebDriver.instance;
|
||||
}
|
||||
|
||||
this.driver = new Builder().usingServer(process.env.SELENIUM_SERVER_URL).withCapabilities(capabilities).build();
|
||||
this.driver.manage().setTimeouts({ implicit: 100 });
|
||||
WebDriver.instance = this;
|
||||
}
|
||||
|
||||
public getDriver() {
|
||||
return this.driver;
|
||||
}
|
||||
}
|
5
source/selenium/src/features/home.feature
Normal file
5
source/selenium/src/features/home.feature
Normal file
|
@ -0,0 +1,5 @@
|
|||
Feature: Home page
|
||||
|
||||
Scenario: Verify home page title
|
||||
Given i visit home page
|
||||
Then page title is $(AppName)
|
15
source/selenium/src/pages/HomePage.ts
Normal file
15
source/selenium/src/pages/HomePage.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { binding } from 'cucumber-tsflow';
|
||||
import { By } from 'selenium-webdriver';
|
||||
|
||||
import { BasePage } from '../common/BasePage';
|
||||
|
||||
@binding()
|
||||
export class HomePage extends BasePage {
|
||||
protected url = '/';
|
||||
|
||||
// initial div
|
||||
public root = By.xpath('//body');
|
||||
|
||||
// page buttons
|
||||
public buttons = {};
|
||||
}
|
6
source/selenium/src/pages/components/Navigation.ts
Normal file
6
source/selenium/src/pages/components/Navigation.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { By } from 'selenium-webdriver';
|
||||
|
||||
export class Navigation {
|
||||
public root = By.xpath('//div[@class="page-top"]');
|
||||
public logoutLink = By.xpath(`${this.root.value}//div[contains(text(), "Odhlásit se")]`);
|
||||
}
|
20
source/selenium/src/steps/common/page.steps.ts
Normal file
20
source/selenium/src/steps/common/page.steps.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { expect } from 'chai';
|
||||
import { binding, given } from 'cucumber-tsflow';
|
||||
import { ThenableWebDriver } from 'selenium-webdriver';
|
||||
|
||||
import { WebDriver } from '../../common/WebDriver';
|
||||
|
||||
@binding([])
|
||||
export class PageSteps {
|
||||
protected driver: ThenableWebDriver;
|
||||
|
||||
public constructor() {
|
||||
this.driver = new WebDriver().getDriver();
|
||||
}
|
||||
|
||||
@given(/page title is (.*)/)
|
||||
public async thenPageTitleIs(title: string) {
|
||||
const pageTitle = await this.driver.getTitle();
|
||||
expect(pageTitle).to.equal(title);
|
||||
}
|
||||
}
|
24
source/selenium/src/steps/common/session.steps.ts
Normal file
24
source/selenium/src/steps/common/session.steps.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { afterAll, binding } from 'cucumber-tsflow';
|
||||
import { until } from 'selenium-webdriver';
|
||||
|
||||
import { WebDriver } from '../../common/WebDriver';
|
||||
import { Navigation } from '../../pages/components/Navigation';
|
||||
|
||||
@binding([])
|
||||
export class SessionSteps {
|
||||
@afterAll()
|
||||
protected async closeBrowser() {
|
||||
const driver = new WebDriver().getDriver();
|
||||
await driver.quit();
|
||||
}
|
||||
|
||||
@afterAll()
|
||||
protected async logout() {
|
||||
const driver = new WebDriver().getDriver();
|
||||
const webElements = await driver.findElements(new Navigation().logoutLink);
|
||||
if (webElements.length > 0) {
|
||||
await webElements[0]?.click?.();
|
||||
await driver.wait(until.urlContains(`${process.env.HOST_IP}:${process.env.APP_PORT}`));
|
||||
}
|
||||
}
|
||||
}
|
16
source/selenium/src/steps/home.steps.ts
Normal file
16
source/selenium/src/steps/home.steps.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { binding, given } from 'cucumber-tsflow';
|
||||
|
||||
import { BaseStep } from '../common/BaseStep';
|
||||
import { HomePage } from '../pages/HomePage';
|
||||
|
||||
@binding([HomePage])
|
||||
export class HomePageSteps extends BaseStep {
|
||||
public constructor(public readonly homePage: HomePage) {
|
||||
super();
|
||||
}
|
||||
|
||||
@given(/i visit home page/)
|
||||
public async givenIamOnHomePage() {
|
||||
await this.driver.get(this.homePage.getPageUrl());
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
"prettier",
|
||||
"next/core-web-vitals"
|
||||
],
|
||||
"plugins": [
|
||||
"react",
|
||||
|
|
|
@ -1,54 +1,34 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"api/*": [
|
||||
"./src/api/*"
|
||||
],
|
||||
"app/*": [
|
||||
"./src/app/*"
|
||||
],
|
||||
"components/*": [
|
||||
"./src/components/*"
|
||||
],
|
||||
"constants/*": [
|
||||
"./src/constants/*"
|
||||
],
|
||||
"features/*": [
|
||||
"./src/features/*"
|
||||
],
|
||||
"hooks/*": [
|
||||
"./src/hooks/*"
|
||||
],
|
||||
"localization/*": [
|
||||
"./src/localization/*"
|
||||
],
|
||||
"pages/*": [
|
||||
"./src/pages/*"
|
||||
],
|
||||
"utils/*": [
|
||||
"./src/utils/*"
|
||||
],
|
||||
"types/*": [
|
||||
"./src/types/*"
|
||||
]
|
||||
},
|
||||
"types": [
|
||||
"node",
|
||||
"jest",
|
||||
"./src/types/yup"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
||||
"./src/**/*.tsx",
|
||||
"./types/modules.d.ts",
|
||||
"src/styles/theme.js"
|
||||
],
|
||||
"exclude": [
|
||||
"./node_modules",
|
||||
"./src/**/__tests__/*.tsx"
|
||||
]
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"types": [
|
||||
"node",
|
||||
"jest"
|
||||
],
|
||||
"strict": false,
|
||||
"noEmit": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
||||
"./src/**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"./src/**/__tests__/*.tsx"
|
||||
]
|
||||
}
|
|
@ -1 +1,36 @@
|
|||
# $(AppName)
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
ENDPOINT_BASE_URL=""
|
|
@ -1 +0,0 @@
|
|||
ENDPOINT_BASE_URL=""
|
|
@ -1,12 +1,27 @@
|
|||
FROM nginx:1.25.3-alpine
|
||||
FROM node:18-alpine3.19
|
||||
|
||||
RUN mkdir app
|
||||
RUN mkdir -p /run/nginx
|
||||
RUN apk add --no-cache libc6-compat
|
||||
|
||||
COPY build /app
|
||||
COPY docker/nginx/conf.d/ /etc/nginx/conf.d/
|
||||
WORKDIR /app
|
||||
|
||||
EXPOSE 80
|
||||
ENV NODE_ENV production
|
||||
ENV PORT 3000
|
||||
|
||||
VOLUME [ "/etc/nginx/conf.d" ]
|
||||
ENTRYPOINT ["nginx", "-g", "daemon off;"]
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs \
|
||||
&& adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY .next/ .next/
|
||||
COPY public/ public/
|
||||
COPY node_modules/ node_modules/
|
||||
COPY package.json package.json
|
||||
COPY next.config.js next.config.js
|
||||
|
||||
RUN chown -R nextjs:nodejs .next
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["npm", "run", "start"]
|
|
@ -1,13 +0,0 @@
|
|||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
server_name _;
|
||||
|
||||
root /app;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.(ts|tsx)$': 'ts-jest',
|
||||
},
|
||||
testRegex: '(/__tests__/.*|(-|/)(test))\\.(ts|tsx)?$',
|
||||
transformIgnorePatterns: ['<rootDir>/node_modules/.*'],
|
||||
testPathIgnorePatterns: ['.vscode'],
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
||||
moduleNameMapper: {
|
||||
'^app(.*)$': '<rootDir>/src/app/$1',
|
||||
'^api(.*)$': '<rootDir>/src/api/$1',
|
||||
'^components(.*)$': '<rootDir>/src/components/$1',
|
||||
'^constants(.*)$': '<rootDir>/src/constants/$1',
|
||||
'^features(.*)$': '<rootDir>/src/features/$1',
|
||||
'^hooks(.*)$': '<rootDir>/src/hooks/$1',
|
||||
'^localization(.*)$': '<rootDir>/src/localization/$1',
|
||||
'^pages(.*)$': '<rootDir>/src/pages/$1',
|
||||
'^types(.*)$': '<rootDir>/src/types/$1',
|
||||
'^utils(.*)$': '<rootDir>/src/utils/$1',
|
||||
},
|
||||
};
|
4
source/ui/next.config.js
Normal file
4
source/ui/next.config.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
module.exports = nextConfig;
|
|
@ -1,41 +0,0 @@
|
|||
/** @type {import('nightwatch').NightwatchOptions} */
|
||||
|
||||
module.exports = {
|
||||
src_folders: 'tests/.nightwatchjs/src',
|
||||
output_folder: 'tests/.nightwatchjs/output',
|
||||
page_objects_path: ['tests/.nightwatchjs/objects'],
|
||||
custom_commands_path: 'tests/.nightwatchjs/commands',
|
||||
use_xpath: true,
|
||||
end_session_on_fail: true,
|
||||
start_process: false,
|
||||
test_settings: {
|
||||
localhost: {
|
||||
launch_url: '',
|
||||
selenium_port: 4444,
|
||||
selenium_host: '10.2.0.4',
|
||||
screenshots: {
|
||||
enabled: true,
|
||||
on_failure: true,
|
||||
on_error: true,
|
||||
path: 'tests/.nightwatchjs/output',
|
||||
},
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions: {
|
||||
args: ['no-sandbox'],
|
||||
},
|
||||
},
|
||||
},
|
||||
ci: {
|
||||
launch_url: '',
|
||||
selenium_port: 4444,
|
||||
selenium_host: '10.0.1.21',
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
chromeOptions: {
|
||||
args: ['headless', 'no-sandbox'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -1,95 +1,73 @@
|
|||
{
|
||||
"name": "$(appName)-ui",
|
||||
"version": "0.1.0",
|
||||
"author": "Roman Jaroš",
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"ci:build": "pnpm build:prod",
|
||||
"ci:build:test": "pnpm build:test",
|
||||
"ci:test:e2e": "nightwatch --env ci",
|
||||
"dev": "webpack serve --config scripts/webpack-dev.js --env config=local",
|
||||
"lint": "eslint -c .eslintrc src/**/*.{ts,tsx}",
|
||||
"lint:css": "stylelint src/**/*.ts",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:update": "jest -u",
|
||||
"test:e2e-build": "tsc -p tests/tsconfig.json -w",
|
||||
"test:e2e": "nightwatch --env localhost",
|
||||
"build:prod": "webpack --config scripts/webpack-prod.js",
|
||||
"build:test": "webpack --config scripts/webpack-dev.js --env config=test",
|
||||
"serve": "http-server-spa build index.html 3331",
|
||||
"codegen": "pnpm dlx @rtk-query/codegen-openapi openapi-config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@procyon/api": "1.2.9",
|
||||
"@procyon/auth": "1.2.9",
|
||||
"@procyon/components": "1.2.9",
|
||||
"@procyon/constants": "1.2.9",
|
||||
"@procyon/forms": "1.2.9",
|
||||
"@procyon/localization": "1.2.9",
|
||||
"@procyon/styles": "1.2.9",
|
||||
"@procyon/types": "1.2.9",
|
||||
"@procyon/utils": "1.2.9",
|
||||
"@reduxjs/toolkit": "2.0.1",
|
||||
"clsx": "2.0.0",
|
||||
"date-fns": "3.0.6",
|
||||
"history": "5.3.0",
|
||||
"ramda": "0.29.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-redux": "9.0.4",
|
||||
"typescript": "5.3.3",
|
||||
"wouter": "2.12.1",
|
||||
"yup": "1.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rtk-query/codegen-openapi": "1.2.0",
|
||||
"@types/enzyme": "3.10.16",
|
||||
"@types/jest": "29.5.11",
|
||||
"@types/nightwatch": "2.3.30",
|
||||
"@types/ramda": "0.29.9",
|
||||
"@types/react": "18.2.45",
|
||||
"@types/react-dom": "18.2.18",
|
||||
"@types/react-redux": "7.1.33",
|
||||
"@types/yup": "0.29.14",
|
||||
"@typescript-eslint/eslint-plugin": "6.15.0",
|
||||
"@typescript-eslint/parser": "6.15.0",
|
||||
"autoprefixer": "10.4.16",
|
||||
"case-sensitive-paths-webpack-plugin": "2.4.0",
|
||||
"clean-webpack-plugin": "4.0.0",
|
||||
"copy-webpack-plugin": "11.0.0",
|
||||
"css-loader": "6.8.1",
|
||||
"process": "0.11.10",
|
||||
"dotenv": "16.3.1",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "10.0.0",
|
||||
"eslint-plugin-typescript": "0.14.0",
|
||||
"eslint-plugin-typescript-sort-keys": "3.1.0",
|
||||
"file-loader": "6.2.0",
|
||||
"html-webpack-plugin": "5.6.0",
|
||||
"http-server-spa": "1.3.0",
|
||||
"jest": "29.7.0",
|
||||
"mini-css-extract-plugin": "2.7.6",
|
||||
"nightwatch": "3.3.5",
|
||||
"postcss": "8.4.32",
|
||||
"postcss-loader": "7.3.3",
|
||||
"prettier": "3.1.1",
|
||||
"tailwindcss": "3.4.0",
|
||||
"ts-node": "10.9.2",
|
||||
"ts-jest": "29.1.1",
|
||||
"ts-loader": "9.5.1",
|
||||
"ts-prune": "0.10.3",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"url-loader": "4.1.1",
|
||||
"webpack": "5.89.0",
|
||||
"webpack-bundle-analyzer": "4.10.1",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-merge": "5.10.0"
|
||||
},
|
||||
"peerDependencies": {}
|
||||
"name": "$(appName)-ui",
|
||||
"version": "0.1.0",
|
||||
"author": "Roman Jaroš",
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"ci:build": "pnpm build:prod",
|
||||
"ci:in-test:smoke": "pnpm in-test:smoke -p ci",
|
||||
"dev": "next dev",
|
||||
"start": "next start",
|
||||
"lint": "eslint src/**/*.{ts,tsx}",
|
||||
"lint:css": "stylelint src/**/*.ts",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:update": "jest -u",
|
||||
"build:prod": "next build",
|
||||
"codegen": "pnpm dlx @rtk-query/codegen-openapi openapi-config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@procyon/api": "1.2.10",
|
||||
"@procyon/auth": "1.2.10",
|
||||
"@procyon/components": "1.2.10",
|
||||
"@procyon/constants": "1.2.10",
|
||||
"@procyon/forms": "1.2.10",
|
||||
"@procyon/localization": "1.2.10",
|
||||
"@procyon/styles": "1.2.10",
|
||||
"@procyon/types": "1.2.10",
|
||||
"@procyon/utils": "1.2.10",
|
||||
"@reduxjs/toolkit": "2.0.1",
|
||||
"clsx": "2.0.0",
|
||||
"date-fns": "3.0.6",
|
||||
"history": "5.3.0",
|
||||
"next": "14.0.4",
|
||||
"ramda": "0.29.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-redux": "9.0.4",
|
||||
"typescript": "5.3.3",
|
||||
"yup": "1.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rtk-query/codegen-openapi": "1.2.0",
|
||||
"@types/jest": "29.5.11",
|
||||
"@types/ramda": "0.29.9",
|
||||
"@types/react": "18.2.45",
|
||||
"@types/react-dom": "18.2.18",
|
||||
"@types/react-redux": "7.1.33",
|
||||
"@types/yup": "0.29.14",
|
||||
"@typescript-eslint/eslint-plugin": "6.15.0",
|
||||
"@typescript-eslint/parser": "6.15.0",
|
||||
"autoprefixer": "10.4.16",
|
||||
"css-loader": "^6.8.1",
|
||||
"process": "0.11.10",
|
||||
"dotenv": "16.3.1",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-config-next": "14.0.4",
|
||||
"eslint-plugin-react": "7.33.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-simple-import-sort": "10.0.0",
|
||||
"eslint-plugin-typescript": "0.14.0",
|
||||
"eslint-plugin-typescript-sort-keys": "3.1.0",
|
||||
"jest": "29.7.0",
|
||||
"postcss": "8.4.32",
|
||||
"postcss-loader": "7.3.3",
|
||||
"prettier": "3.1.1",
|
||||
"tailwindcss": "3.4.0",
|
||||
"ts-node": "10.9.2",
|
||||
"ts-jest": "29.1.1"
|
||||
},
|
||||
"peerDependencies": {}
|
||||
}
|
2778
source/ui/pnpm-lock.yaml
generated
Normal file
2778
source/ui/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load diff
5
source/ui/postcss.config.js
Normal file
5
source/ui/postcss.config.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const configPath = require.resolve('./src/styles/tailwind.config.ts');
|
||||
|
||||
module.exports = {
|
||||
plugins: ['postcss-import', 'tailwindcss/nesting', ['tailwindcss', configPath], 'autoprefixer'],
|
||||
};
|
|
@ -1,82 +0,0 @@
|
|||
require('ts-node/register');
|
||||
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const HtmlWebPackPlugin = require('html-webpack-plugin');
|
||||
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
const __basedir = path.resolve(__dirname, '..');
|
||||
|
||||
module.exports = (env, args, myEnv) => ({
|
||||
entry: {
|
||||
app: [path.resolve(__basedir, 'src/index.tsx')],
|
||||
style: [path.resolve(__basedir, 'src/styles/global.css')],
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__basedir, 'build'),
|
||||
publicPath: '/',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
api: path.resolve(__basedir, 'src/api'),
|
||||
app: path.resolve(__basedir, 'src/app'),
|
||||
components: path.resolve(__basedir, 'src/components'),
|
||||
constants: path.resolve(__basedir, 'src/constants'),
|
||||
features: path.resolve(__basedir, 'src/features'),
|
||||
hooks: path.resolve(__basedir, 'src/hooks'),
|
||||
localization: path.resolve(__basedir, 'src/localization'),
|
||||
pages: path.resolve(__basedir, 'src/pages'),
|
||||
utils: path.resolve(__basedir, 'src/utils'),
|
||||
types: path.resolve(__basedir, 'src/types'),
|
||||
},
|
||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: 'ts-loader',
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
'css-loader',
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
postcssOptions: {
|
||||
config: path.resolve(__basedir, 'src/styles/postcss.config.js'),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].css',
|
||||
}),
|
||||
new HtmlWebPackPlugin({
|
||||
hash: true,
|
||||
filename: 'index.html', //target html
|
||||
template: path.resolve(__basedir, 'src/app/assets/html/index.ejs'), //source html
|
||||
env: {
|
||||
websiteId: process.env.WA_WEBSITE_ID,
|
||||
},
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: path.resolve(__basedir, 'src/app/assets/public'), to: './' },
|
||||
],
|
||||
}),
|
||||
new webpack.EnvironmentPlugin(myEnv),
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser',
|
||||
}),
|
||||
new CaseSensitivePathsPlugin(),
|
||||
],
|
||||
});
|
|
@ -1,17 +0,0 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
|
||||
const common = require('./webpack-common');
|
||||
const myEnv = require('dotenv').config({ path: 'config/app/.env.local' }).parsed;
|
||||
|
||||
module.exports = (env, args) => {
|
||||
return merge(common(env, args, myEnv), {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
devServer: {
|
||||
host: '0.0.0.0',
|
||||
port: '3330',
|
||||
hot: true,
|
||||
historyApiFallback: true,
|
||||
},
|
||||
});
|
||||
};
|
|
@ -1,16 +0,0 @@
|
|||
const { merge } = require('webpack-merge');
|
||||
|
||||
const myEnv = require('dotenv').config({ path: 'config/app/.env.prod' }).parsed;
|
||||
const common = require('./webpack-common');
|
||||
|
||||
// const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||
|
||||
module.exports = (env, args) => {
|
||||
return merge(common(env, args, myEnv), {
|
||||
mode: 'production',
|
||||
devtool: false,
|
||||
plugins: [
|
||||
// new BundleAnalyzerPlugin(),
|
||||
],
|
||||
});
|
||||
};
|
|
@ -1,66 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import React, { FC } from 'react';
|
||||
import { Route, Switch } from 'wouter';
|
||||
|
||||
import { useAuth } from '@procyon/auth/hook/useAuth';
|
||||
import Section from '@procyon/components/Section';
|
||||
import { Skeleton } from '@procyon/components/Skeleton';
|
||||
import { MenuItem } from '@procyon/components/Skeleton/types';
|
||||
|
||||
import { WelcomePage } from 'pages/WelcomePage';
|
||||
|
||||
import { buildRoute, Routes } from './routes';
|
||||
|
||||
const topMenu: MenuItem[][] = [
|
||||
[
|
||||
{ label: 'Routa', href: buildRoute('root') },
|
||||
],
|
||||
[
|
||||
// authenticated
|
||||
],
|
||||
];
|
||||
|
||||
const userMenu: MenuItem[][] = [
|
||||
[
|
||||
// public
|
||||
],
|
||||
[
|
||||
// authenticated
|
||||
],
|
||||
];
|
||||
|
||||
export const App: FC = () => {
|
||||
const { authenticated } = useAuth();
|
||||
|
||||
return (
|
||||
<Skeleton
|
||||
items={{
|
||||
logo: <>Many</>,
|
||||
top: authenticated ? topMenu[1] : topMenu[0],
|
||||
user: authenticated ? userMenu[1] : userMenu[0],
|
||||
}}
|
||||
components={{
|
||||
footer: (
|
||||
<div className="text-center footer">
|
||||
<Section>
|
||||
Tento web používá pouze technické cookie. Monitorování návštěvnosti je zcela anonymní a je prováděno na straně
|
||||
provozovatele webu.
|
||||
</Section>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
>
|
||||
{authenticated ? (
|
||||
<Switch>
|
||||
<Route>404!</Route>
|
||||
</Switch>
|
||||
) : (
|
||||
<Switch>
|
||||
<Route path={Routes.root} component={WelcomePage} />
|
||||
<Route>404!</Route>
|
||||
</Switch>
|
||||
)}
|
||||
</Skeleton>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="https://fonts.googleapis.com/css?family=Ubuntu:400,700&subset=cyrillic-ext" rel="stylesheet">
|
||||
<title>$(AppName)</title>
|
||||
<meta name="robots" content="index,follow">
|
||||
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #666;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
|
||||
<% if (htmlWebpackPlugin.options.env.websiteId) { %>
|
||||
<script async src="https://wa.romanjaros.dev/script.js"
|
||||
data-website-id="<%= htmlWebpackPlugin.options.env.websiteId %>">
|
||||
</script>
|
||||
<% } %>
|
||||
|
||||
</html>
|
28
source/ui/src/app/layout.tsx
Normal file
28
source/ui/src/app/layout.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
// @ts-nocheck
|
||||
import '../styles/global.css';
|
||||
|
||||
import type { Metadata } from 'next';
|
||||
import { Poppins } from 'next/font/google';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
import { ReduxProvider } from '../providers/Redux';
|
||||
import { SkeletonProvider } from '../providers/Skeleton';
|
||||
|
||||
const inter = Poppins({ weight: ['300', '500', '700'], display: 'swap', subsets: ['latin'] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: `$(AppName)`,
|
||||
description: '',
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
|
||||
return (
|
||||
<ReduxProvider>
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
<SkeletonProvider>{children}</SkeletonProvider>
|
||||
</body>
|
||||
</html>
|
||||
</ReduxProvider>
|
||||
);
|
||||
}
|
4
source/ui/src/app/next-page/page.tsx
Normal file
4
source/ui/src/app/next-page/page.tsx
Normal file
|
@ -0,0 +1,4 @@
|
|||
// @ts-nocheck
|
||||
export default function Page() {
|
||||
return <b>Next page</b>;
|
||||
}
|
4
source/ui/src/app/page.tsx
Normal file
4
source/ui/src/app/page.tsx
Normal file
|
@ -0,0 +1,4 @@
|
|||
// @ts-nocheck
|
||||
export default function Page() {
|
||||
return <>Welcome!</>;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import { DotNestedKeys } from '@procyon/localization/types';
|
||||
|
||||
export const Routes = {
|
||||
root: '/'
|
||||
};
|
||||
|
||||
export const buildRoute = (route: DotNestedKeys<typeof Routes>) => {
|
||||
let path = '';
|
||||
let obj: Record<string, any> = Routes;
|
||||
route.split('.').forEach((key: any) => {
|
||||
path += obj[key]?.base ?? obj[key];
|
||||
obj = obj[key];
|
||||
});
|
||||
return path;
|
||||
};
|
|
@ -1,34 +0,0 @@
|
|||
// @ts-nocheck
|
||||
// import generated apis
|
||||
|
||||
import { AnyAction, combineReducers, configureStore, ThunkDispatch } from '@reduxjs/toolkit';
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import authReducer from '@procyon/auth/slice';
|
||||
import { AUTH_REDUCER_NAME } from '@procyon/auth/types';
|
||||
import { ROOT_REDUCER_NAME } from '@procyon/constants/redux';
|
||||
|
||||
import { emptyApi } from '../api/emptyApi';
|
||||
|
||||
type procyonReducer = {
|
||||
[AUTH_REDUCER_NAME]: typeof authReducer;
|
||||
};
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
[ROOT_REDUCER_NAME]: combineReducers<procyonReducer>({
|
||||
[AUTH_REDUCER_NAME]: authReducer,
|
||||
}),
|
||||
[emptyApi.reducerPath]: emptyApi.reducer,
|
||||
},
|
||||
middleware: (gDM) => [...gDM({ serializableCheck: false }).concat([emptyApi.middleware])],
|
||||
devTools: process.env.NODE_ENV === 'development'
|
||||
});
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
export type AppDispatch = ThunkDispatch<RootState, unknown, AnyAction>;
|
||||
|
||||
export const useAppDispatch: () => AppDispatch = useDispatch;
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
|
||||
export default store;
|
|
@ -1,25 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import 'types/global';
|
||||
import 'localization/locale';
|
||||
import 'utils/yup';
|
||||
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { ModalWrapper } from '@procyon/components/Modal/context';
|
||||
import { ToasterWrapper } from '@procyon/components/Toaster/context';
|
||||
|
||||
import { App } from './app/app';
|
||||
import store from './app/store';
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<ModalWrapper>
|
||||
<ToasterWrapper>
|
||||
<App />
|
||||
</ToasterWrapper>
|
||||
</ModalWrapper>
|
||||
</Provider>,
|
||||
document.getElementById('app')
|
||||
);
|
|
@ -1,6 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import React from 'react';
|
||||
|
||||
export const WelcomePage = () => {
|
||||
return <div className="welcome">Seedling app generator.</div>;
|
||||
};
|
16
source/ui/src/providers/Redux.tsx
Normal file
16
source/ui/src/providers/Redux.tsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
// @ts-nocheck
|
||||
'use client';
|
||||
|
||||
import { useRef, ReactNode } from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
|
||||
import { makeStore } from '../redux/store';
|
||||
|
||||
export function ReduxProvider({ children }: { children: ReactNode }) {
|
||||
const storeRef = useRef<ReturnType<typeof makeStore> | null>(null);
|
||||
if (!storeRef.current) {
|
||||
storeRef.current = makeStore();
|
||||
}
|
||||
|
||||
return <Provider store={storeRef.current}>{children}</Provider>;
|
||||
}
|
28
source/ui/src/providers/Skeleton.tsx
Normal file
28
source/ui/src/providers/Skeleton.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
// @ts-nocheck
|
||||
'use client';
|
||||
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Skeleton } from '@procyon/components/Skeleton';
|
||||
|
||||
export function SkeletonProvider({ children }: Readonly<{ children: React.ReactNode }>) {
|
||||
const router = useRouter();
|
||||
return (
|
||||
<Skeleton
|
||||
onHref={(path) => router.push(path as string)}
|
||||
items={{
|
||||
logo: <>App</>,
|
||||
top: [
|
||||
{
|
||||
label: 'Home',
|
||||
href: '/',
|
||||
},
|
||||
{
|
||||
label: 'Next page',
|
||||
href: '/next-page',
|
||||
},
|
||||
],
|
||||
}}>
|
||||
{children}
|
||||
</Skeleton>
|
||||
);
|
||||
}
|
27
source/ui/src/redux/store.ts
Normal file
27
source/ui/src/redux/store.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
// @ts-nocheck
|
||||
import { combineReducers, configureStore } from '@reduxjs/toolkit';
|
||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import authReducer from '@procyon/auth/slice';
|
||||
|
||||
import { emptyApi } from './emptyApi';
|
||||
|
||||
export const makeStore = () =>
|
||||
configureStore({
|
||||
reducer: {
|
||||
procyon: combineReducers({
|
||||
auth: authReducer,
|
||||
}),
|
||||
[emptyApi.reducerPath]: emptyApi.reducer,
|
||||
},
|
||||
middleware: (gDM) => gDM().prepend(emptyApi.middleware),
|
||||
devTools: process.env.NODE_ENV === 'development',
|
||||
});
|
||||
|
||||
export type ReduxStore = ReturnType<typeof makeStore>;
|
||||
|
||||
export type RootState = ReturnType<ReduxStore['getState']>;
|
||||
export type AppDispatch = ReduxStore['dispatch'];
|
||||
|
||||
export const useAppDispatch: () => AppDispatch = useDispatch;
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
|
@ -1,8 +0,0 @@
|
|||
const component = () => ({
|
||||
});
|
||||
|
||||
module.exports = ({ addComponents, theme }) => {
|
||||
addComponents(component(theme));
|
||||
};
|
||||
|
||||
module.exports.component = component;
|
9
source/ui/src/styles/components/component.ts
Normal file
9
source/ui/src/styles/components/component.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { PluginCreator } from 'tailwindcss/types/config';
|
||||
|
||||
const component = () => ({});
|
||||
|
||||
const creator: PluginCreator = ({ addComponents, theme }) => {
|
||||
addComponents({});
|
||||
};
|
||||
|
||||
export default creator;
|
|
@ -1,9 +1,5 @@
|
|||
@import '@procyon/styles/global.css';
|
||||
|
||||
@import "./variables.css";
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;500;700&display=swap');
|
||||
|
||||
body {
|
||||
@apply bg-white text-black text-sm;
|
||||
font-family: 'Poppins', sans-serif;
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
const postcss = require('@procyon/styles/postcss.config');
|
||||
const configPath = require.resolve('./tailwind.config.js');
|
||||
|
||||
module.exports = postcss({ tailwindConfigFile: configPath });
|
|
@ -1,23 +0,0 @@
|
|||
const path = require('path');
|
||||
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
|
||||
module.exports = {
|
||||
presets: [require('@procyon/styles/tailwind.config')],
|
||||
content: [
|
||||
path.resolve(__dirname + '../../**/*.{js,ts,tsx}'),
|
||||
path.resolve(__dirname + '../../../node_modules/@procyon/**/*.{js,ts,tsx}'),
|
||||
],
|
||||
safelist: require('@procyon/styles/tailwind.config').safelist,
|
||||
theme: {
|
||||
extend: require('./theme'),
|
||||
},
|
||||
variants: {
|
||||
extend: {
|
||||
borderWidth: ['last'],
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
plugin(require('./components/component')),
|
||||
],
|
||||
};
|
18
source/ui/src/styles/tailwind.config.ts
Normal file
18
source/ui/src/styles/tailwind.config.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import type { Config } from 'tailwindcss';
|
||||
import plugin from 'tailwindcss/plugin';
|
||||
import path from 'path';
|
||||
|
||||
export default {
|
||||
presets: [require('@procyon/styles/tailwind.config')],
|
||||
content: [
|
||||
path.resolve(__dirname + '../../app/*.{js,ts,tsx}'),
|
||||
path.resolve(__dirname + '../../pages/*.{js,ts,tsx}'),
|
||||
path.resolve(__dirname + '../../components/*.{js,ts,tsx}'),
|
||||
path.resolve(__dirname + '../../../node_modules/@procyon/**/*.{js,ts,tsx}'),
|
||||
],
|
||||
safelist: require('@procyon/styles/tailwind.config').safelist,
|
||||
theme: {
|
||||
extend: require('./theme'),
|
||||
},
|
||||
plugins: [plugin(require('./components/component'))],
|
||||
} satisfies Config;
|
|
@ -1,10 +0,0 @@
|
|||
const { pallete } = require('@procyon/styles/utils/color');
|
||||
|
||||
module.exports = {
|
||||
colors: {
|
||||
disabled: pallete('disabled'),
|
||||
},
|
||||
borderWidth: {
|
||||
1: '1px',
|
||||
},
|
||||
};
|
12
source/ui/src/styles/theme.ts
Normal file
12
source/ui/src/styles/theme.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
// @ts-nocheck
|
||||
|
||||
import palette from '@procyon/styles/palette';
|
||||
|
||||
module.exports = {
|
||||
colors: {
|
||||
...palette,
|
||||
},
|
||||
borderWidth: {
|
||||
1: '1px',
|
||||
},
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
:root {
|
||||
--color-h: 0;
|
||||
--color-s: 0%;
|
||||
--color-l: 0%;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
declare global {
|
||||
interface Window {
|
||||
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: any;
|
||||
}
|
||||
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
ENDPOINT_BASE_URL: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default global;
|
5
source/ui/src/types/next-env.d.ts
vendored
Normal file
5
source/ui/src/types/next-env.d.ts
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
8
source/ui/src/types/yup.d.ts
vendored
8
source/ui/src/types/yup.d.ts
vendored
|
@ -1,8 +0,0 @@
|
|||
// @ts-nocheck
|
||||
import { StringSchema } from 'yup';
|
||||
|
||||
declare module 'yup' {
|
||||
interface StringSchema {
|
||||
// place custom Yup definition of validation
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
// @ts-nocheck
|
||||
// place import for custom Yup validations
|
||||
|
||||
import * as Yup from 'yup';
|
||||
import * as Yup from 'src/utils/yup';
|
||||
|
||||
Yup.setLocale({
|
||||
mixed: {
|
||||
|
|
9
source/ui/tests/nightwatchjs.d.ts
vendored
9
source/ui/tests/nightwatchjs.d.ts
vendored
|
@ -1,9 +0,0 @@
|
|||
import { Definition } from 'nightwatch';
|
||||
|
||||
declare module 'nightwatch' {
|
||||
interface NightwatchCustomPageObjects {
|
||||
}
|
||||
|
||||
export interface NightwatchCustomCommands {
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": ".nightwatchjs",
|
||||
"baseUrl": ".",
|
||||
"rootDir": ".",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "commonjs",
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": false,
|
||||
"target": "es6",
|
||||
"lib": [
|
||||
"es6",
|
||||
],
|
||||
},
|
||||
"files": [
|
||||
"./nightwatchjs.d.ts"
|
||||
],
|
||||
"include": [
|
||||
"./**/*.ts",
|
||||
]
|
||||
}
|
Loading…
Add table
Reference in a new issue