Compare commits
21 Commits
lerna
...
vercel-tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a854b42ce5 | ||
|
|
228ae71a1c | ||
|
|
71a8d3e77f | ||
|
|
4ddeb927cc | ||
|
|
72c1685fa6 | ||
|
|
7e7ee24109 | ||
|
|
708d971717 | ||
|
|
7781d092ca | ||
|
|
d0e84fb51a | ||
|
|
0e673ffa7c | ||
|
|
4c4c73db2d | ||
|
|
0086ee5186 | ||
|
|
bb49fcb42b | ||
|
|
d47b1165c4 | ||
|
|
f2e1efcb45 | ||
|
|
2e3b2cbf92 | ||
|
|
68e61429aa | ||
|
|
646be4bb20 | ||
|
|
dfd8b0ca4e | ||
|
|
2ab1a5606a | ||
|
|
c33370d4d2 |
5
.github/workflows/docker-build.yml
vendored
5
.github/workflows/docker-build.yml
vendored
@@ -19,7 +19,7 @@ on:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: abouhuolia/bigcapital-client
|
||||
IMAGE_NAME: abouhuolia/bigcapital-webapp
|
||||
|
||||
jobs:
|
||||
setup-build-publish-deploy:
|
||||
@@ -50,8 +50,9 @@ jobs:
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./packages/webapp/Dockerfile
|
||||
push: true
|
||||
tags: ghcr.io/bigcapitalhq/client:latest
|
||||
tags: ghcr.io/bigcapitalhq/webapp:latest
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
# Send notification to Slack channel.
|
||||
- name: Slack Notification built and published successfully.
|
||||
|
||||
4
.husky/commit-msg
Normal file
4
.husky/commit-msg
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
yarn commitlint --edit
|
||||
2
.husky/pre-commit
Normal file
2
.husky/pre-commit
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
5
.vercelignore
Normal file
5
.vercelignore
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
!package.json
|
||||
!package-lock.json
|
||||
!yarn.lock
|
||||
!packages/webapp
|
||||
0
bin/.gitkeep
Normal file
0
bin/.gitkeep
Normal file
1
commitlint.config.js
Normal file
1
commitlint.config.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: ['@commitlint/config-lerna-scopes'] };
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||
"useWorkspaces": true,
|
||||
"version": "0.0.0"
|
||||
"version": "0.0.0",
|
||||
"npmClient": "npm"
|
||||
}
|
||||
|
||||
26
package.json
26
package.json
@@ -6,17 +6,29 @@
|
||||
"dev": "lerna run dev",
|
||||
"build": "lerna run build",
|
||||
"dev:webapp": "lerna run dev --scope \"@bigcapital/webapp\"",
|
||||
"build:webapp": "lerna run dev --scope \"@bigcapital/webapp\"",
|
||||
"build:webapp": "lerna run build --scope \"@bigcapital/webapp\"",
|
||||
"dev:server": "lerna run dev --scope \"@bigcapital/server\"",
|
||||
"build:server": "lerna run dev --scope \"@bigcapital/server\""
|
||||
"build:server": "lerna run build --scope \"@bigcapital/server\"",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
"packages/*",
|
||||
"shared/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"lerna": "^6.4.1"
|
||||
"@commitlint/config-conventional": "^17.4.2",
|
||||
"@commitlint/config-lerna-scopes": "^17.4.2",
|
||||
"husky": "^8.0.3",
|
||||
"lerna": "^6.4.1",
|
||||
"@commitlint/cli": "^17.4.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.20"
|
||||
}
|
||||
}
|
||||
"node": "14.x"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"dependencies": {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# @bigcapital/server
|
||||
@@ -1,94 +0,0 @@
|
||||
import Knex from 'knex';
|
||||
import { knexSnakeCaseMappers } from 'objection';
|
||||
import color from 'colorette';
|
||||
import config from '../src/config';
|
||||
// import { systemKnexConfig } from '../src/config/knexConfig';
|
||||
|
||||
function initSystemKnex() {
|
||||
return Knex({
|
||||
client: config.system.db_client,
|
||||
connection: {
|
||||
host: config.system.db_host,
|
||||
user: config.system.db_user,
|
||||
password: config.system.db_password,
|
||||
database: config.system.db_name,
|
||||
charset: 'utf8',
|
||||
},
|
||||
migrations: {
|
||||
directory: config.system.migrations_dir,
|
||||
},
|
||||
seeds: {
|
||||
directory: config.system.seeds_dir,
|
||||
},
|
||||
pool: { min: 0, max: 7 },
|
||||
...knexSnakeCaseMappers({ upperCase: true }),
|
||||
});
|
||||
}
|
||||
|
||||
function getAllSystemTenants(knex) {
|
||||
return knex('tenants');
|
||||
}
|
||||
|
||||
function initTenantKnex(organizationId) {
|
||||
return Knex({
|
||||
client: config.tenant.db_client,
|
||||
connection: {
|
||||
host: config.tenant.db_host,
|
||||
user: config.tenant.db_user,
|
||||
password: config.tenant.db_password,
|
||||
database: `${config.tenant.db_name_prefix}${organizationId}`,
|
||||
charset: config.tenant.charset,
|
||||
},
|
||||
migrations: {
|
||||
directory: config.tenant.migrations_dir,
|
||||
},
|
||||
seeds: {
|
||||
directory: config.tenant.seeds_dir,
|
||||
},
|
||||
pool: { min: 0, max: 5 },
|
||||
...knexSnakeCaseMappers({ upperCase: true }),
|
||||
})
|
||||
}
|
||||
|
||||
function exit(text) {
|
||||
if (text instanceof Error) {
|
||||
console.error(
|
||||
color.red(`${text.detail ? `${text.detail}\n` : ''}${text.stack}`)
|
||||
);
|
||||
} else {
|
||||
console.error(color.red(text));
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function success(text) {
|
||||
console.log(text);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function log(text) {
|
||||
console.log(text);
|
||||
}
|
||||
|
||||
function getDeepValue(prop, obj) {
|
||||
if (!Object.keys(obj).length) { return []; }
|
||||
|
||||
return Object.entries(obj).reduce((acc, [key, val]) => {
|
||||
if (key === prop) {
|
||||
acc.push(val);
|
||||
} else {
|
||||
acc.push(Array.isArray(val) ? val.map(getIds).flat() : getIds(val));
|
||||
}
|
||||
return acc.flat();
|
||||
}, []);
|
||||
}
|
||||
|
||||
export {
|
||||
initTenantKnex,
|
||||
initSystemKnex,
|
||||
getAllSystemTenants,
|
||||
exit,
|
||||
success,
|
||||
log,
|
||||
getDeepValue,
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "bigcapital-server",
|
||||
"name": "@bigcapital/server",
|
||||
"version": "1.7.1",
|
||||
"description": "",
|
||||
"main": "src/server.ts",
|
||||
@@ -8,7 +8,9 @@
|
||||
"clear": "rimraf build",
|
||||
"dev": "cross-env NODE_ENV=development webpack --config scripts/webpack.config.js",
|
||||
"build:resources": "gulp --gulpfile=scripts/gulpfile.js styles styles-rtl",
|
||||
"build": "cross-env NODE_ENV=production webpack --config scripts/webpack.config.js",
|
||||
"build:app": "cross-env NODE_ENV=production webpack --config scripts/webpack.config.js",
|
||||
"build:commands": "cross-env NODE_ENV=production webpack --config scripts/webpack.cli.js",
|
||||
"build": "npm-run-all build:*",
|
||||
"lint:fix": "eslint --fix ./**/*.ts"
|
||||
},
|
||||
"author": "Ahmed Bouhuolia, <a.bouhuolia@gmail.com>",
|
||||
|
||||
11
packages/server/scripts/webpack.cli.js
Normal file
11
packages/server/scripts/webpack.cli.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const { getCommonWebpackOptions } = require('./webpack.common');
|
||||
|
||||
const inputEntry = './src/commands/index.ts';
|
||||
const outputDir = '../build';
|
||||
const outputFilename = 'commands.js';
|
||||
|
||||
module.exports = getCommonWebpackOptions({
|
||||
inputEntry,
|
||||
outputDir,
|
||||
outputFilename,
|
||||
});
|
||||
76
packages/server/scripts/webpack.common.js
Normal file
76
packages/server/scripts/webpack.common.js
Normal file
@@ -0,0 +1,76 @@
|
||||
const path = require('path');
|
||||
const { NormalModuleReplacementPlugin } = require('webpack');
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
exports.getCommonWebpackOptions = ({
|
||||
inputEntry,
|
||||
outputDir,
|
||||
outputFilename,
|
||||
}) => {
|
||||
const webpackOptions = {
|
||||
entry: ['regenerator-runtime/runtime', inputEntry],
|
||||
target: 'node',
|
||||
mode: isDev ? 'development' : 'production',
|
||||
watch: isDev,
|
||||
watchOptions: {
|
||||
aggregateTimeout: 200,
|
||||
poll: 1000,
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, outputDir),
|
||||
filename: outputFilename,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js'],
|
||||
extensionAlias: {
|
||||
'.ts': ['.js', '.ts'],
|
||||
'.cts': ['.cjs', '.cts'],
|
||||
'.mts': ['.mjs', '.mts'],
|
||||
},
|
||||
plugins: [
|
||||
new TsconfigPathsPlugin({
|
||||
configFile: './tsconfig.json',
|
||||
extensions: ['.ts', '.tsx', '.js'],
|
||||
}),
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// Ignore knex dynamic required dialects that we don't use
|
||||
new NormalModuleReplacementPlugin(
|
||||
/m[sy]sql2?|oracle(db)?|sqlite3|pg-(native|query)/,
|
||||
'noop2'
|
||||
),
|
||||
new ProgressBarPlugin(),
|
||||
],
|
||||
externals: [nodeExternals(), 'aws-sdk', 'prettier'],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.([cm]?ts|tsx|js)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
configFile: 'tsconfig.json',
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: /(node_modules)/,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if (isDev) {
|
||||
webpackOptions.plugins.push(
|
||||
new RunScriptWebpackPlugin({ name: outputFilename })
|
||||
);
|
||||
}
|
||||
return webpackOptions;
|
||||
};
|
||||
@@ -1,74 +1,11 @@
|
||||
const path = require('path');
|
||||
const { NormalModuleReplacementPlugin } = require('webpack');
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
|
||||
const { getCommonWebpackOptions } = require('./webpack.common');
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
const inputEntry = './src/server.ts';
|
||||
const outputDir = '../build';
|
||||
const outputFilename = 'index.js';
|
||||
const inputEntry = './src/server.ts';
|
||||
|
||||
const webpackOptions = {
|
||||
entry: ['regenerator-runtime/runtime', inputEntry],
|
||||
target: 'node',
|
||||
mode: isDev ? 'development' : 'production',
|
||||
watch: isDev,
|
||||
watchOptions: {
|
||||
aggregateTimeout: 200,
|
||||
poll: 1000,
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, outputDir),
|
||||
filename: outputFilename,
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js'],
|
||||
extensionAlias: {
|
||||
'.ts': ['.js', '.ts'],
|
||||
'.cts': ['.cjs', '.cts'],
|
||||
'.mts': ['.mjs', '.mts'],
|
||||
},
|
||||
plugins: [
|
||||
new TsconfigPathsPlugin({
|
||||
configFile: './tsconfig.json',
|
||||
extensions: ['.ts', '.tsx', '.js'],
|
||||
}),
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// Ignore knex dynamic required dialects that we don't use
|
||||
new NormalModuleReplacementPlugin(
|
||||
/m[sy]sql2?|oracle(db)?|sqlite3|pg-(native|query)/,
|
||||
'noop2'
|
||||
),
|
||||
new ProgressBarPlugin(),
|
||||
],
|
||||
externals: [nodeExternals(), 'aws-sdk', 'prettier'],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.([cm]?ts|tsx|js)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
configFile: 'tsconfig.json',
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: /(node_modules)/,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if (isDev) {
|
||||
webpackOptions.plugins.push(
|
||||
new RunScriptWebpackPlugin({ name: outputFilename })
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = webpackOptions;
|
||||
module.exports = getCommonWebpackOptions({
|
||||
inputEntry,
|
||||
outputDir,
|
||||
outputFilename,
|
||||
});
|
||||
|
||||
@@ -1,15 +1,81 @@
|
||||
#!/usr/bin/env node
|
||||
import commander from 'commander';
|
||||
import color from 'colorette';
|
||||
import argv from 'getopts'
|
||||
import config from '../src/config';
|
||||
import {
|
||||
initSystemKnex,
|
||||
getAllSystemTenants,
|
||||
initTenantKnex,
|
||||
exit,
|
||||
success,
|
||||
log,
|
||||
} from './utils';
|
||||
import argv from 'getopts';
|
||||
import Knex from 'knex';
|
||||
import { knexSnakeCaseMappers } from 'objection';
|
||||
import config from '../config';
|
||||
|
||||
function initSystemKnex() {
|
||||
return Knex({
|
||||
client: config.system.db_client,
|
||||
connection: {
|
||||
host: config.system.db_host,
|
||||
user: config.system.db_user,
|
||||
password: config.system.db_password,
|
||||
database: config.system.db_name,
|
||||
charset: 'utf8',
|
||||
},
|
||||
migrations: {
|
||||
directory: config.system.migrations_dir,
|
||||
},
|
||||
seeds: {
|
||||
directory: config.system.seeds_dir,
|
||||
},
|
||||
pool: { min: 0, max: 7 },
|
||||
...knexSnakeCaseMappers({ upperCase: true }),
|
||||
});
|
||||
}
|
||||
|
||||
function initTenantKnex(organizationId) {
|
||||
return Knex({
|
||||
client: config.tenant.db_client,
|
||||
connection: {
|
||||
host: config.tenant.db_host,
|
||||
user: config.tenant.db_user,
|
||||
password: config.tenant.db_password,
|
||||
database: `${config.tenant.db_name_prefix}${organizationId}`,
|
||||
charset: config.tenant.charset,
|
||||
},
|
||||
migrations: {
|
||||
directory: config.tenant.migrations_dir,
|
||||
},
|
||||
seeds: {
|
||||
directory: config.tenant.seeds_dir,
|
||||
},
|
||||
pool: { min: 0, max: 5 },
|
||||
...knexSnakeCaseMappers({ upperCase: true }),
|
||||
});
|
||||
}
|
||||
function exit(text) {
|
||||
if (text instanceof Error) {
|
||||
console.error(
|
||||
color.red(`${text.detail ? `${text.detail}\n` : ''}${text.stack}`)
|
||||
);
|
||||
} else {
|
||||
console.error(color.red(text));
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function success(text) {
|
||||
console.log(text);
|
||||
process.exit(0);
|
||||
}
|
||||
function log(text) {
|
||||
console.log(text);
|
||||
}
|
||||
|
||||
function getAllSystemTenants(knex) {
|
||||
return knex('tenants');
|
||||
}
|
||||
|
||||
// module.exports = {
|
||||
// log,
|
||||
// success,
|
||||
// exit,
|
||||
// initSystemKnex,
|
||||
// };
|
||||
|
||||
// - bigcapital system:migrate:latest
|
||||
// - bigcapital system:migrate:rollback
|
||||
@@ -17,12 +83,12 @@ import {
|
||||
// - bigcapital tenants:migrate:latest --tenant_id=XXX
|
||||
// - bigcapital tenants:migrate:rollback
|
||||
// - bigcapital tenants:migrate:rollback --tenant_id=XXX
|
||||
// - bigcapital tenants:migrate:make
|
||||
// - bigcapital system:migrate:make
|
||||
// - bigcapital tenants:migrate:make
|
||||
// - bigcapital system:migrate:make
|
||||
// - bigcapital tenants:list
|
||||
|
||||
commander
|
||||
.command('system:migrate:rollback')
|
||||
.command('system:migrate:rollback')
|
||||
.description('Migrate the system database of the application.')
|
||||
.action(async () => {
|
||||
try {
|
||||
@@ -33,18 +99,17 @@ commander
|
||||
success(color.cyan('Already at the base migration'));
|
||||
}
|
||||
success(
|
||||
color.green(
|
||||
`Batch ${batchNo} rolled back: ${_log.length} migrations`
|
||||
) + (argv.verbose ? `\n${color.cyan(_log.join('\n'))}` : '')
|
||||
color.green(`Batch ${batchNo} rolled back: ${_log.length} migrations`) +
|
||||
(argv.verbose ? `\n${color.cyan(_log.join('\n'))}` : '')
|
||||
);
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
exit(error);
|
||||
}
|
||||
});
|
||||
|
||||
commander
|
||||
.command('system:migrate:latest')
|
||||
.description('Rollback latest mgiration of the system database.')
|
||||
.description('Migrate latest mgiration of the system database.')
|
||||
.action(async () => {
|
||||
try {
|
||||
const sysKnex = await initSystemKnex();
|
||||
@@ -57,7 +122,7 @@ commander
|
||||
color.green(`Batch ${batchNo} run: ${log.length} migrations`) +
|
||||
(argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
|
||||
);
|
||||
} catch(error) {
|
||||
} catch (error) {
|
||||
exit(error);
|
||||
}
|
||||
});
|
||||
@@ -67,85 +132,47 @@ commander
|
||||
.description('Created a named migration file to the system database.')
|
||||
.action(async (name) => {
|
||||
const sysKnex = await initSystemKnex();
|
||||
|
||||
sysKnex.migrate.make(name).then((name) => {
|
||||
success(color.green(`Created Migration: ${name}`));
|
||||
}).catch(exit)
|
||||
});
|
||||
|
||||
commander
|
||||
.command('tenants:migrate:make <name>')
|
||||
.description('Created a name migration file to the tenants databases.')
|
||||
.action(async (name) => {
|
||||
const sysKnex = await initTenantKnex();
|
||||
|
||||
sysKnex.migrate.make(name).then((name) => {
|
||||
success(color.green(`Created Migration: ${name}`));
|
||||
}).catch(exit)
|
||||
sysKnex.migrate
|
||||
.make(name)
|
||||
.then((name) => {
|
||||
success(color.green(`Created Migration: ${name}`));
|
||||
})
|
||||
.catch(exit);
|
||||
});
|
||||
|
||||
commander
|
||||
.command('tenants:list')
|
||||
.description('Retrieve a list of all system tenants databases.')
|
||||
.action(async (cmd) => {
|
||||
try{
|
||||
try {
|
||||
const sysKnex = await initSystemKnex();
|
||||
const tenants = await getAllSystemTenants(sysKnex);
|
||||
|
||||
tenants.forEach((tenant) => {
|
||||
const dbName = `${config.tenant.db_name_prefix}${tenant.organizationId}`;
|
||||
console.log(`ID: ${tenant.id} | Organization ID: ${tenant.organizationId} | DB Name: ${dbName}`);
|
||||
console.log(
|
||||
`ID: ${tenant.id} | Organization ID: ${tenant.organizationId} | DB Name: ${dbName}`
|
||||
);
|
||||
});
|
||||
} catch(error) { exit(error); };
|
||||
} catch (error) {
|
||||
exit(error);
|
||||
}
|
||||
success('---');
|
||||
});
|
||||
|
||||
commander
|
||||
.command('tenants:migrate:rollback')
|
||||
.description('Rollback the last batch of tenants migrations.')
|
||||
.option('-t, --tenant_id [tenant_id]', 'Which tenant id do you migrate.')
|
||||
.action(async (cmd) => {
|
||||
try {
|
||||
const sysKnex = await initSystemKnex();
|
||||
const tenants = await getAllSystemTenants(sysKnex);
|
||||
const tenantsOrgsIds = tenants.map((tenant) => tenant.organizationId);
|
||||
.command('tenants:migrate:make <name>')
|
||||
.description('Created a named migration file to the tenants database.')
|
||||
.action(async (name) => {
|
||||
const sysKnex = await initTenantKnex();
|
||||
|
||||
if (cmd.tenant_id && tenantsOrgsIds.indexOf(cmd.tenant_id) === -1) {
|
||||
exit(`The given tenant id ${cmd.tenant_id} is not exists.`);
|
||||
}
|
||||
|
||||
const migrateOpers = [];
|
||||
const migrateTenant = async (organizationId) => {
|
||||
try {
|
||||
const tenantKnex = await initTenantKnex(organizationId);
|
||||
const [batchNo, _log] = await tenantKnex.migrate.rollback();
|
||||
const tenantDb = `${config.tenant.db_name_prefix}${organizationId}`;
|
||||
|
||||
if (_log.length === 0) {
|
||||
log(color.cyan('Already at the base migration'));
|
||||
}
|
||||
log(
|
||||
color.green(
|
||||
`Tenant: ${tenantDb} > Batch ${batchNo} rolled back: ${_log.length} migrations`
|
||||
) + (argv.verbose ? `\n${color.cyan(_log.join('\n'))}` : '')
|
||||
);
|
||||
log('---------------');
|
||||
} catch (error) { exit(error); }
|
||||
};
|
||||
|
||||
if (!cmd.tenant_id) {
|
||||
tenants.forEach((tenant) => {
|
||||
const oper = migrateTenant(tenant.organizationId);
|
||||
migrateOpers.push(oper);
|
||||
});
|
||||
} else {
|
||||
const oper = migrateTenant(cmd.tenant_id);
|
||||
migrateOpers.push(oper);
|
||||
}
|
||||
Promise.all(migrateOpers).then(() => {
|
||||
success('All tenants are rollbacked.');
|
||||
});
|
||||
} catch (error) { exit(error); }
|
||||
sysKnex.migrate
|
||||
.make(name)
|
||||
.then((name) => {
|
||||
success(color.green(`Created Migration: ${name}`));
|
||||
})
|
||||
.catch(exit);
|
||||
});
|
||||
|
||||
commander
|
||||
@@ -156,8 +183,8 @@ commander
|
||||
try {
|
||||
const sysKnex = await initSystemKnex();
|
||||
const tenants = await getAllSystemTenants(sysKnex);
|
||||
const tenantsOrgsIds = tenants.map(tenant => tenant.organizationId);
|
||||
|
||||
const tenantsOrgsIds = tenants.map((tenant) => tenant.organizationId);
|
||||
|
||||
if (cmd.tenant_id && tenantsOrgsIds.indexOf(cmd.tenant_id) === -1) {
|
||||
exit(`The given tenant id ${cmd.tenant_id} is not exists.`);
|
||||
}
|
||||
@@ -174,14 +201,15 @@ commander
|
||||
log(color.cyan('Already up to date'));
|
||||
}
|
||||
log(
|
||||
color.green(`Tenant ${tenantDb} > Batch ${batchNo} run: ${_log.length} migrations`) +
|
||||
(argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
|
||||
color.green(
|
||||
`Tenant ${tenantDb} > Batch ${batchNo} run: ${_log.length} migrations`
|
||||
) + (argv.verbose ? `\n${color.cyan(log.join('\n'))}` : '')
|
||||
);
|
||||
log('-------------------');
|
||||
} catch (error) {
|
||||
log(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!cmd.tenant_id) {
|
||||
tenants.forEach((tenant) => {
|
||||
const oper = migrateTenant(tenant.organizationId);
|
||||
@@ -200,4 +228,55 @@ commander
|
||||
}
|
||||
});
|
||||
|
||||
commander.parse(process.argv);
|
||||
commander
|
||||
.command('tenants:migrate:rollback')
|
||||
.description('Rollback the last batch of tenants migrations.')
|
||||
.option('-t, --tenant_id [tenant_id]', 'Which tenant id do you migrate.')
|
||||
.action(async (cmd) => {
|
||||
try {
|
||||
const sysKnex = await initSystemKnex();
|
||||
const tenants = await getAllSystemTenants(sysKnex);
|
||||
const tenantsOrgsIds = tenants.map((tenant) => tenant.organizationId);
|
||||
|
||||
if (cmd.tenant_id && tenantsOrgsIds.indexOf(cmd.tenant_id) === -1) {
|
||||
exit(`The given tenant id ${cmd.tenant_id} is not exists.`);
|
||||
}
|
||||
|
||||
const migrateOpers = [];
|
||||
const migrateTenant = async (organizationId) => {
|
||||
try {
|
||||
const tenantKnex = await initTenantKnex(organizationId);
|
||||
const [batchNo, _log] = await tenantKnex.migrate.rollback();
|
||||
const tenantDb = `${config.tenant.db_name_prefix}${organizationId}`;
|
||||
|
||||
if (_log.length === 0) {
|
||||
log(color.cyan('Already at the base migration'));
|
||||
}
|
||||
log(
|
||||
color.green(
|
||||
`Tenant: ${tenantDb} > Batch ${batchNo} rolled back: ${_log.length} migrations`
|
||||
) + (argv.verbose ? `\n${color.cyan(_log.join('\n'))}` : '')
|
||||
);
|
||||
log('---------------');
|
||||
} catch (error) {
|
||||
exit(error);
|
||||
}
|
||||
};
|
||||
|
||||
if (!cmd.tenant_id) {
|
||||
tenants.forEach((tenant) => {
|
||||
const oper = migrateTenant(tenant.organizationId);
|
||||
migrateOpers.push(oper);
|
||||
});
|
||||
} else {
|
||||
const oper = migrateTenant(cmd.tenant_id);
|
||||
migrateOpers.push(oper);
|
||||
}
|
||||
Promise.all(migrateOpers).then(() => {
|
||||
success('All tenants are rollbacked.');
|
||||
});
|
||||
} catch (error) {
|
||||
exit(error);
|
||||
}
|
||||
});
|
||||
|
||||
4
packages/server/src/commands/index.ts
Normal file
4
packages/server/src/commands/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import commander from 'commander';
|
||||
import './bigcapital';
|
||||
|
||||
commander.parse();
|
||||
@@ -9,7 +9,7 @@ if (envFound.error) {
|
||||
throw new Error("⚠️ Couldn't find .env file ⚠️");
|
||||
}
|
||||
|
||||
export default {
|
||||
module.exports = {
|
||||
/**
|
||||
* Your favorite port
|
||||
*/
|
||||
|
||||
@@ -6,4 +6,4 @@ class HttpException extends Error {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
export default class PaymentInputInvalid {
|
||||
constructor() {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import ServiceError from './ServiceError';
|
||||
|
||||
|
||||
export default class ServiceErrors {
|
||||
errors: ServiceError[];
|
||||
|
||||
@@ -9,7 +8,8 @@ export default class ServiceErrors {
|
||||
}
|
||||
|
||||
hasType(errorType: string) {
|
||||
return this.errors
|
||||
.some((error: ServiceError) => error.errorType === errorType);
|
||||
return this.errors.some(
|
||||
(error: ServiceError) => error.errorType === errorType
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
|
||||
|
||||
export default class TenantAlreadyInitialized {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
|
||||
|
||||
|
||||
|
||||
export default class TenantAlreadySeeded {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
|
||||
|
||||
export default class TenantDatabaseNotBuilt {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
export default class VoucherCodeRequired {
|
||||
constructor() {
|
||||
this.name = 'VoucherCodeRequired';
|
||||
|
||||
@@ -5,6 +5,9 @@ import './before';
|
||||
import express from 'express';
|
||||
import loadersFactory from 'loaders';
|
||||
|
||||
|
||||
console.log("asdfasf");
|
||||
|
||||
async function startServer() {
|
||||
const app = express();
|
||||
|
||||
|
||||
@@ -4,17 +4,20 @@ USER root
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./package.json /app/package.json
|
||||
COPY ./package-lock.json /app/package-lock.json
|
||||
# Install dependencies
|
||||
COPY package.json ./
|
||||
COPY lerna.json ./
|
||||
|
||||
COPY ./packages/webapp/package.json /app/packages/webapp/package.json
|
||||
|
||||
RUN npm install
|
||||
RUN npm run bootstrap
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
# Build webapp package
|
||||
COPY ./packages/webapp /app/packages/webapp
|
||||
RUN npm run build:webapp
|
||||
|
||||
FROM nginx
|
||||
|
||||
COPY ./nginx/sites/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
COPY --from=build /app/build /usr/share/nginx/html
|
||||
COPY ./packages/webapp/nginx/sites/default.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/packages/webapp/build /usr/share/nginx/html
|
||||
|
||||
@@ -1,68 +1 @@
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.<br />
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||
|
||||
The page will reload if you make edits.<br />
|
||||
You will also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.<br />
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.<br />
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.<br />
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
|
||||
|
||||
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
|
||||
|
||||
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
|
||||
# @bigcapital/webapp
|
||||
44
packages/webapp/package-lock.json
generated
44
packages/webapp/package-lock.json
generated
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@bigcapital/webpack",
|
||||
"name": "@bigcapital/webapp",
|
||||
"version": "1.7.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
@@ -1144,6 +1144,11 @@
|
||||
"@babel/plugin-transform-typescript": "^7.9.0"
|
||||
}
|
||||
},
|
||||
"@babel/regjsgen": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
|
||||
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.20.13",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
|
||||
@@ -3516,9 +3521,9 @@
|
||||
}
|
||||
},
|
||||
"async-each": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.5.tgz",
|
||||
"integrity": "sha512-5QzqtU3BlagehwmdoqwaS2FBQF2P5eL6vFqXwNsb5jwoEsmtfAXg1ocFvW7I6/gGLFhBMKwcMwZuy7uv/Bo9jA=="
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz",
|
||||
"integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg=="
|
||||
},
|
||||
"async-foreach": {
|
||||
"version": "0.1.3",
|
||||
@@ -4681,9 +4686,9 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001450",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001450.tgz",
|
||||
"integrity": "sha512-qMBmvmQmFXaSxexkjjfMvD5rnDL0+m+dUMZKoDYsGG8iZN29RuYh9eRoMvKsT6uMAWlyUUGDEQGJJYjzCIO9ew=="
|
||||
"version": "1.0.30001451",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz",
|
||||
"integrity": "sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w=="
|
||||
},
|
||||
"capture-exit": {
|
||||
"version": "2.0.0",
|
||||
@@ -6015,9 +6020,9 @@
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.285",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.285.tgz",
|
||||
"integrity": "sha512-47o4PPgxfU1KMNejz+Dgaodf7YTcg48uOfV1oM6cs3adrl2+7R+dHkt3Jpxqo0LRCbGJEzTKMUt0RdvByb/leg=="
|
||||
"version": "1.4.289",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.289.tgz",
|
||||
"integrity": "sha512-relLdMfPBxqGCxy7Gyfm1HcbRPcFUJdlgnCPVgQ23sr1TvUrRJz0/QPoGP0+x41wOVSTN/Wi3w6YDgHiHJGOzg=="
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.5.4",
|
||||
@@ -10984,9 +10989,9 @@
|
||||
}
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.9.tgz",
|
||||
"integrity": "sha512-2xfmOrRkGogbTK9R6Leda0DGiXeY3p2NJpy4+gNCffdUvV6mdEJnaDEic1i3Ec2djAo8jWYoJMR5PB0MSMpxUA=="
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
|
||||
"integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
|
||||
},
|
||||
"node-sass": {
|
||||
"version": "4.14.1",
|
||||
@@ -14129,23 +14134,18 @@
|
||||
"integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="
|
||||
},
|
||||
"regexpu-core": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz",
|
||||
"integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.0.tgz",
|
||||
"integrity": "sha512-ZdhUQlng0RoscyW7jADnUZ25F5eVtHdMyXSb2PiwafvteRAOJUjFoUPEYZSIfP99fBIs3maLIRfpEddT78wAAQ==",
|
||||
"requires": {
|
||||
"@babel/regjsgen": "^0.8.0",
|
||||
"regenerate": "^1.4.2",
|
||||
"regenerate-unicode-properties": "^10.1.0",
|
||||
"regjsgen": "^0.7.1",
|
||||
"regjsparser": "^0.9.1",
|
||||
"unicode-match-property-ecmascript": "^2.0.0",
|
||||
"unicode-match-property-value-ecmascript": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"regjsgen": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz",
|
||||
"integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA=="
|
||||
},
|
||||
"regjsparser": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
|
||||
|
||||
0
shared/.gitkeep
Normal file
0
shared/.gitkeep
Normal file
9
vercel.json
Normal file
9
vercel.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"buildCommand": "npm run build:webapp",
|
||||
"devCommand": "npm run dev:webapp",
|
||||
"installCommand": "npm install && npm run bootstrap",
|
||||
"outputDirectory": "packages/webapp/build",
|
||||
"env": {
|
||||
"CI": "false"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user