diff --git a/.env.example b/.env.example
index ca4be82d1..59e64cb14 100644
--- a/.env.example
+++ b/.env.example
@@ -48,6 +48,9 @@ SIGNUP_DISABLED=false
SIGNUP_ALLOWED_DOMAINS=
SIGNUP_ALLOWED_EMAILS=
+# Sign-up Email Confirmation
+SIGNUP_EMAIL_CONFIRMATION=false
+
# API rate limit (points,duration,block duration).
API_RATE_LIMIT=120,60,600
diff --git a/.github/workflows/build-deploy-container.yml b/.github/workflows/build-deploy-container.yml
index d4c423b4f..8619f0ecf 100644
--- a/.github/workflows/build-deploy-container.yml
+++ b/.github/workflows/build-deploy-container.yml
@@ -14,10 +14,6 @@ jobs:
build-publish-webapp:
strategy:
fail-fast: false
- matrix:
- platform:
- - linux/amd64
- - linux/arm64
name: Build and deploy webapp container
runs-on: ubuntu-latest
environment: production
@@ -30,9 +26,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -40,15 +33,14 @@ jobs:
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
- registry: ${{ env.REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GH_TOKEN }}
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
- images: ${{ env.REGISTRY }}/${{ env.WEBAPP_IMAGE_NAME }}
+ images: ${{ env.WEBAPP_IMAGE_NAME }}
# Builds and push the Docker image.
- name: Build and push Docker image
@@ -57,10 +49,11 @@ jobs:
with:
context: ./
file: ./packages/webapp/Dockerfile
- platforms: ${{ matrix.platform }}
+ platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/poudelprakash/webapp:latest, ghcr.io/poudelprakash/webapp:${{github.ref_name}}
labels: ${{ steps.meta.outputs.labels }}
+ tags: bigcapitalhq/webapp:latest, bigcapitalhq/webapp:${{github.ref_name}}
- name: Export digest
run: |
@@ -71,7 +64,7 @@ jobs:
- name: Upload digest
uses: actions/upload-artifact@v4
with:
- name: digests-main-${{ env.PLATFORM_PAIR }}
+ name: digests-webapp
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
@@ -93,9 +86,6 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -103,9 +93,8 @@ jobs:
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
- registry: ${{ env.REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ secrets.GH_TOKEN }}
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
# Builds and push the Docker image.
- name: Build and push Docker image
@@ -114,7 +103,7 @@ jobs:
with:
context: ./
file: ./packages/server/Dockerfile
- platforms: ${{ matrix.platform }}
+ platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/poudelprakash/server:latest, ghcr.io/poudelprakash/server:${{github.ref_name}}
labels: ${{ steps.meta.outputs.labels }}
@@ -128,11 +117,11 @@ jobs:
- name: Upload digest
uses: actions/upload-artifact@v4
with:
- name: digests-main-${{ env.PLATFORM_PAIR }}
+ name: digests-server
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
-
+
# Send notification to Slack channel.
# - name: Slack Notification built and published server container successfully.
# uses: rtCamp/action-slack-notify@v2
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae75e5f45..eaaa61f99 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,76 @@
All notable changes to Bigcapital server-side will be in this file.
+## [0.16.11] - 06-05-2024
+
+### improvements
+
+* feat: Export resource data to csv, xlsx by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/430
+* feat: User email verification after signing-up. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/426
+
+### Fixes
+* feat(repo): upgrade to latest lerna v8 and pnpm v9 by @benpsnyder in https://github.com/bigcapitalhq/bigcapital/pull/414
+* feat: Update Docker Build-Push Action and Add ARM64 Support by @cloudsbird in https://github.com/bigcapitalhq/bigcapital/pull/412
+* feat: Pushing docker containers by version tag by @cloudsbird in https://github.com/bigcapitalhq/bigcapital/pull/421
+
+## [0.16.10]
+
+* fix: Running migration Docker container on Windows by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/432
+
+## [0.16.9]
+
+* feat: New Relic for tracking by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/429
+
+## [0.16.8]
+
+* feat: Ability to enable/disable the bank connect feature by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/423
+
+## [0.16.6]
+
+* hotfix: fix the subscription plan when subscribe on cloud by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/422
+
+## [0.16.5]
+
+IMPORTANT: If you upgraded to the v0.16 recently you should upgrade to v0.16.4 as soon as possible, because there're some breaking changes affected the sign-in and some users reported couldn't sign-in.
+
+* feat: Seed free subscription to tenants that have no subscription. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/410
+
+## [0.16.3]
+
+* feat: Integrate Lemon Squeezy payment by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/402
+* feat: optimize the onboarding subscription experience. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/404
+* feat: subscription page content by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/405
+* feat: auto subscribe to free plan once signup on community version. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/406
+* chore: add default value to env variable by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/407
+* fix: absolute storage imports path. by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/408
+
+## [0.16.0]
+
+* feat: add convert to invoice button on estimate drawer toolbar by @ANasouf in https://github.com/bigcapitalhq/bigcapital/pull/361
+* feat(webapp): add mark as delivered to action bar of invoice details … by @ANasouf in https://github.com/bigcapitalhq/bigcapital/pull/360
+* feat(webapp): Dialog to choose the bank service provider by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/378
+* feat: Categorize the bank synced transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/377
+* feat: uncategorize the cashflow transaction by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/381
+* Import resources from csv/xlsx by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/382
+* feat(webapp): import resource UI by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/386
+* fix: import resources improvements by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/388
+* feat: add sample sheet to accounts and bank transactions by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/389
+* fix: show the unique row value in the import preview by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/392
+* feat: advanced parser for numeric and boolean import values by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/394
+* feat: validate the given imported sheet whether is empty by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/395
+* feat: linking relation with id in importing by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/393
+* feat: Aggregate rows import by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/396
+* feat: clean up the imported temp files by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/400
+* feat: add hints to import fields by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/401
+
+## [0.15.0]
+
+* feat: Printing financial reports by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/363
+* feat: Convert invoice status after sending mail notification by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/332
+* feat: Bigcapital <> Plaid Integration by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/346
+* fix: Broken transactions by vendor report by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/369
+* fix: Optimize the print style some financial reports by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/370
+
## [0.14.0] - 30-01-2024
* feat: purchases by items exporting by @abouolia in https://github.com/bigcapitalhq/bigcapital/pull/327
diff --git a/README.md b/README.md
index 96ff272c3..a50ecdfe2 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
@@ -27,7 +27,7 @@
- Bigcapital Cloud
+ Bigcapital Cloud
@@ -51,7 +51,7 @@ Bigcapital is available open-source under AGPL license. You can host it on your
### Docker
-To get started with self-hosted with Docker and Docker Compose, take a look at the [Docker guide](https://docs.bigcapital.ly/deployment/docker).
+To get started with self-hosted with Docker and Docker Compose, take a look at the [Docker guide](https://docs.bigcapital.app/deployment/docker).
## Development
@@ -74,7 +74,7 @@ You can integrate Bigcapital API with your system to organize your transactions
# Resources
-- [Documentation](https://docs.bigcapital.ly/) - Learn how to use.
+- [Documentation](https://docs.bigcapital.app/) - Learn how to use.
- [Contribution](https://github.com/bigcapitalhq/bigcapital/blob/develop/CONTRIBUTING.md) - Welcome to any contributions.
- [Discord](https://discord.com/invite/c8nPBJafeb) - Ask for help.
- [Bug Tracker](https://github.com/bigcapitalhq/bigcapital/issues) - Notify us new bugs.
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index d842d1d86..bdbc136bf 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -25,12 +25,12 @@ services:
webapp:
container_name: bigcapital-webapp
- image: ghcr.io/bigcapitalhq/webapp:latest
+ image: bigcapitalhq/webapp:latest
restart: on-failure
server:
container_name: bigcapital-server
- image: ghcr.io/bigcapitalhq/server:latest
+ image: bigcapitalhq/server:latest
expose:
- '3000'
links:
@@ -102,6 +102,13 @@ services:
- LEMONSQUEEZY_WEBHOOK_SECRET=${LEMONSQUEEZY_WEBHOOK_SECRET}
- HOSTED_ON_BIGCAPITAL_CLOUD=${HOSTED_ON_BIGCAPITAL_CLOUD}
+ # New Relic matrics tracking.
+ - NEW_RELIC_DISTRIBUTED_TRACING_ENABLED=${NEW_RELIC_DISTRIBUTED_TRACING_ENABLED}
+ - NEW_RELIC_LOG=${NEW_RELIC_LOG}
+ - NEW_RELIC_AI_MONITORING_ENABLED=${NEW_RELIC_AI_MONITORING_ENABLED}
+ - NEW_RELIC_CUSTOM_INSIGHTS_EVENTS_MAX_SAMPLES_STORED=${NEW_RELIC_CUSTOM_INSIGHTS_EVENTS_MAX_SAMPLES_STORED}
+ - NEW_RELIC_SPAN_EVENTS_MAX_SAMPLES_STORED=${NEW_RELIC_SPAN_EVENTS_MAX_SAMPLES_STORED}
+
# OIDC
- OIDC_LOGIN_DISABLED=${OIDC_LOGIN_DISABLED:-false}
- OIDC_ISSUER=${OIDC_ISSUER}
diff --git a/docker/migration/Dockerfile b/docker/migration/Dockerfile
index 162d5039c..d61ef0679 100644
--- a/docker/migration/Dockerfile
+++ b/docker/migration/Dockerfile
@@ -1,4 +1,4 @@
-FROM ghcr.io/bigcapitalhq/server:latest as build
+FROM bigcapitalhq/server:latest as build
ARG DB_HOST= \
DB_USER= \
@@ -34,7 +34,5 @@ WORKDIR /app/packages/server
RUN git clone https://github.com/vishnubob/wait-for-it.git
-ADD docker/migration/start.sh /
-RUN chmod +x /start.sh
-
-CMD ["/start.sh"]
\ No newline at end of file
+# Once we listen the mysql port run the migration task.
+CMD ./wait-for-it/wait-for-it.sh mysql:3306 -- sh -c "node ./build/commands.js system:migrate:latest && node ./build/commands.js tenants:migrate:latest"
diff --git a/docker/migration/start.sh b/docker/migration/start.sh
deleted file mode 100644
index 5fa9f0c28..000000000
--- a/docker/migration/start.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-# Migrate the master system database.
-./wait-for-it/wait-for-it.sh mysql:3306 -- node ./build/commands.js system:migrate:latest
-
-# Migrate all tenants.
-./wait-for-it/wait-for-it.sh mysql:3306 -- node ./build/commands.js tenants:migrate:latest
\ No newline at end of file
diff --git a/packages/server/Dockerfile b/packages/server/Dockerfile
index 095508e2d..be4426405 100644
--- a/packages/server/Dockerfile
+++ b/packages/server/Dockerfile
@@ -78,6 +78,9 @@ ENV MAIL_HOST=$MAIL_HOST \
SIGNUP_ALLOWED_DOMAINS=$SIGNUP_ALLOWED_DOMAINS \
SIGNUP_ALLOWED_EMAILS=$SIGNUP_ALLOWED_EMAILS
+# New Relic config file.
+ENV NEW_RELIC_NO_CONFIG_FILE=true
+
# Create app directory.
WORKDIR /app
@@ -89,8 +92,8 @@ RUN npm install -g pnpm
# Copy application dependency manifests to the container image.
COPY ./package*.json ./
COPY ./pnpm-lock.yaml ./pnpm-lock.yaml
-COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY ./lerna.json ./lerna.json
+COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY ./packages/server/package*.json ./packages/server/
# Install application dependencies
diff --git a/packages/server/package.json b/packages/server/package.json
index 1e3660471..2ba20d9d0 100644
--- a/packages/server/package.json
+++ b/packages/server/package.json
@@ -83,6 +83,7 @@
"mustache": "^3.0.3",
"mysql": "^2.17.1",
"mysql2": "^1.6.5",
+ "newrelic": "^11.15.0",
"node-cache": "^4.2.1",
"nodemailer": "^6.3.0",
"nodemon": "^1.19.1",
diff --git a/packages/server/resources/locales/en.json b/packages/server/resources/locales/en.json
index 13fc8a174..ba4c158b8 100644
--- a/packages/server/resources/locales/en.json
+++ b/packages/server/resources/locales/en.json
@@ -244,6 +244,7 @@
"account.field.active": "Active",
"account.field.currency": "Currency",
"account.field.balance": "Balance",
+ "account.field.bank_balance": "Bank Balance",
"account.field.parent_account": "Parent Account",
"account.field.created_at": "Created at",
"item.field.type": "Item Type",
@@ -331,7 +332,7 @@
"bill_payment.field.reference_no": "Reference No.",
"bill_payment.field.description": "Description",
"bill_payment.field.exchange_rate": "Exchange Rate",
- "bill_payment.field.statement": "Statement",
+ "bill_payment.field.note": "Note",
"bill_payment.field.entries.bill": "Bill No.",
"bill_payment.field.entries.payment_amount": "Payment Amount",
"bill_payment.field.reference": "Reference No.",
@@ -431,6 +432,7 @@
"vendor.field.created_at": "Created at",
"vendor.field.balance": "Balance",
"vendor.field.status": "Status",
+ "vendor.field.note": "Note",
"vendor.field.currency": "Currency",
"vendor.field.status.active": "Active",
"vendor.field.status.inactive": "Inactive",
diff --git a/packages/server/src/api/controllers/Authentication.ts b/packages/server/src/api/controllers/Authentication.ts
index c26da733e..354d37475 100644
--- a/packages/server/src/api/controllers/Authentication.ts
+++ b/packages/server/src/api/controllers/Authentication.ts
@@ -11,6 +11,8 @@ import AuthenticationApplication from '@/services/Authentication/AuthApplication
import AttachCurrentTenantUser from '@/api/middleware/AttachCurrentTenantUser';
import JWTAuth from '@/api/middleware/jwtAuth';
+import JWTAuth from '@/api/middleware/jwtAuth';
+import AttachCurrentTenantUser from '@/api/middleware/AttachCurrentTenantUser';
@Service()
export default class AuthenticationController extends BaseController {
@Inject()
@@ -30,6 +32,20 @@ export default class AuthenticationController extends BaseController {
asyncMiddleware(this.login.bind(this)),
this.handlerErrors
);
+ router.use('/register/verify/resend', JWTAuth);
+ router.use('/register/verify/resend', AttachCurrentTenantUser);
+ router.post(
+ '/register/verify/resend',
+ asyncMiddleware(this.registerVerifyResendMail.bind(this)),
+ this.handlerErrors
+ );
+ router.post(
+ '/register/verify',
+ this.signupVerifySchema,
+ this.validationResult,
+ asyncMiddleware(this.registerVerify.bind(this)),
+ this.handlerErrors
+ );
router.post(
'/register',
this.registerSchema,
@@ -107,6 +123,17 @@ export default class AuthenticationController extends BaseController {
];
}
+ private get signupVerifySchema(): ValidationChain[] {
+ return [
+ check('email')
+ .exists()
+ .isString()
+ .isEmail()
+ .isLength({ max: DATATYPES_LENGTH.STRING }),
+ check('token').exists().isString(),
+ ];
+ }
+
/**
* Reset password schema.
* @returns {ValidationChain[]}
@@ -174,6 +201,58 @@ export default class AuthenticationController extends BaseController {
}
}
+ /**
+ * Verifies the provider user's email after signin-up.
+ * @param {Request} req
+ * @param {Response}| res
+ * @param {Function} next
+ * @returns {Response|void}
+ */
+ private async registerVerify(req: Request, res: Response, next: Function) {
+ const signUpVerifyDTO: { email: string; token: string } =
+ this.matchedBodyData(req);
+
+ try {
+ const user = await this.authApplication.signUpConfirm(
+ signUpVerifyDTO.email,
+ signUpVerifyDTO.token
+ );
+ return res.status(200).send({
+ type: 'success',
+ message: 'The given user has verified successfully',
+ user,
+ });
+ } catch (error) {
+ next(error);
+ }
+ }
+
+ /**
+ * Resends the confirmation email to the user.
+ * @param {Request} req
+ * @param {Response}| res
+ * @param {Function} next
+ */
+ private async registerVerifyResendMail(
+ req: Request,
+ res: Response,
+ next: Function
+ ) {
+ const { user } = req;
+
+ try {
+ const data = await this.authApplication.signUpConfirmResend(user.id);
+
+ return res.status(200).send({
+ type: 'success',
+ message: 'The given user has verified successfully',
+ data,
+ });
+ } catch (error) {
+ next(error);
+ }
+ }
+
/**
* Send reset password handler
* @param {Request} req
diff --git a/packages/server/src/api/controllers/Export/ExportController.ts b/packages/server/src/api/controllers/Export/ExportController.ts
new file mode 100644
index 000000000..632c84932
--- /dev/null
+++ b/packages/server/src/api/controllers/Export/ExportController.ts
@@ -0,0 +1,99 @@
+import { Inject, Service } from 'typedi';
+import { Router, Request, Response, NextFunction } from 'express';
+import { query } from 'express-validator';
+import BaseController from '@/api/controllers/BaseController';
+import { ServiceError } from '@/exceptions';
+import { ExportApplication } from '@/services/Export/ExportApplication';
+import { ACCEPT_TYPE } from '@/interfaces/Http';
+
+@Service()
+export class ExportController extends BaseController {
+ @Inject()
+ private exportResourceApp: ExportApplication;
+
+ /**
+ * Router constructor method.
+ */
+ router() {
+ const router = Router();
+
+ router.get(
+ '/',
+ [
+ query('resource').exists(),
+ query('format').isIn(['csv', 'xlsx']).optional(),
+ ],
+ this.validationResult,
+ this.export.bind(this),
+ this.catchServiceErrors
+ );
+ return router;
+ }
+
+ /**
+ * Imports xlsx/csv to the given resource type.
+ * @param {Request} req -
+ * @param {Response} res -
+ * @param {NextFunction} next -
+ */
+ private async export(req: Request, res: Response, next: NextFunction) {
+ const { tenantId } = req;
+ const query = this.matchedQueryData(req);
+
+ try {
+ const accept = this.accepts(req);
+
+ const acceptType = accept.types([
+ ACCEPT_TYPE.APPLICATION_XLSX,
+ ACCEPT_TYPE.APPLICATION_CSV,
+ ACCEPT_TYPE.APPLICATION_PDF,
+ ]);
+ const data = await this.exportResourceApp.export(
+ tenantId,
+ query.resource,
+ acceptType === ACCEPT_TYPE.APPLICATION_XLSX ? 'xlsx' : 'csv'
+ );
+ if (ACCEPT_TYPE.APPLICATION_CSV === acceptType) {
+ res.setHeader('Content-Disposition', 'attachment; filename=output.csv');
+ res.setHeader('Content-Type', 'text/csv');
+
+ return res.send(data);
+ // Retrieves the xlsx format.
+ } else if (ACCEPT_TYPE.APPLICATION_XLSX === acceptType) {
+ res.setHeader(
+ 'Content-Disposition',
+ 'attachment; filename=output.xlsx'
+ );
+ res.setHeader(
+ 'Content-Type',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ );
+ return res.send(data);
+ }
+ } catch (error) {
+ next(error);
+ }
+ }
+
+ /**
+ * Transforms service errors to response.
+ * @param {Error}
+ * @param {Request} req
+ * @param {Response} res
+ * @param {ServiceError} error
+ */
+ private catchServiceErrors(
+ error,
+ req: Request,
+ res: Response,
+ next: NextFunction
+ ) {
+ if (error instanceof ServiceError) {
+ return res.status(400).send({
+ errors: [{ type: error.errorType }],
+ });
+ }
+
+ next(error);
+ }
+}
diff --git a/packages/server/src/api/index.ts b/packages/server/src/api/index.ts
index e5943475b..a3af24354 100644
--- a/packages/server/src/api/index.ts
+++ b/packages/server/src/api/index.ts
@@ -2,66 +2,67 @@ import { Router } from 'express';
import { Container } from 'typedi';
// Middlewares
-import JWTAuth from '@/api/middleware/jwtAuth';
import AttachCurrentTenantUser from '@/api/middleware/AttachCurrentTenantUser';
-import SubscriptionMiddleware from '@/api/middleware/SubscriptionMiddleware';
-import TenancyMiddleware from '@/api/middleware/TenancyMiddleware';
import EnsureTenantIsInitialized from '@/api/middleware/EnsureTenantIsInitialized';
-import SettingsMiddleware from '@/api/middleware/SettingsMiddleware';
-import I18nMiddleware from '@/api/middleware/I18nMiddleware';
-import I18nAuthenticatedMiddlware from '@/api/middleware/I18nAuthenticatedMiddlware';
import EnsureTenantIsSeeded from '@/api/middleware/EnsureTenantIsSeeded';
+import I18nAuthenticatedMiddlware from '@/api/middleware/I18nAuthenticatedMiddlware';
+import I18nMiddleware from '@/api/middleware/I18nMiddleware';
+import SettingsMiddleware from '@/api/middleware/SettingsMiddleware';
+import SubscriptionMiddleware from '@/api/middleware/SubscriptionMiddleware';
+import TenancyMiddleware from '@/api/middleware/TenancyMiddleware';
+import JWTAuth from '@/api/middleware/jwtAuth';
// Routes
-import Authentication from '@/api/controllers/Authentication';
-import InviteUsers from '@/api/controllers/InviteUsers';
-import Organization from '@/api/controllers/Organization';
import Account from '@/api/controllers/Account';
-import Users from '@/api/controllers/Users';
-import Items from '@/api/controllers/Items';
-import ItemCategories from '@/api/controllers/ItemCategories';
-import Accounts from '@/api/controllers/Accounts';
import AccountTypes from '@/api/controllers/AccountTypes';
-import Views from '@/api/controllers/Views';
-import ManualJournals from '@/api/controllers/ManualJournals';
-import FinancialStatements from '@/api/controllers/FinancialStatements';
-import Expenses from '@/api/controllers/Expenses';
-import Settings from '@/api/controllers/Settings';
-import Currencies from '@/api/controllers/Currencies';
+import Accounts from '@/api/controllers/Accounts';
+import Authentication from '@/api/controllers/Authentication';
import Contacts from '@/api/controllers/Contacts/Contacts';
import Customers from '@/api/controllers/Contacts/Customers';
import Vendors from '@/api/controllers/Contacts/Vendors';
-import Sales from '@/api/controllers/Sales';
-import Purchases from '@/api/controllers/Purchases';
-import Resources from './controllers/Resources';
+import Currencies from '@/api/controllers/Currencies';
import ExchangeRates from '@/api/controllers/ExchangeRates';
-import Media from '@/api/controllers/Media';
-import Ping from '@/api/controllers/Ping';
-import { SubscriptionController } from '@/api/controllers/Subscription';
+import Expenses from '@/api/controllers/Expenses';
+import FinancialStatements from '@/api/controllers/FinancialStatements';
import InventoryAdjustments from '@/api/controllers/Inventory/InventoryAdjustments';
-import asyncRenderMiddleware from './middleware/AsyncRenderMiddleware';
-import Jobs from './controllers/Jobs';
+import InviteUsers from '@/api/controllers/InviteUsers';
+import ItemCategories from '@/api/controllers/ItemCategories';
+import Items from '@/api/controllers/Items';
+import ManualJournals from '@/api/controllers/ManualJournals';
+import Media from '@/api/controllers/Media';
import Miscellaneous from '@/api/controllers/Miscellaneous';
+import OidcController from '@/api/controllers/Oidc';
+import Organization from '@/api/controllers/Organization';
import OrganizationDashboard from '@/api/controllers/OrganizationDashboard';
+import Ping from '@/api/controllers/Ping';
+import Purchases from '@/api/controllers/Purchases';
+import Sales from '@/api/controllers/Sales';
+import Settings from '@/api/controllers/Settings';
+import { SubscriptionController } from '@/api/controllers/Subscription';
+import Users from '@/api/controllers/Users';
+import Views from '@/api/controllers/Views';
+import { BranchIntegrationErrorsMiddleware } from '@/services/Branches/BranchIntegrationErrorsMiddleware';
+import { BankingController } from './controllers/Banking/BankingController';
+import { BranchesController } from './controllers/Branches';
import CashflowController from './controllers/Cashflow/CashflowController';
-import AuthorizationMiddleware from './middleware/AuthorizationMiddleware';
-import RolesController from './controllers/Roles';
-import TransactionsLocking from './controllers/TransactionsLocking';
import DashboardController from './controllers/Dashboard';
-import { BranchesController } from './controllers/Branches';
-import { WarehousesController } from './controllers/Warehouses';
-import { WarehousesTransfers } from './controllers/Warehouses/WarehouseTransfers';
-import { WarehousesItemController } from './controllers/Warehouses/WarehousesItem';
-import { BranchIntegrationErrorsMiddleware } from '@/services/Branches/BranchIntegrationErrorsMiddleware';
+import { ExportController } from './controllers/Export/ExportController';
+import { ImportController } from './controllers/Import/ImportController';
import { InventoryItemsCostController } from './controllers/Inventory/InventortyItemsCosts';
+import Jobs from './controllers/Jobs';
import { ProjectsController } from './controllers/Projects/Projects';
import { ProjectTasksController } from './controllers/Projects/Tasks';
import { ProjectTimesController } from './controllers/Projects/Times';
+import Resources from './controllers/Resources';
+import RolesController from './controllers/Roles';
import { TaxRatesController } from './controllers/TaxRates/TaxRates';
-import { ImportController } from './controllers/Import/ImportController';
-import { BankingController } from './controllers/Banking/BankingController';
+import TransactionsLocking from './controllers/TransactionsLocking';
+import { WarehousesController } from './controllers/Warehouses';
+import { WarehousesTransfers } from './controllers/Warehouses/WarehouseTransfers';
+import { WarehousesItemController } from './controllers/Warehouses/WarehousesItem';
import { Webhooks } from './controllers/Webhooks/Webhooks';
-import OidcController from '@/api/controllers/Oidc'
+import asyncRenderMiddleware from './middleware/AsyncRenderMiddleware';
+import AuthorizationMiddleware from './middleware/AuthorizationMiddleware';
export default () => {
const app = Router();
@@ -70,7 +71,7 @@ export default () => {
// ---------------------------
app.use(asyncRenderMiddleware);
app.use(I18nMiddleware);
-
+
app.use('/oidc', Container.get(OidcController).router());
app.use('/auth', Container.get(Authentication).router());
app.use('/invite', Container.get(InviteUsers).nonAuthRouter());
@@ -143,6 +144,7 @@ export default () => {
dashboard.use('/projects', Container.get(ProjectsController).router());
dashboard.use('/tax-rates', Container.get(TaxRatesController).router());
dashboard.use('/import', Container.get(ImportController).router());
+ dashboard.use('/export', Container.get(ExportController).router());
dashboard.use('/', Container.get(ProjectTasksController).router());
dashboard.use('/', Container.get(ProjectTimesController).router());
diff --git a/packages/server/src/config/index.ts b/packages/server/src/config/index.ts
index 6a61b70d1..72307d080 100644
--- a/packages/server/src/config/index.ts
+++ b/packages/server/src/config/index.ts
@@ -153,6 +153,13 @@ module.exports = {
),
},
+ /**
+ * Sign-up email confirmation
+ */
+ signupConfirmation: {
+ enabled: parseBoolean(process.env.SIGNUP_EMAIL_CONFIRMATION, false),
+ },
+
/**
* Puppeteer remote browserless connection.
*/
diff --git a/packages/server/src/interfaces/Authentication.ts b/packages/server/src/interfaces/Authentication.ts
index 6a2bf625d..41c7aa577 100644
--- a/packages/server/src/interfaces/Authentication.ts
+++ b/packages/server/src/interfaces/Authentication.ts
@@ -1,6 +1,6 @@
-import { ISystemUser } from './User';
-import { ITenant } from './Tenancy';
import { SystemUser } from '@/system/models';
+import { ITenant } from './Tenancy';
+import { ISystemUser } from './User';
export interface IRegisterDTO {
firstName: string;
@@ -66,17 +66,28 @@ export interface IAuthResetedPasswordEventPayload {
password: string;
}
-
export interface IAuthSendingResetPassword {
- user: ISystemUser,
+ user: ISystemUser;
token: string;
}
export interface IAuthSendedResetPassword {
- user: ISystemUser,
+ user: ISystemUser;
token: string;
}
export interface IAuthGetMetaPOJO {
signupDisabled: boolean;
oidcLoginDisabled: boolean;
-}
\ No newline at end of file
+}
+
+export interface IAuthSignUpVerifingEventPayload {
+ email: string;
+ verifyToken: string;
+ userId: number;
+}
+
+export interface IAuthSignUpVerifiedEventPayload {
+ email: string;
+ verifyToken: string;
+ userId: number;
+}
diff --git a/packages/server/src/interfaces/Model.ts b/packages/server/src/interfaces/Model.ts
index 87912bafe..93bb1f7fc 100644
--- a/packages/server/src/interfaces/Model.ts
+++ b/packages/server/src/interfaces/Model.ts
@@ -126,13 +126,16 @@ export interface IModelMeta {
defaultFilterField: string;
defaultSort: IModelMetaDefaultSort;
- importable?: boolean;
+ exportable?: boolean;
+ exportFlattenOn?: string;
+ importable?: boolean;
importAggregator?: string;
importAggregateOn?: string;
importAggregateBy?: string;
fields: { [key: string]: IModelMetaField };
+ columns: { [key: string]: IModelMetaColumn };
}
// ----
@@ -161,3 +164,22 @@ export type IModelMetaField2 = IModelMetaFieldCommon2 &
| IModelMetaRelationField2
| IModelMetaCollectionField
);
+
+export interface ImodelMetaColumnMeta {
+ name: string;
+ accessor?: string;
+ exportable?: boolean;
+}
+
+interface IModelMetaColumnText {
+ type: 'text;';
+}
+
+interface IModelMetaColumnCollection {
+ type: 'collection';
+ collectionOf: 'object';
+ columns: { [key: string]: ImodelMetaColumnMeta & IModelMetaColumnText };
+}
+
+export type IModelMetaColumn = ImodelMetaColumnMeta &
+ (IModelMetaColumnText | IModelMetaColumnCollection);
diff --git a/packages/server/src/loaders/eventEmitter.ts b/packages/server/src/loaders/eventEmitter.ts
index 91d814f8a..9da52fd86 100644
--- a/packages/server/src/loaders/eventEmitter.ts
+++ b/packages/server/src/loaders/eventEmitter.ts
@@ -91,6 +91,7 @@ import { SaleEstimateMarkApprovedOnMailSent } from '@/services/Sales/Estimates/s
import { DeleteCashflowTransactionOnUncategorize } from '@/services/Cashflow/subscribers/DeleteCashflowTransactionOnUncategorize';
import { PreventDeleteTransactionOnDelete } from '@/services/Cashflow/subscribers/PreventDeleteTransactionsOnDelete';
import { SubscribeFreeOnSignupCommunity } from '@/services/Subscription/events/SubscribeFreeOnSignupCommunity';
+import { SendVerfiyMailOnSignUp } from '@/services/Authentication/events/SendVerfiyMailOnSignUp';
export default () => {
@@ -222,6 +223,7 @@ export const susbcribers = () => {
DeleteCashflowTransactionOnUncategorize,
PreventDeleteTransactionOnDelete,
- SubscribeFreeOnSignupCommunity
+ SubscribeFreeOnSignupCommunity,
+ SendVerfiyMailOnSignUp
];
};
diff --git a/packages/server/src/loaders/jobs.ts b/packages/server/src/loaders/jobs.ts
index 58da23291..231149f48 100644
--- a/packages/server/src/loaders/jobs.ts
+++ b/packages/server/src/loaders/jobs.ts
@@ -12,6 +12,7 @@ import { SaleReceiptMailNotificationJob } from '@/services/Sales/Receipts/SaleRe
import { PaymentReceiveMailNotificationJob } from '@/services/Sales/PaymentReceives/PaymentReceiveMailNotificationJob';
import { PlaidFetchTransactionsJob } from '@/services/Banking/Plaid/PlaidFetchTransactionsJob';
import { ImportDeleteExpiredFilesJobs } from '@/services/Import/jobs/ImportDeleteExpiredFilesJob';
+import { SendVerifyMailJob } from '@/services/Authentication/jobs/SendVerifyMailJob';
export default ({ agenda }: { agenda: Agenda }) => {
new ResetPasswordMailJob(agenda);
@@ -27,6 +28,7 @@ export default ({ agenda }: { agenda: Agenda }) => {
new PaymentReceiveMailNotificationJob(agenda);
new PlaidFetchTransactionsJob(agenda);
new ImportDeleteExpiredFilesJobs(agenda);
+ new SendVerifyMailJob(agenda);
agenda.start().then(() => {
agenda.every('1 hours', 'delete-expired-imported-files', {});
diff --git a/packages/server/src/models/Account.Settings.ts b/packages/server/src/models/Account.Settings.ts
index 5fb8ea8a7..7be8cf404 100644
--- a/packages/server/src/models/Account.Settings.ts
+++ b/packages/server/src/models/Account.Settings.ts
@@ -7,6 +7,7 @@ export default {
sortField: 'name',
},
importable: true,
+ exportable: true,
fields: {
name: {
name: 'account.field.name',
@@ -85,6 +86,55 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ name: {
+ name: 'account.field.name',
+ type: 'text',
+ },
+ code: {
+ name: 'account.field.code',
+ type: 'text',
+ },
+ rootType: {
+ name: 'account.field.root_type',
+ type: 'text',
+ accessor: 'accountRootType',
+ },
+ accountType: {
+ name: 'account.field.type',
+ accessor: 'accountTypeLabel',
+ type: 'text',
+ },
+ accountNormal: {
+ name: 'account.field.normal',
+ accessor: 'accountNormalFormatted',
+ },
+ currencyCode: {
+ name: 'account.field.currency',
+ type: 'text',
+ },
+ bankBalance: {
+ name: 'account.field.bank_balance',
+ accessor: 'bankBalanceFormatted',
+ type: 'text',
+ exportable: true,
+ },
+ balance: {
+ name: 'account.field.balance',
+ accessor: 'amount',
+ },
+ description: {
+ name: 'account.field.description',
+ type: 'text',
+ },
+ active: {
+ name: 'account.field.active',
+ type: 'boolean',
+ },
+ createdAt: {
+ name: 'account.field.created_at',
+ },
+ },
fields2: {
name: {
name: 'account.field.name',
diff --git a/packages/server/src/models/Bill.Settings.ts b/packages/server/src/models/Bill.Settings.ts
index 2842ff926..890a9635a 100644
--- a/packages/server/src/models/Bill.Settings.ts
+++ b/packages/server/src/models/Bill.Settings.ts
@@ -5,6 +5,8 @@ export default {
sortField: 'bill_date',
},
importable: true,
+ exportFlattenOn: 'entries',
+ exportable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
importAggregateBy: 'billNumber',
@@ -80,6 +82,84 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ billNumber: {
+ name: 'Bill No.',
+ type: 'text',
+ },
+ referenceNo: {
+ name: 'Reference No.',
+ type: 'text',
+ },
+ billDate: {
+ name: 'Date',
+ type: 'date',
+ },
+ dueDate: {
+ name: 'Due Date',
+ type: 'date',
+ },
+ vendorId: {
+ name: 'Vendor',
+ accessor: 'vendor.displayName',
+ type: 'text',
+ },
+ amount: {
+ name: 'Amount',
+ accessor: 'formattedAmount',
+ },
+ exchangeRate: {
+ name: 'Exchange Rate',
+ type: 'number',
+ },
+ currencyCode: {
+ name: 'Currency Code',
+ type: 'text',
+ },
+ dueAmount: {
+ name: 'Due Amount',
+ accessor: 'formattedDueAmount',
+ },
+ paidAmount: {
+ name: 'Paid Amount',
+ accessor: 'formattedPaymentAmount',
+ },
+ note: {
+ name: 'Note',
+ type: 'text',
+ },
+ open: {
+ name: 'Open',
+ type: 'boolean',
+ },
+ entries: {
+ name: 'Entries',
+ accessor: 'entries',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ itemName: {
+ name: 'Item Name',
+ accessor: 'item.name',
+ },
+ rate: {
+ name: 'Item Rate',
+ accessor: 'rateFormatted',
+ },
+ quantity: {
+ name: 'Item Quantity',
+ accessor: 'quantityFormatted',
+ },
+ description: {
+ name: 'Item Description',
+ },
+ amount: {
+ name: 'Item Amount',
+ accessor: 'totalFormatted',
+ },
+ },
+ },
+ },
fields2: {
billNumber: {
name: 'Bill No.',
@@ -132,7 +212,7 @@ export default {
relationModel: 'Item',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the item name or code."
+ importHint: 'Matches the item name or code.',
},
rate: {
name: 'Rate',
diff --git a/packages/server/src/models/BillPayment.Settings.ts b/packages/server/src/models/BillPayment.Settings.ts
index 1f2369f21..4d7de9239 100644
--- a/packages/server/src/models/BillPayment.Settings.ts
+++ b/packages/server/src/models/BillPayment.Settings.ts
@@ -4,6 +4,7 @@ export default {
sortOrder: 'DESC',
sortField: 'bill_date',
},
+ exportable: true,
importable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
@@ -67,6 +68,46 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ vendor: {
+ name: 'bill_payment.field.vendor',
+ type: 'relation',
+ accessor: 'vendor.displayName',
+ },
+ paymentDate: {
+ name: 'bill_payment.field.payment_date',
+ type: 'date',
+ },
+ paymentNumber: {
+ name: 'bill_payment.field.payment_number',
+ type: 'text',
+ },
+ paymentAccount: {
+ name: 'bill_payment.field.payment_account',
+ accessor: 'paymentAccount.name',
+ type: 'text',
+ },
+ amount: {
+ name: 'Amount',
+ accessor: 'formattedAmount',
+ },
+ currencyCode: {
+ name: 'Currency Code',
+ type: 'text',
+ },
+ exchangeRate: {
+ name: 'bill_payment.field.exchange_rate',
+ type: 'number',
+ },
+ statement: {
+ name: 'bill_payment.field.note',
+ type: 'text',
+ },
+ reference: {
+ name: 'bill_payment.field.reference',
+ type: 'text',
+ },
+ },
fields2: {
vendorId: {
name: 'bill_payment.field.vendor',
@@ -84,7 +125,7 @@ export default {
name: 'bill_payment.field.payment_number',
fieldType: 'text',
unique: true,
- importHint: "The payment number should be unique."
+ importHint: 'The payment number should be unique.',
},
paymentAccountId: {
name: 'bill_payment.field.payment_account',
@@ -92,14 +133,14 @@ export default {
relationModel: 'Account',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the account name or code."
+ importHint: 'Matches the account name or code.',
},
exchangeRate: {
name: 'bill_payment.field.exchange_rate',
fieldType: 'number',
},
statement: {
- name: 'bill_payment.field.statement',
+ name: 'bill_payment.field.note',
fieldType: 'text',
},
reference: {
@@ -120,7 +161,7 @@ export default {
relationModel: 'Bill',
relationImportMatch: 'billNumber',
required: true,
- importHint: "Matches the bill number."
+ importHint: 'Matches the bill number.',
},
paymentAmount: {
name: 'bill_payment.field.entries.payment_amount',
diff --git a/packages/server/src/models/CreditNote.Meta.ts b/packages/server/src/models/CreditNote.Meta.ts
index f6317528b..5da0c1d9e 100644
--- a/packages/server/src/models/CreditNote.Meta.ts
+++ b/packages/server/src/models/CreditNote.Meta.ts
@@ -12,10 +12,14 @@ export default {
sortOrder: 'DESC',
sortField: 'name',
},
+ exportable: true,
+ exportFlattenOn: 'entries',
+
importable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
importAggregateBy: 'creditNoteNumber',
+
fields: {
customer: {
name: 'credit_note.field.customer',
@@ -81,6 +85,67 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ customer: {
+ name: 'Customer',
+ type: 'relation',
+ accessor: 'customer.displayName',
+ },
+ exchangeRate: {
+ name: 'Exchange Rate',
+ type: 'number',
+ },
+ creditNoteDate: {
+ name: 'Credit Note Date',
+ type: 'date',
+ },
+ referenceNo: {
+ name: 'Reference No.',
+ type: 'text',
+ },
+ note: {
+ name: 'Note',
+ type: 'text',
+ },
+ termsConditions: {
+ name: 'Terms & Conditions',
+ type: 'text',
+ },
+ creditNoteNumber: {
+ name: 'Credit Note Number',
+ type: 'text',
+ },
+ open: {
+ name: 'Open',
+ type: 'boolean',
+ },
+ entries: {
+ name: 'Entries',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ itemName: {
+ name: 'Item Name',
+ accessor: 'item.name',
+ },
+ rate: {
+ name: 'Item Rate',
+ accessor: 'rateFormatted',
+ },
+ quantity: {
+ name: 'Item Quantity',
+ accessor: 'quantityFormatted',
+ },
+ description: {
+ name: 'Item Description',
+ },
+ amount: {
+ name: 'Item Amount',
+ accessor: 'totalFormatted',
+ },
+ },
+ },
+ },
fields2: {
customerId: {
name: 'Customer',
diff --git a/packages/server/src/models/Customer.Settings.ts b/packages/server/src/models/Customer.Settings.ts
index fa7bcc2d2..71f631032 100644
--- a/packages/server/src/models/Customer.Settings.ts
+++ b/packages/server/src/models/Customer.Settings.ts
@@ -1,5 +1,6 @@
export default {
importable: true,
+ exportable: true,
defaultFilterField: 'displayName',
defaultSort: {
sortOrder: 'DESC',
@@ -90,6 +91,138 @@ export default {
},
},
},
+ columns: {
+ firstName: {
+ name: 'vendor.field.first_name',
+ type: 'text',
+ },
+ lastName: {
+ name: 'vendor.field.last_name',
+ type: 'text',
+ },
+ displayName: {
+ name: 'vendor.field.display_name',
+ type: 'text',
+ },
+ email: {
+ name: 'vendor.field.email',
+ type: 'text',
+ },
+ workPhone: {
+ name: 'vendor.field.work_phone',
+ type: 'text',
+ },
+ personalPhone: {
+ name: 'vendor.field.personal_phone',
+ type: 'text',
+ },
+ companyName: {
+ name: 'vendor.field.company_name',
+ type: 'text',
+ },
+ website: {
+ name: 'vendor.field.website',
+ type: 'text',
+ },
+ balance: {
+ name: 'vendor.field.balance',
+ type: 'number',
+ },
+ openingBalance: {
+ name: 'vendor.field.opening_balance',
+ type: 'number',
+ },
+ openingBalanceAt: {
+ name: 'vendor.field.opening_balance_at',
+ type: 'date',
+ },
+ currencyCode: {
+ name: 'vendor.field.currency',
+ type: 'text',
+ },
+ status: {
+ name: 'vendor.field.status',
+ },
+ note: {
+ name: 'vendor.field.note',
+ },
+ // Billing Address
+ billingAddress1: {
+ name: 'Billing Address 1',
+ column: 'billing_address1',
+ type: 'text',
+ },
+ billingAddress2: {
+ name: 'Billing Address 2',
+ column: 'billing_address2',
+ type: 'text',
+ },
+ billingAddressCity: {
+ name: 'Billing Address City',
+ column: 'billing_address_city',
+ type: 'text',
+ },
+ billingAddressCountry: {
+ name: 'Billing Address Country',
+ column: 'billing_address_country',
+ type: 'text',
+ },
+ billingAddressPostcode: {
+ name: 'Billing Address Postcode',
+ column: 'billing_address_postcode',
+ type: 'text',
+ },
+ billingAddressState: {
+ name: 'Billing Address State',
+ column: 'billing_address_state',
+ type: 'text',
+ },
+ billingAddressPhone: {
+ name: 'Billing Address Phone',
+ column: 'billing_address_phone',
+ type: 'text',
+ },
+ // Shipping Address
+ shippingAddress1: {
+ name: 'Shipping Address 1',
+ column: 'shipping_address1',
+ type: 'text',
+ },
+ shippingAddress2: {
+ name: 'Shipping Address 2',
+ column: 'shipping_address2',
+ type: 'text',
+ },
+ shippingAddressCity: {
+ name: 'Shipping Address City',
+ column: 'shipping_address_city',
+ type: 'text',
+ },
+ shippingAddressCountry: {
+ name: 'Shipping Address Country',
+ column: 'shipping_address_country',
+ type: 'text',
+ },
+ shippingAddressPostcode: {
+ name: 'Shipping Address Postcode',
+ column: 'shipping_address_postcode',
+ type: 'text',
+ },
+ shippingAddressPhone: {
+ name: 'Shipping Address Phone',
+ column: 'shipping_address_phone',
+ type: 'text',
+ },
+ shippingAddressState: {
+ name: 'Shipping Address State',
+ column: 'shipping_address_state',
+ type: 'text',
+ },
+ createdAt: {
+ name: 'vendor.field.created_at',
+ type: 'date',
+ },
+ },
fields2: {
customerType: {
name: 'Customer Type',
diff --git a/packages/server/src/models/Expense.Settings.ts b/packages/server/src/models/Expense.Settings.ts
index c1d670526..12c539782 100644
--- a/packages/server/src/models/Expense.Settings.ts
+++ b/packages/server/src/models/Expense.Settings.ts
@@ -8,6 +8,8 @@ export default {
sortField: 'name',
},
importable: true,
+ exportFlattenOn: 'categories',
+ exportable: true,
fields: {
payment_date: {
name: 'expense.field.payment_date',
@@ -61,6 +63,56 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ paymentReceive: {
+ name: 'expense.field.payment_account',
+ type: 'text',
+ accessor: 'paymentAccount.name'
+ },
+ referenceNo: {
+ name: 'expense.field.reference_no',
+ type: 'text',
+ },
+ paymentDate: {
+ name: 'expense.field.payment_date',
+ type: 'date',
+ },
+ currencyCode: {
+ name: 'expense.field.currency_code',
+ type: 'text',
+ },
+ exchangeRate: {
+ name: 'expense.field.exchange_rate',
+ type: 'number',
+ },
+ description: {
+ name: 'expense.field.description',
+ type: 'text',
+ },
+ categories: {
+ name: 'expense.field.categories',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ expenseAccount: {
+ name: 'expense.field.expense_account',
+ accessor: 'expenseAccount.name',
+ },
+ amount: {
+ name: 'expense.field.amount',
+ accessor: 'amountFormatted',
+ },
+ description: {
+ name: 'expense.field.line_description',
+ type: 'text',
+ },
+ },
+ },
+ publish: {
+ name: 'expense.field.publish',
+ type: 'boolean',
+ },
+ },
fields2: {
paymentAccountId: {
name: 'expense.field.payment_account',
@@ -68,7 +120,7 @@ export default {
relationModel: 'Account',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the account name or code."
+ importHint: 'Matches the account name or code.',
},
referenceNo: {
name: 'expense.field.reference_no',
@@ -102,7 +154,7 @@ export default {
relationModel: 'Account',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the account name or code."
+ importHint: 'Matches the account name or code.',
},
amount: {
name: 'expense.field.amount',
diff --git a/packages/server/src/models/InventoryAdjustment.Settings.ts b/packages/server/src/models/InventoryAdjustment.Settings.ts
index 9ef90cbc5..9d7f65237 100644
--- a/packages/server/src/models/InventoryAdjustment.Settings.ts
+++ b/packages/server/src/models/InventoryAdjustment.Settings.ts
@@ -4,6 +4,54 @@ export default {
sortOrder: 'DESC',
sortField: 'date',
},
+ columns: {
+ date: {
+ name: 'inventory_adjustment.field.date',
+ column: 'date',
+ fieldType: 'date',
+ exportable: true,
+ },
+ type: {
+ name: 'inventory_adjustment.field.type',
+ column: 'type',
+ fieldType: 'enumeration',
+ options: [
+ { key: 'increment', name: 'inventory_adjustment.field.type.increment' },
+ { key: 'decrement', name: 'inventory_adjustment.field.type.decrement' },
+ ],
+ exportable: true,
+ },
+ adjustmentAccount: {
+ name: 'inventory_adjustment.field.adjustment_account',
+ type: 'adjustment_account_id',
+ exportable: true,
+ },
+ reason: {
+ name: 'inventory_adjustment.field.reason',
+ type: 'text',
+ exportable: true,
+ },
+ referenceNo: {
+ name: 'inventory_adjustment.field.reference_no',
+ type: 'text',
+ exportable: true,
+ },
+ description: {
+ name: 'inventory_adjustment.field.description',
+ type: 'text',
+ exportable: true,
+ },
+ publishedAt: {
+ name: 'inventory_adjustment.field.published_at',
+ type: 'date',
+ exportable: true,
+ },
+ createdAt: {
+ name: 'inventory_adjustment.field.created_at',
+ type: 'date',
+ exportable: true,
+ },
+ },
fields: {
date: {
name: 'inventory_adjustment.field.date',
diff --git a/packages/server/src/models/Item.Settings.ts b/packages/server/src/models/Item.Settings.ts
index 640c271ea..9c8a50ce8 100644
--- a/packages/server/src/models/Item.Settings.ts
+++ b/packages/server/src/models/Item.Settings.ts
@@ -1,5 +1,6 @@
export default {
importable: true,
+ exportable: true,
defaultFilterField: 'name',
defaultSort: {
sortField: 'name',
@@ -121,6 +122,97 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ type: {
+ name: 'item.field.type',
+ type: 'text',
+ exportable: true,
+ },
+ name: {
+ name: 'item.field.name',
+ type: 'text',
+ exportable: true,
+ },
+ code: {
+ name: 'item.field.code',
+ type: 'text',
+ exportable: true,
+ },
+ sellable: {
+ name: 'item.field.sellable',
+ type: 'boolean',
+ exportable: true,
+ },
+ purchasable: {
+ name: 'item.field.purchasable',
+ type: 'boolean',
+ exportable: true,
+ },
+ sellPrice: {
+ name: 'item.field.cost_price',
+ type: 'number',
+ exportable: true,
+ },
+ costPrice: {
+ name: 'item.field.cost_account',
+ type: 'number',
+ exportable: true,
+ },
+ costAccount: {
+ name: 'item.field.sell_account',
+ type: 'text',
+ accessor: 'costAccount.name',
+ exportable: true,
+ },
+ sellAccount: {
+ name: 'item.field.sell_description',
+ type: 'text',
+ accessor: 'sellAccount.name',
+ exportable: true,
+ },
+ inventoryAccount: {
+ name: 'item.field.inventory_account',
+ type: 'text',
+ accessor: 'inventoryAccount.name',
+ exportable: true,
+ },
+ sellDescription: {
+ name: 'Sell description',
+ type: 'text',
+ exportable: true,
+ },
+ purchaseDescription: {
+ name: 'Purchase description',
+ type: 'text',
+ exportable: true,
+ },
+ quantityOnHand: {
+ name: 'item.field.quantity_on_hand',
+ type: 'number',
+ exportable: true,
+ },
+ note: {
+ name: 'item.field.note',
+ type: 'text',
+ exportable: true,
+ },
+ category: {
+ name: 'item.field.category',
+ type: 'text',
+ accessor: 'category.name',
+ exportable: true,
+ },
+ active: {
+ name: 'item.field.active',
+ fieldType: 'boolean',
+ exportable: true,
+ },
+ createdAt: {
+ name: 'item.field.created_at',
+ type: 'date',
+ exportable: true,
+ },
+ },
fields2: {
type: {
name: 'item.field.type',
@@ -195,7 +287,7 @@ export default {
fieldType: 'relation',
relationModel: 'ItemCategory',
relationImportMatch: ['name'],
- importHint: "Matches the category name."
+ importHint: 'Matches the category name.',
},
active: {
name: 'item.field.active',
diff --git a/packages/server/src/models/ItemCategory.Settings.ts b/packages/server/src/models/ItemCategory.Settings.ts
index 32a29cd10..66b7af28f 100644
--- a/packages/server/src/models/ItemCategory.Settings.ts
+++ b/packages/server/src/models/ItemCategory.Settings.ts
@@ -5,6 +5,7 @@ export default {
sortOrder: 'DESC',
},
importable: true,
+ exportable: true,
fields: {
name: {
name: 'item_category.field.name',
@@ -28,6 +29,24 @@ export default {
columnType: 'date',
},
},
+ columns: {
+ name: {
+ name: 'item_category.field.name',
+ type: 'text',
+ },
+ description: {
+ name: 'item_category.field.description',
+ type: 'text',
+ },
+ count: {
+ name: 'item_category.field.count',
+ type: 'text',
+ },
+ createdAt: {
+ name: 'item_category.field.created_at',
+ type: 'text',
+ },
+ },
fields2: {
name: {
name: 'item_category.field.name',
diff --git a/packages/server/src/models/ManualJournal.Settings.ts b/packages/server/src/models/ManualJournal.Settings.ts
index 11409e1aa..db2712220 100644
--- a/packages/server/src/models/ManualJournal.Settings.ts
+++ b/packages/server/src/models/ManualJournal.Settings.ts
@@ -5,6 +5,9 @@ export default {
sortField: 'name',
},
importable: true,
+ exportFlattenOn: 'entries',
+
+ exportable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
importAggregateBy: 'journalNumber',
@@ -56,6 +59,76 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ date: {
+ name: 'manual_journal.field.date',
+ type: 'date',
+ },
+ journalNumber: {
+ name: 'manual_journal.field.journal_number',
+ type: 'text',
+ },
+ reference: {
+ name: 'manual_journal.field.reference',
+ type: 'text',
+ },
+ journalType: {
+ name: 'manual_journal.field.journal_type',
+ type: 'text',
+ },
+ amount: {
+ name: 'Amount',
+ accessor: 'formattedAmount',
+ },
+ currencyCode: {
+ name: 'manual_journal.field.currency',
+ type: 'text',
+ },
+ exchangeRate: {
+ name: 'manual_journal.field.exchange_rate',
+ type: 'number',
+ },
+ description: {
+ name: 'manual_journal.field.description',
+ type: 'text',
+ },
+ entries: {
+ name: 'Entries',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ credit: {
+ name: 'Credit',
+ type: 'text',
+ },
+ debit: {
+ name: 'Debit',
+ type: 'text',
+ },
+ account: {
+ name: 'Account',
+ accessor: 'account.name',
+ },
+ contact: {
+ name: 'Contact',
+ accessor: 'contact.displayName',
+ },
+ note: {
+ name: 'Note',
+ },
+ },
+ publish: {
+ name: 'Publish',
+ type: 'boolean',
+ },
+ publishedAt: {
+ name: 'Published At',
+ },
+ },
+ createdAt: {
+ name: 'Created At',
+ },
+ },
fields2: {
date: {
name: 'manual_journal.field.date',
diff --git a/packages/server/src/models/PaymentReceive.Settings.ts b/packages/server/src/models/PaymentReceive.Settings.ts
index e96e1c7b2..663b5884d 100644
--- a/packages/server/src/models/PaymentReceive.Settings.ts
+++ b/packages/server/src/models/PaymentReceive.Settings.ts
@@ -1,5 +1,6 @@
export default {
importable: true,
+ exportable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
importAggregateBy: 'paymentReceiveNo',
@@ -57,6 +58,42 @@ export default {
fieldDate: 'date',
},
},
+ columns: {
+ customer: {
+ name: 'payment_receive.field.customer',
+ accessor: 'customer.displayName',
+ type: 'text',
+ },
+ paymentDate: {
+ name: 'payment_receive.field.payment_date',
+ type: 'date',
+ },
+ amount: {
+ name: 'payment_receive.field.amount',
+ type: 'number',
+ },
+ referenceNo: {
+ name: 'payment_receive.field.reference_no',
+ type: 'text',
+ },
+ depositAccount: {
+ name: 'payment_receive.field.deposit_account',
+ accessor: 'depositAccount.name',
+ type: 'text',
+ },
+ paymentReceiveNo: {
+ name: 'payment_receive.field.payment_receive_no',
+ type: 'text',
+ },
+ statement: {
+ name: 'payment_receive.field.statement',
+ type: 'text',
+ },
+ created_at: {
+ name: 'payment_receive.field.created_at',
+ type: 'date',
+ },
+ },
fields2: {
customerId: {
name: 'payment_receive.field.customer',
@@ -84,12 +121,12 @@ export default {
relationModel: 'Account',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the account name or code."
+ importHint: 'Matches the account name or code.',
},
paymentReceiveNo: {
name: 'payment_receive.field.payment_receive_no',
fieldType: 'text',
- importHint: "The payment number should be unique."
+ importHint: 'The payment number should be unique.',
},
statement: {
name: 'payment_receive.field.statement',
@@ -108,7 +145,7 @@ export default {
relationModel: 'SaleInvoice',
relationImportMatch: 'invoiceNo',
required: true,
- importHint: "Matches the invoice number."
+ importHint: 'Matches the invoice number.',
},
paymentAmount: {
name: 'payment_receive.field.entries.payment_amount',
diff --git a/packages/server/src/models/SaleEstimate.Settings.ts b/packages/server/src/models/SaleEstimate.Settings.ts
index f92735f34..a9577b4f4 100644
--- a/packages/server/src/models/SaleEstimate.Settings.ts
+++ b/packages/server/src/models/SaleEstimate.Settings.ts
@@ -4,6 +4,9 @@ export default {
sortOrder: 'DESC',
sortField: 'estimate_date',
},
+ exportable: true,
+ exportFlattenOn: 'entries',
+
importable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
@@ -73,6 +76,91 @@ export default {
columnType: 'date',
},
},
+ columns: {
+ customer: {
+ name: 'Customer',
+ type: 'text',
+ accessor: 'customer.displayName',
+ exportable: true,
+ },
+ estimateDate: {
+ name: 'Estimate Date',
+ type: 'date',
+ exportable: true,
+ },
+ expirationDate: {
+ name: 'Expiration Date',
+ type: 'date',
+ exportable: true,
+ },
+ estimateNumber: {
+ name: 'Estimate No.',
+ type: 'text',
+ exportable: true,
+ },
+ reference: {
+ name: 'Reference No.',
+ type: 'text',
+ exportable: true,
+ },
+ amount: {
+ name: 'Amount',
+ accessor: 'formattedAmount',
+ type: 'text',
+ },
+ exchangeRate: {
+ name: 'Exchange Rate',
+ type: 'number',
+ exportable: true,
+ },
+ currencyCode: {
+ name: 'Currency',
+ type: 'text',
+ exportable: true,
+ },
+ note: {
+ name: 'Note',
+ type: 'text',
+ exportable: true,
+ },
+ termsConditions: {
+ name: 'Terms & Conditions',
+ type: 'text',
+ exportable: true,
+ },
+ delivered: {
+ name: 'Delivered',
+ type: 'boolean',
+ exportable: true,
+ },
+ entries: {
+ name: 'Entries',
+ accessor: 'entries',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ itemName: {
+ name: 'Item Name',
+ accessor: 'item.name',
+ },
+ rate: {
+ name: 'Item Rate',
+ accessor: 'rateFormatted',
+ },
+ quantity: {
+ name: 'Item Quantity',
+ accessor: 'quantityFormatted',
+ },
+ description: {
+ name: 'Item Description',
+ },
+ amount: {
+ name: 'Item Amount',
+ accessor: 'totalFormatted',
+ },
+ },
+ },
+ },
fields2: {
customerId: {
name: 'Customer',
@@ -132,7 +220,7 @@ export default {
relationModel: 'Item',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the item name or code."
+ importHint: 'Matches the item name or code.',
},
rate: {
name: 'invoice.field.rate',
diff --git a/packages/server/src/models/SaleInvoice.Settings.ts b/packages/server/src/models/SaleInvoice.Settings.ts
index c48befbcb..24728522e 100644
--- a/packages/server/src/models/SaleInvoice.Settings.ts
+++ b/packages/server/src/models/SaleInvoice.Settings.ts
@@ -4,6 +4,9 @@ export default {
sortOrder: 'DESC',
sortField: 'created_at',
},
+ exportable: true,
+ exportFlattenOn: 'entries',
+
importable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
@@ -87,6 +90,89 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ invoiceDate: {
+ name: 'invoice.field.invoice_date',
+ type: 'date',
+ },
+ dueDate: {
+ name: 'invoice.field.due_date',
+ type: 'date',
+ },
+ referenceNo: {
+ name: 'invoice.field.reference_no',
+ type: 'text',
+ },
+ invoiceNo: {
+ name: 'invoice.field.invoice_no',
+ type: 'text',
+ },
+ customer: {
+ name: 'invoice.field.customer',
+ type: 'text',
+ accessor: 'customer.displayName',
+ },
+ amount: {
+ name: 'invoice.field.amount',
+ type: 'text',
+ accessor: 'balanceAmountFormatted',
+ },
+ exchangeRate: {
+ name: 'invoice.field.exchange_rate',
+ type: 'number',
+ },
+ currencyCode: {
+ name: 'invoice.field.currency',
+ type: 'text',
+ },
+ paidAmount: {
+ name: 'Paid Amount',
+ accessor: 'paymentAmountFormatted',
+ },
+ dueAmount: {
+ name: 'Due Amount',
+ accessor: 'dueAmountFormatted',
+ },
+ invoiceMessage: {
+ name: 'invoice.field.invoice_message',
+ type: 'text',
+ },
+ termsConditions: {
+ name: 'invoice.field.terms_conditions',
+ type: 'text',
+ },
+ delivered: {
+ name: 'invoice.field.delivered',
+ type: 'boolean',
+ },
+ entries: {
+ name: 'Entries',
+ accessor: 'entries',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ itemName: {
+ name: 'Item Name',
+ accessor: 'item.name',
+ },
+ rate: {
+ name: 'Item Rate',
+ accessor: 'rateFormatted',
+ },
+ quantity: {
+ name: 'Item Quantity',
+ accessor: 'quantityFormatted',
+ },
+ description: {
+ name: 'Item Description',
+ },
+ amount: {
+ name: 'Item Amount',
+ accessor: 'totalFormatted',
+ },
+ },
+ },
+ },
fields2: {
invoiceDate: {
name: 'invoice.field.invoice_date',
@@ -142,7 +228,7 @@ export default {
relationModel: 'Item',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the item name or code."
+ importHint: 'Matches the item name or code.',
},
rate: {
name: 'invoice.field.rate',
diff --git a/packages/server/src/models/SaleReceipt.Settings.ts b/packages/server/src/models/SaleReceipt.Settings.ts
index 2b2fe6fa2..3fecd0480 100644
--- a/packages/server/src/models/SaleReceipt.Settings.ts
+++ b/packages/server/src/models/SaleReceipt.Settings.ts
@@ -4,6 +4,9 @@ export default {
sortOrder: 'DESC',
sortField: 'created_at',
},
+ exportable: true,
+ exportFlattenOn: 'entries',
+
importable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
@@ -77,6 +80,86 @@ export default {
sortCustomQuery: StatusFieldSortQuery,
},
},
+ columns: {
+ amount: {
+ name: 'receipt.field.amount',
+ column: 'amount',
+ type: 'number',
+ },
+ depositAccount: {
+ name: 'receipt.field.deposit_account',
+ type: 'text',
+ accessor: 'depositAccount.name',
+ },
+ customer: {
+ name: 'receipt.field.customer',
+ type: 'text',
+ accessor: 'customer.displayName',
+ },
+ receiptDate: {
+ name: 'receipt.field.receipt_date',
+ type: 'date',
+ },
+ receiptNumber: {
+ name: 'receipt.field.receipt_number',
+ type: 'text',
+ },
+ referenceNo: {
+ name: 'receipt.field.reference_no',
+ column: 'reference_no',
+ type: 'text',
+ exportable: true,
+ },
+ receiptMessage: {
+ name: 'receipt.field.receipt_message',
+ column: 'receipt_message',
+ type: 'text',
+ },
+ statement: {
+ name: 'receipt.field.statement',
+ type: 'text',
+ },
+ status: {
+ name: 'receipt.field.status',
+ type: 'enumeration',
+ options: [
+ { key: 'draft', label: 'receipt.field.status.draft' },
+ { key: 'closed', label: 'receipt.field.status.closed' },
+ ],
+ exportable: true,
+ },
+ entries: {
+ name: 'Entries',
+ accessor: 'entries',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ itemName: {
+ name: 'Item Name',
+ accessor: 'item.name',
+ },
+ rate: {
+ name: 'Item Rate',
+ accessor: 'rateFormatted',
+ },
+ quantity: {
+ name: 'Item Quantity',
+ accessor: 'quantityFormatted',
+ },
+ description: {
+ name: 'Item Description',
+ },
+ amount: {
+ name: 'Item Amount',
+ accessor: 'totalFormatted',
+ },
+ },
+ },
+ createdAt: {
+ name: 'receipt.field.created_at',
+ type: 'date',
+ },
+ },
fields2: {
receiptDate: {
name: 'Receipt Date',
@@ -126,7 +209,7 @@ export default {
relationModel: 'Item',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the item name or code."
+ importHint: 'Matches the item name or code.',
},
rate: {
name: 'invoice.field.rate',
diff --git a/packages/server/src/models/Vendor.Settings.ts b/packages/server/src/models/Vendor.Settings.ts
index 7f22d5ba4..7681dfa10 100644
--- a/packages/server/src/models/Vendor.Settings.ts
+++ b/packages/server/src/models/Vendor.Settings.ts
@@ -5,6 +5,7 @@ export default {
sortField: 'created_at',
},
importable: true,
+ exportable: true,
fields: {
first_name: {
name: 'vendor.field.first_name',
@@ -32,7 +33,7 @@ export default {
fieldType: 'text',
},
personal_phone: {
- name: 'vendor.field.personal_pone',
+ name: 'vendor.field.personal_phone',
column: 'personal_phone',
fieldType: 'text',
},
@@ -90,6 +91,154 @@ export default {
},
},
},
+ columns: {
+ firstName: {
+ name: 'vendor.field.first_name',
+ type: 'text',
+ },
+ lastName: {
+ name: 'vendor.field.last_name',
+ type: 'text',
+ },
+ displayName: {
+ name: 'vendor.field.display_name',
+ type: 'text',
+ },
+ email: {
+ name: 'vendor.field.email',
+ type: 'text',
+ },
+ workPhone: {
+ name: 'vendor.field.work_phone',
+ type: 'text',
+ },
+ personalPhone: {
+ name: 'vendor.field.personal_phone',
+ type: 'text',
+ },
+ companyName: {
+ name: 'vendor.field.company_name',
+ type: 'text',
+ },
+ website: {
+ name: 'vendor.field.website',
+ type: 'text',
+ },
+ balance: {
+ name: 'vendor.field.balance',
+ type: 'number',
+ },
+ openingBalance: {
+ name: 'vendor.field.opening_balance',
+ type: 'number',
+ },
+ openingBalanceAt: {
+ name: 'vendor.field.opening_balance_at',
+ type: 'date',
+ },
+ currencyCode: {
+ name: 'vendor.field.currency',
+ type: 'text',
+ },
+ status: {
+ name: 'vendor.field.status',
+ },
+ note: {
+ name: 'vendor.field.note',
+ type: 'text',
+ },
+ // Billing Address
+ billingAddress1: {
+ name: 'Billing Address 1',
+ column: 'billing_address1',
+ type: 'text',
+ exportable: true,
+ },
+ billingAddress2: {
+ name: 'Billing Address 2',
+ column: 'billing_address2',
+ type: 'text',
+ exportable: true,
+ },
+ billingAddressCity: {
+ name: 'Billing Address City',
+ column: 'billing_address_city',
+ type: 'text',
+ exportable: true,
+ },
+ billingAddressCountry: {
+ name: 'Billing Address Country',
+ column: 'billing_address_country',
+ type: 'text',
+ exportable: true,
+ },
+ billingAddressPostcode: {
+ name: 'Billing Address Postcode',
+ column: 'billing_address_postcode',
+ type: 'text',
+ exportable: true,
+ },
+ billingAddressState: {
+ name: 'Billing Address State',
+ column: 'billing_address_state',
+ type: 'text',
+ exportable: true,
+ },
+ billingAddressPhone: {
+ name: 'Billing Address Phone',
+ column: 'billing_address_phone',
+ type: 'text',
+ exportable: true,
+ },
+ // Shipping Address
+ shippingAddress1: {
+ name: 'Shipping Address 1',
+ column: 'shipping_address1',
+ type: 'text',
+ exportable: true,
+ },
+ shippingAddress2: {
+ name: 'Shipping Address 2',
+ column: 'shipping_address2',
+ type: 'text',
+ exportable: true,
+ },
+ shippingAddressCity: {
+ name: 'Shipping Address City',
+ column: 'shipping_address_city',
+ type: 'text',
+ exportable: true,
+ },
+ shippingAddressCountry: {
+ name: 'Shipping Address Country',
+ column: 'shipping_address_country',
+ type: 'text',
+ exportable: true,
+ },
+ shippingAddressPostcode: {
+ name: 'Shipping Address Postcode',
+ column: 'shipping_address_postcode',
+ type: 'text',
+ exportable: true,
+ },
+ shippingAddressState: {
+ name: 'Shipping Address State',
+ column: 'shipping_address_state',
+ type: 'text',
+ exportable: true,
+ },
+ shippingAddressPhone: {
+ name: 'Shipping Address Phone',
+ column: 'shipping_address_phone',
+ type: 'text',
+ exportable: true,
+ },
+ createdAt: {
+ name: 'vendor.field.created_at',
+ type: 'date',
+ exportable: true,
+ },
+ },
fields2: {
firstName: {
name: 'vendor.field.first_name',
diff --git a/packages/server/src/models/VendorCredit.Meta.ts b/packages/server/src/models/VendorCredit.Meta.ts
index 86a3aa103..b57cc275c 100644
--- a/packages/server/src/models/VendorCredit.Meta.ts
+++ b/packages/server/src/models/VendorCredit.Meta.ts
@@ -12,10 +12,14 @@ export default {
sortOrder: 'DESC',
sortField: 'name',
},
+ exportable: true,
+ exportFlattenOn: 'entries',
+
importable: true,
importAggregator: 'group',
importAggregateOn: 'entries',
importAggregateBy: 'vendorCreditNumber',
+
fields: {
vendor: {
name: 'vendor_credit.field.vendor',
@@ -76,6 +80,79 @@ export default {
fieldType: 'date',
},
},
+ columns: {
+ vendorId: {
+ name: 'Vendor',
+ type: 'relation',
+ accessor: 'vendor.displayName',
+ },
+ exchangeRate: {
+ name: 'Echange Rate',
+ type: 'text',
+ },
+ vendorCreditNumber: {
+ name: 'Vendor Credit No.',
+ type: 'text',
+ },
+ referenceNo: {
+ name: 'Refernece No.',
+ type: 'text',
+ },
+ vendorCreditDate: {
+ name: 'Vendor Credit Date',
+ type: 'date',
+ },
+ amount: {
+ name: 'Amount',
+ accessor: 'formattedAmount',
+ },
+ creditRemaining: {
+ name: 'Credits Remaining',
+ accessor: 'formattedCreditsRemaining',
+ },
+ refundedAmount: {
+ name: 'Refunded Amount',
+ accessor: 'refundedAmount',
+ },
+ invoicedAmount: {
+ name: 'Invoiced Amount',
+ accessor: 'formattedInvoicedAmount',
+ },
+ note: {
+ name: 'Note',
+ type: 'text',
+ },
+ open: {
+ name: 'Open',
+ type: 'boolean',
+ },
+ entries: {
+ name: 'Entries',
+ type: 'collection',
+ collectionOf: 'object',
+ columns: {
+ itemName: {
+ name: 'Item Name',
+ accessor: 'item.name',
+ },
+ rate: {
+ name: 'Item Rate',
+ accessor: 'rateFormatted',
+ },
+ quantity: {
+ name: 'Item Quantity',
+ accessor: 'quantityFormatted',
+ },
+ description: {
+ name: 'Item Description',
+ },
+ amount: {
+ name: 'Item Amount',
+ accessor: 'totalFormatted',
+ },
+ },
+ },
+ },
fields2: {
vendorId: {
name: 'Vendor',
@@ -122,7 +199,7 @@ export default {
relationModel: 'Item',
relationImportMatch: ['name', 'code'],
required: true,
- importHint: "Matches the item name or code."
+ importHint: 'Matches the item name or code.',
},
rate: {
name: 'Rate',
diff --git a/packages/server/src/models/WarehouseTransfer.Settings.ts b/packages/server/src/models/WarehouseTransfer.Settings.ts
index 8d0bc635d..d20064187 100644
--- a/packages/server/src/models/WarehouseTransfer.Settings.ts
+++ b/packages/server/src/models/WarehouseTransfer.Settings.ts
@@ -8,6 +8,34 @@ export default {
sortField: 'name',
sortOrder: 'DESC',
},
+ columns: {
+ date: {
+ name: 'warehouse_transfer.field.date',
+ type: 'date',
+ exportable: true,
+ },
+ transaction_number: {
+ name: 'warehouse_transfer.field.transaction_number',
+ type: 'text',
+ exportable: true,
+ },
+ status: {
+ name: 'warehouse_transfer.field.status',
+ fieldType: 'enumeration',
+ options: [
+ { key: 'draft', label: 'Draft' },
+ { key: 'in-transit', label: 'In Transit' },
+ { key: 'transferred', label: 'Transferred' },
+ ],
+ sortable: false,
+ },
+ created_at: {
+ name: 'warehouse_transfer.field.created_at',
+ column: 'created_at',
+ columnType: 'date',
+ fieldType: 'date',
+ },
+ },
fields: {
date: {
name: 'warehouse_transfer.field.date',
diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts
index 9c08e6533..9b05fe2c0 100644
--- a/packages/server/src/server.ts
+++ b/packages/server/src/server.ts
@@ -1,4 +1,5 @@
import 'reflect-metadata'; // We need this in order to use @Decorators
+import 'newrelic';
import './before';
import '@/config';
diff --git a/packages/server/src/services/Accounts/AccountsExportable.ts b/packages/server/src/services/Accounts/AccountsExportable.ts
new file mode 100644
index 000000000..86a6293d8
--- /dev/null
+++ b/packages/server/src/services/Accounts/AccountsExportable.ts
@@ -0,0 +1,31 @@
+import { Inject, Service } from 'typedi';
+import { AccountsApplication } from './AccountsApplication';
+import { Exportable } from '../Export/Exportable';
+import { IAccountsFilter, IAccountsStructureType } from '@/interfaces';
+
+@Service()
+export class AccountsExportable extends Exportable {
+ @Inject()
+ private accountsApplication: AccountsApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IAccountsFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ inactiveMode: false,
+ ...query,
+ structure: IAccountsStructureType.Flat,
+ pageSize: 12000,
+ page: 1,
+ } as IAccountsFilter;
+
+ return this.accountsApplication
+ .getAccounts(tenantId, parsedQuery)
+ .then((output) => output.accounts);
+ }
+}
diff --git a/packages/server/src/services/Authentication/AuthApplication.ts b/packages/server/src/services/Authentication/AuthApplication.ts
index a3cf0fc31..f900e63ac 100644
--- a/packages/server/src/services/Authentication/AuthApplication.ts
+++ b/packages/server/src/services/Authentication/AuthApplication.ts
@@ -1,16 +1,19 @@
-import { Service, Inject, Container } from 'typedi';
import {
+ IAuthGetMetaPOJO,
+ IPasswordReset,
IRegisterDTO,
ISystemUser,
- IPasswordReset,
- IAuthGetMetaPOJO,
ITenant,
} from '@/interfaces';
+import { SystemUser } from '@/system/models';
+import { Inject, Service } from 'typedi';
+import { AuthSendResetPassword } from './AuthSendResetPassword';
import { AuthSigninService } from './AuthSignin';
import { AuthSignupService } from './AuthSignup';
-import { AuthSendResetPassword } from './AuthSendResetPassword';
-import { GetAuthMeta } from './GetAuthMeta';
+import { AuthSignupConfirmService } from './AuthSignupConfirm';
+import { AuthSignupConfirmResend } from './AuthSignupResend';
import { GetAuthMe } from './GetAuthMe';
+import { GetAuthMeta } from './GetAuthMeta';
@Service()
export default class AuthenticationApplication {
@@ -20,6 +23,12 @@ export default class AuthenticationApplication {
@Inject()
private authSignupService: AuthSignupService;
+ @Inject()
+ private authSignupConfirmService: AuthSignupConfirmService;
+
+ @Inject()
+ private authSignUpConfirmResendService: AuthSignupConfirmResend;
+
@Inject()
private authResetPasswordService: AuthSendResetPassword;
@@ -49,6 +58,28 @@ export default class AuthenticationApplication {
return this.authSignupService.signUp(signupDTO);
}
+ /**
+ * Verfying the provided user's email after signin-up.
+ * @param {string} email
+ * @param {string} token
+ * @returns {Promise}
+ */
+ public async signUpConfirm(
+ email: string,
+ token: string
+ ): Promise {
+ return this.authSignupConfirmService.signUpConfirm(email, token);
+ }
+
+ /**
+ * Resends the confirmation email of the given system user.
+ * @param {number} userId - System user id.
+ * @returns {Promise}
+ */
+ public async signUpConfirmResend(userId: number) {
+ return this.authSignUpConfirmResendService.signUpConfirmResend(userId);
+ }
+
/**
* Generates and retrieve password reset token for the given user email.
* @param {string} email
diff --git a/packages/server/src/services/Authentication/AuthSignup.ts b/packages/server/src/services/Authentication/AuthSignup.ts
index b064a3d91..17c7f574c 100644
--- a/packages/server/src/services/Authentication/AuthSignup.ts
+++ b/packages/server/src/services/Authentication/AuthSignup.ts
@@ -1,5 +1,6 @@
-import { isEmpty, omit } from 'lodash';
+import { defaultTo, isEmpty, omit } from 'lodash';
import moment from 'moment';
+import crypto from 'crypto';
import { ServiceError } from '@/exceptions';
import {
IAuthSignedUpEventPayload,
@@ -42,6 +43,13 @@ export class AuthSignupService {
const hashedPassword = await hashPassword(signupDTO.password);
+ const verifyTokenCrypto = crypto.randomBytes(64).toString('hex');
+ const verifiedEnabed = defaultTo(config.signupConfirmation.enabled, false);
+ const verifyToken = verifiedEnabed ? verifyTokenCrypto : '';
+ const verified = !verifiedEnabed;
+
+ const inviteAcceptedAt = moment().format('YYYY-MM-DD');
+
// Triggers signin up event.
await this.eventPublisher.emitAsync(events.auth.signingUp, {
signupDTO,
@@ -50,10 +58,12 @@ export class AuthSignupService {
const tenant = await this.tenantsManager.createTenant();
const registeredUser = await systemUserRepository.create({
...omit(signupDTO, 'country'),
+ verifyToken,
+ verified,
active: true,
password: hashedPassword,
tenantId: tenant.id,
- inviteAcceptedAt: moment().format('YYYY-MM-DD'),
+ inviteAcceptedAt,
});
// Triggers signed up event.
await this.eventPublisher.emitAsync(events.auth.signUp, {
diff --git a/packages/server/src/services/Authentication/AuthSignupConfirm.ts b/packages/server/src/services/Authentication/AuthSignupConfirm.ts
new file mode 100644
index 000000000..b08a4bd2e
--- /dev/null
+++ b/packages/server/src/services/Authentication/AuthSignupConfirm.ts
@@ -0,0 +1,57 @@
+import { Inject, Service } from 'typedi';
+import { ServiceError } from '@/exceptions';
+import { SystemUser } from '@/system/models';
+import { ERRORS } from './_constants';
+import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
+import events from '@/subscribers/events';
+import {
+ IAuthSignUpVerifiedEventPayload,
+ IAuthSignUpVerifingEventPayload,
+} from '@/interfaces';
+
+@Service()
+export class AuthSignupConfirmService {
+ @Inject()
+ private eventPublisher: EventPublisher;
+
+ /**
+ * Verifies the provided user's email after signing-up.
+ * @throws {ServiceErrors}
+ * @param {IRegisterDTO} signupDTO
+ * @returns {Promise}
+ */
+ public async signUpConfirm(
+ email: string,
+ verifyToken: string
+ ): Promise {
+ const foundUser = await SystemUser.query().findOne({ email, verifyToken });
+
+ if (!foundUser) {
+ throw new ServiceError(ERRORS.SIGNUP_CONFIRM_TOKEN_INVALID);
+ }
+ const userId = foundUser.id;
+
+ // Triggers `signUpConfirming` event.
+ await this.eventPublisher.emitAsync(events.auth.signUpConfirming, {
+ email,
+ verifyToken,
+ userId,
+ } as IAuthSignUpVerifingEventPayload);
+
+ const updatedUser = await SystemUser.query().patchAndFetchById(
+ foundUser.id,
+ {
+ verified: true,
+ verifyToken: '',
+ }
+ );
+ // Triggers `signUpConfirmed` event.
+ await this.eventPublisher.emitAsync(events.auth.signUpConfirmed, {
+ email,
+ verifyToken,
+ userId,
+ } as IAuthSignUpVerifiedEventPayload);
+
+ return updatedUser as SystemUser;
+ }
+}
diff --git a/packages/server/src/services/Authentication/AuthSignupResend.ts b/packages/server/src/services/Authentication/AuthSignupResend.ts
new file mode 100644
index 000000000..8edb08f35
--- /dev/null
+++ b/packages/server/src/services/Authentication/AuthSignupResend.ts
@@ -0,0 +1,34 @@
+import { Inject, Service } from 'typedi';
+import { ServiceError } from '@/exceptions';
+import { SystemUser } from '@/system/models';
+import { ERRORS } from './_constants';
+
+@Service()
+export class AuthSignupConfirmResend {
+ @Inject('agenda')
+ private agenda: any;
+
+ /**
+ * Resends the email confirmation of the given user.
+ * @param {number} userId - User ID.
+ * @returns {Promise}
+ */
+ public async signUpConfirmResend(userId: number) {
+ const user = await SystemUser.query().findById(userId).throwIfNotFound();
+
+ // Throw error if the user is already verified.
+ if (user.verified) {
+ throw new ServiceError(ERRORS.USER_ALREADY_VERIFIED);
+ }
+ // Throw error if the verification token is not exist.
+ if (!user.verifyToken) {
+ throw new ServiceError(ERRORS.USER_ALREADY_VERIFIED);
+ }
+ const payload = {
+ email: user.email,
+ token: user.verifyToken,
+ fullName: user.firstName,
+ };
+ await this.agenda.now('send-signup-verify-mail', payload);
+ }
+}
diff --git a/packages/server/src/services/Authentication/AuthenticationMailMessages.ts b/packages/server/src/services/Authentication/AuthenticationMailMessages.ts
index c8c26ea0d..533315e72 100644
--- a/packages/server/src/services/Authentication/AuthenticationMailMessages.ts
+++ b/packages/server/src/services/Authentication/AuthenticationMailMessages.ts
@@ -33,4 +33,33 @@ export default class AuthenticationMailMesssages {
})
.send();
}
+
+ /**
+ * Sends signup verification mail.
+ * @param {string} email - Email address
+ * @param {string} fullName - User name.
+ * @param {string} token - Verification token.
+ * @returns {Promise}
+ */
+ public async sendSignupVerificationMail(
+ email: string,
+ fullName: string,
+ token: string
+ ) {
+ const verifyUrl = `${config.baseURL}/auth/email_confirmation?token=${token}&email=${email}`;
+
+ await new Mail()
+ .setSubject('Bigcapital - Verify your email')
+ .setView('mail/SignupVerifyEmail.html')
+ .setTo(email)
+ .setAttachments([
+ {
+ filename: 'bigcapital.png',
+ path: `${global.__views_dir}/images/bigcapital.png`,
+ cid: 'bigcapital_logo',
+ },
+ ])
+ .setData({ verifyUrl, fullName })
+ .send();
+ }
}
diff --git a/packages/server/src/services/Authentication/_constants.ts b/packages/server/src/services/Authentication/_constants.ts
index 8c62dbe6c..506525779 100644
--- a/packages/server/src/services/Authentication/_constants.ts
+++ b/packages/server/src/services/Authentication/_constants.ts
@@ -9,4 +9,6 @@ export const ERRORS = {
EMAIL_EXISTS: 'EMAIL_EXISTS',
SIGNUP_RESTRICTED_NOT_ALLOWED: 'SIGNUP_RESTRICTED_NOT_ALLOWED',
SIGNUP_RESTRICTED: 'SIGNUP_RESTRICTED',
+ SIGNUP_CONFIRM_TOKEN_INVALID: 'SIGNUP_CONFIRM_TOKEN_INVALID',
+ USER_ALREADY_VERIFIED: 'USER_ALREADY_VERIFIED',
};
diff --git a/packages/server/src/services/Authentication/events/SendVerfiyMailOnSignUp.ts b/packages/server/src/services/Authentication/events/SendVerfiyMailOnSignUp.ts
new file mode 100644
index 000000000..14f9aaa07
--- /dev/null
+++ b/packages/server/src/services/Authentication/events/SendVerfiyMailOnSignUp.ts
@@ -0,0 +1,30 @@
+import { IAuthSignedUpEventPayload } from '@/interfaces';
+import events from '@/subscribers/events';
+import { Inject } from 'typedi';
+
+export class SendVerfiyMailOnSignUp {
+ @Inject('agenda')
+ private agenda: any;
+
+ /**
+ * Attaches events with handles.
+ */
+ public attach(bus) {
+ bus.subscribe(events.auth.signUp, this.handleSendVerifyMailOnSignup);
+ }
+
+ /**
+ *
+ * @param {ITaxRateEditedPayload} payload -
+ */
+ private handleSendVerifyMailOnSignup = async ({
+ user,
+ }: IAuthSignedUpEventPayload) => {
+ const payload = {
+ email: user.email,
+ token: user.verifyToken,
+ fullName: user.firstName,
+ };
+ await this.agenda.now('send-signup-verify-mail', payload);
+ };
+}
diff --git a/packages/server/src/services/Authentication/jobs/SendVerifyMailJob.ts b/packages/server/src/services/Authentication/jobs/SendVerifyMailJob.ts
new file mode 100644
index 000000000..8e09053da
--- /dev/null
+++ b/packages/server/src/services/Authentication/jobs/SendVerifyMailJob.ts
@@ -0,0 +1,35 @@
+import { Container } from 'typedi';
+import AuthenticationMailMesssages from '@/services/Authentication/AuthenticationMailMessages';
+
+export class SendVerifyMailJob {
+ /**
+ * Constructor method.
+ * @param {Agenda} agenda
+ */
+ constructor(agenda) {
+ agenda.define(
+ 'send-signup-verify-mail',
+ { priority: 'high' },
+ this.handler.bind(this)
+ );
+ }
+
+ /**
+ * Handle send welcome mail job.
+ * @param {Job} job
+ * @param {Function} done
+ */
+ public async handler(job, done: Function): Promise {
+ const { data } = job.attrs;
+ const { email, fullName, token } = data;
+ const authService = Container.get(AuthenticationMailMesssages);
+
+ try {
+ await authService.sendSignupVerificationMail(email, fullName, token);
+ done();
+ } catch (error) {
+ console.log(error);
+ done(error);
+ }
+ }
+}
diff --git a/packages/server/src/services/Contacts/Customers/CustomersExportable.ts b/packages/server/src/services/Contacts/Customers/CustomersExportable.ts
new file mode 100644
index 000000000..8654fa31f
--- /dev/null
+++ b/packages/server/src/services/Contacts/Customers/CustomersExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { IItemsFilter } from '@/interfaces';
+import { CustomersApplication } from './CustomersApplication';
+import { Exportable } from '@/services/Export/Exportable';
+
+@Service()
+export class CustomersExportable extends Exportable {
+ @Inject()
+ private customersApplication: CustomersApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IItemsFilter) {
+ const parsedQuery = {
+ sortOrder: 'DESC',
+ columnSortBy: 'created_at',
+ page: 1,
+ ...query,
+ pageSize: 12,
+ } as IItemsFilter;
+
+ return this.customersApplication
+ .getCustomers(tenantId, parsedQuery)
+ .then((output) => output.customers);
+ }
+}
diff --git a/packages/server/src/services/Contacts/Vendors/VendorsExportable.ts b/packages/server/src/services/Contacts/Vendors/VendorsExportable.ts
new file mode 100644
index 000000000..c11f50050
--- /dev/null
+++ b/packages/server/src/services/Contacts/Vendors/VendorsExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { IItemsFilter } from '@/interfaces';
+import { Exportable } from '@/services/Export/Exportable';
+import { VendorsApplication } from './VendorsApplication';
+
+@Service()
+export class VendorsExportable extends Exportable {
+ @Inject()
+ private vendorsApplication: VendorsApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IItemsFilter) {
+ const parsedQuery = {
+ sortOrder: 'DESC',
+ columnSortBy: 'created_at',
+ page: 1,
+ ...query,
+ pageSize: 12,
+ } as IItemsFilter;
+
+ return this.vendorsApplication
+ .getVendors(tenantId, parsedQuery)
+ .then((output) => output.vendors);
+ }
+}
diff --git a/packages/server/src/services/CreditNotes/CreditNotesExportable.ts b/packages/server/src/services/CreditNotes/CreditNotesExportable.ts
new file mode 100644
index 000000000..09dae2a74
--- /dev/null
+++ b/packages/server/src/services/CreditNotes/CreditNotesExportable.ts
@@ -0,0 +1,30 @@
+import { Inject, Service } from 'typedi';
+import { ICreditNotesQueryDTO } from '@/interfaces';
+import { Exportable } from '@/services/Export/Exportable';
+import ListCreditNotes from './ListCreditNotes';
+
+@Service()
+export class CreditNotesExportable extends Exportable {
+ @Inject()
+ private getCreditNotes: ListCreditNotes;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId -
+ * @param {IVendorCreditsQueryDTO} query -
+ * @returns {}
+ */
+ public exportable(tenantId: number, query: ICreditNotesQueryDTO) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 12000,
+ } as ICreditNotesQueryDTO;
+
+ return this.getCreditNotes
+ .getCreditNotesList(tenantId, parsedQuery)
+ .then((output) => output.creditNotes);
+ }
+}
diff --git a/packages/server/src/services/CreditNotes/ListCreditNotes.ts b/packages/server/src/services/CreditNotes/ListCreditNotes.ts
index 498d3d74d..11ec2f7fa 100644
--- a/packages/server/src/services/CreditNotes/ListCreditNotes.ts
+++ b/packages/server/src/services/CreditNotes/ListCreditNotes.ts
@@ -45,7 +45,7 @@ export default class ListCreditNotes extends BaseCreditNotes {
);
const { results, pagination } = await CreditNote.query()
.onBuild((builder) => {
- builder.withGraphFetched('entries');
+ builder.withGraphFetched('entries.item');
builder.withGraphFetched('customer');
dynamicFilter.buildQuery()(builder);
})
diff --git a/packages/server/src/services/Expenses/ExpensesExportable.ts b/packages/server/src/services/Expenses/ExpensesExportable.ts
new file mode 100644
index 000000000..51362912f
--- /dev/null
+++ b/packages/server/src/services/Expenses/ExpensesExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { Exportable } from '../Export/Exportable';
+import { IExpensesFilter } from '@/interfaces';
+import { ExpensesApplication } from './ExpensesApplication';
+
+@Service()
+export class ExpensesExportable extends Exportable {
+ @Inject()
+ private expensesApplication: ExpensesApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IExpensesFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 12000,
+ } as IExpensesFilter;
+
+ return this.expensesApplication
+ .getExpenses(tenantId, parsedQuery)
+ .then((output) => output.expenses);
+ }
+}
diff --git a/packages/server/src/services/Export/ExportApplication.ts b/packages/server/src/services/Export/ExportApplication.ts
new file mode 100644
index 000000000..44a7dc73f
--- /dev/null
+++ b/packages/server/src/services/Export/ExportApplication.ts
@@ -0,0 +1,17 @@
+import { Inject, Service } from 'typedi';
+import { ExportResourceService } from './ExportService';
+
+@Service()
+export class ExportApplication {
+ @Inject()
+ private exportResource: ExportResourceService;
+
+ /**
+ * Exports the given resource to csv, xlsx or pdf format.
+ * @param {string} reosurce
+ * @param {string} format
+ */
+ public export(tenantId: number, resource: string, format: string) {
+ return this.exportResource.export(tenantId, resource, format);
+ }
+}
diff --git a/packages/server/src/services/Export/ExportRegistery.ts b/packages/server/src/services/Export/ExportRegistery.ts
new file mode 100644
index 000000000..33271f4ec
--- /dev/null
+++ b/packages/server/src/services/Export/ExportRegistery.ts
@@ -0,0 +1,49 @@
+import { camelCase, upperFirst } from 'lodash';
+import { Exportable } from './Exportable';
+
+export class ExportableRegistry {
+ private static instance: ExportableRegistry;
+ private exportables: Record;
+
+ /**
+ * Constructor method.
+ */
+ constructor() {
+ this.exportables = {};
+ }
+
+ /**
+ * Gets singleton instance of registry.
+ * @returns {ExportableRegistry}
+ */
+ public static getInstance(): ExportableRegistry {
+ if (!ExportableRegistry.instance) {
+ ExportableRegistry.instance = new ExportableRegistry();
+ }
+ return ExportableRegistry.instance;
+ }
+
+ /**
+ * Registers the given importable service.
+ * @param {string} resource
+ * @param {Exportable} importable
+ */
+ public registerExportable(resource: string, importable: Exportable): void {
+ const _resource = this.sanitizeResourceName(resource);
+ this.exportables[_resource] = importable;
+ }
+
+ /**
+ * Retrieves the importable service instance of the given resource name.
+ * @param {string} name
+ * @returns {Exportable}
+ */
+ public getExportable(name: string): Exportable {
+ const _name = this.sanitizeResourceName(name);
+ return this.exportables[_name];
+ }
+
+ private sanitizeResourceName(resource: string) {
+ return upperFirst(camelCase(resource));
+ }
+}
diff --git a/packages/server/src/services/Export/ExportResources.ts b/packages/server/src/services/Export/ExportResources.ts
new file mode 100644
index 000000000..b252bfab1
--- /dev/null
+++ b/packages/server/src/services/Export/ExportResources.ts
@@ -0,0 +1,72 @@
+import Container, { Service } from 'typedi';
+import { AccountsExportable } from '../Accounts/AccountsExportable';
+import { ExportableRegistry } from './ExportRegistery';
+import { ItemsExportable } from '../Items/ItemsExportable';
+import { CustomersExportable } from '../Contacts/Customers/CustomersExportable';
+import { VendorsExportable } from '../Contacts/Vendors/VendorsExportable';
+import { ExpensesExportable } from '../Expenses/ExpensesExportable';
+import { SaleInvoicesExportable } from '../Sales/Invoices/SaleInvoicesExportable';
+import { SaleEstimatesExportable } from '../Sales/Estimates/SaleEstimatesExportable';
+import { SaleReceiptsExportable } from '../Sales/Receipts/SaleReceiptsExportable';
+import { BillsExportable } from '../Purchases/Bills/BillsExportable';
+import { PaymentsReceivedExportable } from '../Sales/PaymentReceives/PaymentsReceivedExportable';
+import { BillPaymentExportable } from '../Purchases/BillPayments/BillPaymentExportable';
+import { ManualJournalsExportable } from '../ManualJournals/ManualJournalExportable';
+import { CreditNotesExportable } from '../CreditNotes/CreditNotesExportable';
+import { VendorCreditsExportable } from '../Purchases/VendorCredits/VendorCreditsExportable';
+import { ItemCategoriesExportable } from '../ItemCategories/ItemCategoriesExportable';
+
+@Service()
+export class ExportableResources {
+ private static registry: ExportableRegistry;
+
+ /**
+ * Consttuctor method.
+ */
+ constructor() {
+ this.boot();
+ }
+
+ /**
+ * Importable instances.
+ */
+ private importables = [
+ { resource: 'Account', exportable: AccountsExportable },
+ { resource: 'Item', exportable: ItemsExportable },
+ { resource: 'ItemCategory', exportable: ItemCategoriesExportable },
+ { resource: 'Customer', exportable: CustomersExportable },
+ { resource: 'Vendor', exportable: VendorsExportable },
+ { resource: 'Expense', exportable: ExpensesExportable },
+ { resource: 'SaleInvoice', exportable: SaleInvoicesExportable },
+ { resource: 'SaleEstimate', exportable: SaleEstimatesExportable },
+ { resource: 'SaleReceipt', exportable: SaleReceiptsExportable },
+ { resource: 'Bill', exportable: BillsExportable },
+ { resource: 'PaymentReceive', exportable: PaymentsReceivedExportable },
+ { resource: 'BillPayment', exportable: BillPaymentExportable },
+ { resource: 'ManualJournal', exportable: ManualJournalsExportable },
+ { resource: 'CreditNote', exportable: CreditNotesExportable },
+ { resource: 'VendorCredit', exportable: VendorCreditsExportable },
+ ];
+
+ /**
+ *
+ */
+ public get registry() {
+ return ExportableResources.registry;
+ }
+
+ /**
+ * Boots all the registered importables.
+ */
+ public boot() {
+ if (!ExportableResources.registry) {
+ const instance = ExportableRegistry.getInstance();
+
+ this.importables.forEach((importable) => {
+ const importableInstance = Container.get(importable.exportable);
+ instance.registerExportable(importable.resource, importableInstance);
+ });
+ ExportableResources.registry = instance;
+ }
+ }
+}
diff --git a/packages/server/src/services/Export/ExportService.ts b/packages/server/src/services/Export/ExportService.ts
new file mode 100644
index 000000000..c9c3dc432
--- /dev/null
+++ b/packages/server/src/services/Export/ExportService.ts
@@ -0,0 +1,161 @@
+import { Inject, Service } from 'typedi';
+import xlsx from 'xlsx';
+import * as R from 'ramda';
+import { get } from 'lodash';
+import { sanitizeResourceName } from '../Import/_utils';
+import ResourceService from '../Resource/ResourceService';
+import { ExportableResources } from './ExportResources';
+import { ServiceError } from '@/exceptions';
+import { Errors } from './common';
+import { IModelMeta, IModelMetaColumn } from '@/interfaces';
+import { flatDataCollections, getDataAccessor } from './utils';
+
+@Service()
+export class ExportResourceService {
+ @Inject()
+ private resourceService: ResourceService;
+
+ @Inject()
+ private exportableResources: ExportableResources;
+
+ /**
+ * Exports the given resource data through csv, xlsx or pdf.
+ * @param {number} tenantId - Tenant id.
+ * @param {string} resourceName - Resource name.
+ * @param {string} format - File format.
+ */
+ public async export(tenantId: number, resourceName: string, format: string = 'csv') {
+ const resource = sanitizeResourceName(resourceName);
+ const resourceMeta = this.getResourceMeta(tenantId, resource);
+
+ this.validateResourceMeta(resourceMeta);
+
+ const data = await this.getExportableData(tenantId, resource);
+ const transformed = this.transformExportedData(tenantId, resource, data);
+ const exportableColumns = this.getExportableColumns(resourceMeta);
+ const workbook = this.createWorkbook(transformed, exportableColumns);
+
+ return this.exportWorkbook(workbook, format);
+ }
+
+ /**
+ * Retrieves metadata for a specific resource.
+ * @param {number} tenantId - The tenant identifier.
+ * @param {string} resource - The name of the resource.
+ * @returns The metadata of the resource.
+ */
+ private getResourceMeta(tenantId: number, resource: string) {
+ return this.resourceService.getResourceMeta(tenantId, resource);
+ }
+
+ /**
+ * Validates if the resource metadata is exportable.
+ * @param {any} resourceMeta - The metadata of the resource.
+ * @throws {ServiceError} If the resource is not exportable or lacks columns.
+ */
+ private validateResourceMeta(resourceMeta: any) {
+ if (!resourceMeta.exportable || !resourceMeta.columns) {
+ throw new ServiceError(Errors.RESOURCE_NOT_EXPORTABLE);
+ }
+ }
+
+ /**
+ * Transforms the exported data based on the resource metadata.
+ * If the resource metadata specifies a flattening attribute (`exportFlattenOn`),
+ * the data will be flattened based on this attribute using the `flatDataCollections` utility function.
+ *
+ * @param {number} tenantId - The tenant identifier.
+ * @param {string} resource - The name of the resource.
+ * @param {Array>} data - The original data to be transformed.
+ * @returns {Array>} - The transformed data.
+ */
+ private transformExportedData(
+ tenantId: number,
+ resource: string,
+ data: Array>
+ ): Array> {
+ const resourceMeta = this.getResourceMeta(tenantId, resource);
+
+ return R.when>, Array>>(
+ R.always(Boolean(resourceMeta.exportFlattenOn)),
+ (data) => flatDataCollections(data, resourceMeta.exportFlattenOn),
+ data
+ );
+ }
+ /**
+ * Fetches exportable data for a given resource.
+ * @param {number} tenantId - The tenant identifier.
+ * @param {string} resource - The name of the resource.
+ * @returns A promise that resolves to the exportable data.
+ */
+ private async getExportableData(tenantId: number, resource: string) {
+ const exportable =
+ this.exportableResources.registry.getExportable(resource);
+ return exportable.exportable(tenantId, {});
+ }
+
+ /**
+ * Extracts columns that are marked as exportable from the resource metadata.
+ * @param {IModelMeta} resourceMeta - The metadata of the resource.
+ * @returns An array of exportable columns.
+ */
+ private getExportableColumns(resourceMeta: IModelMeta) {
+ const processColumns = (
+ columns: { [key: string]: IModelMetaColumn },
+ parent = ''
+ ) => {
+ return Object.entries(columns)
+ .filter(([_, value]) => value.exportable !== false)
+ .flatMap(([key, value]) => {
+ if (value.type === 'collection' && value.collectionOf === 'object') {
+ return processColumns(value.columns, key);
+ } else {
+ const group = parent;
+ return [
+ {
+ name: value.name,
+ type: value.type || 'text',
+ accessor: value.accessor || key,
+ group,
+ },
+ ];
+ }
+ });
+ };
+ return processColumns(resourceMeta.columns);
+ }
+
+ /**
+ * Creates a workbook from the provided data and columns.
+ * @param {any[]} data - The data to be included in the workbook.
+ * @param {any[]} exportableColumns - The columns to be included in the workbook.
+ * @returns The created workbook.
+ */
+ private createWorkbook(data: any[], exportableColumns: any[]) {
+ const workbook = xlsx.utils.book_new();
+ const worksheetData = data.map((item) =>
+ exportableColumns.map((col) => get(item, getDataAccessor(col)))
+ );
+
+ worksheetData.unshift(exportableColumns.map((col) => col.name));
+
+ const worksheet = xlsx.utils.aoa_to_sheet(worksheetData);
+ xlsx.utils.book_append_sheet(workbook, worksheet, 'Exported Data');
+
+ return workbook;
+ }
+
+ /**
+ * Exports the workbook in the specified format.
+ * @param {any} workbook - The workbook to be exported.
+ * @param {string} format - The format to export the workbook in.
+ * @returns The exported workbook data.
+ */
+ private exportWorkbook(workbook: any, format: string) {
+ if (format.toLowerCase() === 'csv') {
+ return xlsx.write(workbook, { type: 'buffer', bookType: 'csv' });
+ } else if (format.toLowerCase() === 'xlsx') {
+ return xlsx.write(workbook, { type: 'buffer', bookType: 'xlsx' });
+ }
+ }
+}
diff --git a/packages/server/src/services/Export/Exportable.ts b/packages/server/src/services/Export/Exportable.ts
new file mode 100644
index 000000000..0e8801678
--- /dev/null
+++ b/packages/server/src/services/Export/Exportable.ts
@@ -0,0 +1,22 @@
+export class Exportable {
+ /**
+ *
+ * @param tenantId
+ * @returns
+ */
+ public async exportable(
+ tenantId: number,
+ query: Record
+ ): Promise>> {
+ return [];
+ }
+
+ /**
+ *
+ * @param data
+ * @returns
+ */
+ public transform(data: Record) {
+ return data;
+ }
+}
diff --git a/packages/server/src/services/Export/common.ts b/packages/server/src/services/Export/common.ts
new file mode 100644
index 000000000..5895e3367
--- /dev/null
+++ b/packages/server/src/services/Export/common.ts
@@ -0,0 +1,3 @@
+export enum Errors {
+ RESOURCE_NOT_EXPORTABLE = 'RESOURCE_NOT_EXPORTABLE',
+}
diff --git a/packages/server/src/services/Export/utils.ts b/packages/server/src/services/Export/utils.ts
new file mode 100644
index 000000000..e1436d8ab
--- /dev/null
+++ b/packages/server/src/services/Export/utils.ts
@@ -0,0 +1,27 @@
+import { flatMap } from 'lodash';
+/**
+ * Flattens the data based on a specified attribute.
+ * @param data - The data to be flattened.
+ * @param flattenAttr - The attribute to be flattened.
+ * @returns - The flattened data.
+ */
+export const flatDataCollections = (
+ data: Record,
+ flattenAttr: string
+): Record[] => {
+ return flatMap(data, (item) =>
+ item[flattenAttr].map((entry) => ({
+ ...item,
+ [flattenAttr]: entry,
+ }))
+ );
+};
+
+/**
+ * Gets the data accessor for a given column.
+ * @param col - The column to get the data accessor for.
+ * @returns - The data accessor.
+ */
+export const getDataAccessor = (col: any) => {
+ return col.group ? `${col.group}.${col.accessor}` : col.accessor;
+};
diff --git a/packages/server/src/services/ItemCategories/ItemCategoriesExportable.ts b/packages/server/src/services/ItemCategories/ItemCategoriesExportable.ts
new file mode 100644
index 000000000..0cc8142ce
--- /dev/null
+++ b/packages/server/src/services/ItemCategories/ItemCategoriesExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { Exportable } from '../Export/Exportable';
+import { IAccountsFilter, IAccountsStructureType } from '@/interfaces';
+import ItemCategoriesService from './ItemCategoriesService';
+
+@Service()
+export class ItemCategoriesExportable extends Exportable {
+ @Inject()
+ private itemCategoriesApplication: ItemCategoriesService;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IAccountsFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ inactiveMode: false,
+ ...query,
+ structure: IAccountsStructureType.Flat,
+ } as IAccountsFilter;
+
+ return this.itemCategoriesApplication
+ .getItemCategoriesList(tenantId, parsedQuery, {})
+ .then((output) => output.itemCategories);
+ }
+}
diff --git a/packages/server/src/services/Items/ItemsExportable.ts b/packages/server/src/services/Items/ItemsExportable.ts
new file mode 100644
index 000000000..223b403d9
--- /dev/null
+++ b/packages/server/src/services/Items/ItemsExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { Exportable } from '../Export/Exportable';
+import { IItemsFilter } from '@/interfaces';
+import { ItemsApplication } from './ItemsApplication';
+
+@Service()
+export class ItemsExportable extends Exportable {
+ @Inject()
+ private itemsApplication: ItemsApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IItemsFilter) {
+ const parsedQuery = {
+ sortOrder: 'DESC',
+ columnSortBy: 'created_at',
+ page: 1,
+ ...query,
+ pageSize: 12,
+ } as IItemsFilter;
+
+ return this.itemsApplication
+ .getItems(tenantId, parsedQuery)
+ .then((output) => output.items);
+ }
+}
diff --git a/packages/server/src/services/ManualJournals/GetManualJournals.ts b/packages/server/src/services/ManualJournals/GetManualJournals.ts
index b6bca8848..d4dd35f4d 100644
--- a/packages/server/src/services/ManualJournals/GetManualJournals.ts
+++ b/packages/server/src/services/ManualJournals/GetManualJournals.ts
@@ -39,7 +39,7 @@ export class GetManualJournals {
tenantId: number,
filterDTO: IManualJournalsFilter
): Promise<{
- manualJournals: IManualJournal;
+ manualJournals: IManualJournal[];
pagination: IPaginationMeta;
filterMeta: IFilterMeta;
}> => {
diff --git a/packages/server/src/services/ManualJournals/ManualJournalExportable.ts b/packages/server/src/services/ManualJournals/ManualJournalExportable.ts
new file mode 100644
index 000000000..10d16e992
--- /dev/null
+++ b/packages/server/src/services/ManualJournals/ManualJournalExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { IManualJournalsFilter } from '@/interfaces';
+import { Exportable } from '../Export/Exportable';
+import { ManualJournalsApplication } from './ManualJournalsApplication';
+
+@Service()
+export class ManualJournalsExportable extends Exportable {
+ @Inject()
+ private manualJournalsApplication: ManualJournalsApplication;
+
+ /**
+ * Retrieves the manual journals data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IManualJournalsFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 12000,
+ } as IManualJournalsFilter;
+
+ return this.manualJournalsApplication
+ .getManualJournals(tenantId, parsedQuery)
+ .then((output) => output.manualJournals);
+ }
+}
diff --git a/packages/server/src/services/Purchases/BillPayments/BillPaymentExportable.ts b/packages/server/src/services/Purchases/BillPayments/BillPaymentExportable.ts
new file mode 100644
index 000000000..8c2a89b48
--- /dev/null
+++ b/packages/server/src/services/Purchases/BillPayments/BillPaymentExportable.ts
@@ -0,0 +1,28 @@
+import { Inject, Service } from 'typedi';
+import { Exportable } from '@/services/Export/Exportable';
+import { BillPaymentsApplication } from './BillPaymentsApplication';
+
+@Service()
+export class BillPaymentExportable extends Exportable {
+ @Inject()
+ private billPaymentsApplication: BillPaymentsApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: any) {
+ const parsedQuery = {
+ page: 1,
+ pageSize: 12,
+ ...query,
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ } as any;
+
+ return this.billPaymentsApplication
+ .getBillPayments(tenantId, parsedQuery)
+ .then((output) => output.billPayments);
+ }
+}
diff --git a/packages/server/src/services/Purchases/BillPayments/GetBillPayments.ts b/packages/server/src/services/Purchases/BillPayments/GetBillPayments.ts
index 2c9fda01f..9c4464403 100644
--- a/packages/server/src/services/Purchases/BillPayments/GetBillPayments.ts
+++ b/packages/server/src/services/Purchases/BillPayments/GetBillPayments.ts
@@ -31,7 +31,7 @@ export class GetBillPayments {
tenantId: number,
filterDTO: IBillPaymentsFilter
): Promise<{
- billPayments: IBillPayment;
+ billPayments: IBillPayment[];
pagination: IPaginationMeta;
filterMeta: IFilterMeta;
}> {
diff --git a/packages/server/src/services/Purchases/Bills/BillsApplication.ts b/packages/server/src/services/Purchases/Bills/BillsApplication.ts
index 1ffdd5aa4..2593b03b2 100644
--- a/packages/server/src/services/Purchases/Bills/BillsApplication.ts
+++ b/packages/server/src/services/Purchases/Bills/BillsApplication.ts
@@ -99,7 +99,7 @@ export class BillsApplication {
tenantId: number,
filterDTO: IBillsFilter
): Promise<{
- bills: IBill;
+ bills: IBill[];
pagination: IPaginationMeta;
filterMeta: IFilterMeta;
}> {
diff --git a/packages/server/src/services/Purchases/Bills/BillsExportable.ts b/packages/server/src/services/Purchases/Bills/BillsExportable.ts
new file mode 100644
index 000000000..a45783643
--- /dev/null
+++ b/packages/server/src/services/Purchases/Bills/BillsExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { IBillsFilter } from '@/interfaces';
+import { Exportable } from '@/services/Export/Exportable';
+import { BillsApplication } from './BillsApplication';
+
+@Service()
+export class BillsExportable extends Exportable {
+ @Inject()
+ private billsApplication: BillsApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: IBillsFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 12000,
+ } as IBillsFilter;
+
+ return this.billsApplication
+ .getBills(tenantId, parsedQuery)
+ .then((output) => output.bills);
+ }
+}
diff --git a/packages/server/src/services/Purchases/Bills/GetBills.ts b/packages/server/src/services/Purchases/Bills/GetBills.ts
index 1ea19797d..73abc55da 100644
--- a/packages/server/src/services/Purchases/Bills/GetBills.ts
+++ b/packages/server/src/services/Purchases/Bills/GetBills.ts
@@ -49,6 +49,7 @@ export class GetBills {
const { results, pagination } = await Bill.query()
.onBuild((builder) => {
builder.withGraphFetched('vendor');
+ builder.withGraphFetched('entries.item');
dynamicFilter.buildQuery()(builder);
})
.pagination(filter.page - 1, filter.pageSize);
diff --git a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts
index be1431ac2..282b6f08e 100644
--- a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts
+++ b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts
@@ -14,6 +14,7 @@ export class VendorCreditTransformer extends Transformer {
'formattedSubtotal',
'formattedVendorCreditDate',
'formattedCreditsRemaining',
+ 'formattedInvoicedAmount',
'entries',
];
};
@@ -58,6 +59,17 @@ export class VendorCreditTransformer extends Transformer {
});
};
+ /**
+ * Retrieves the formatted invoiced amount.
+ * @param credit
+ * @returns {string}
+ */
+ protected formattedInvoicedAmount = (credit) => {
+ return formatNumber(credit.invoicedAmount, {
+ currencyCode: credit.currencyCode,
+ });
+ };
+
/**
* Retrieves the entries of the bill.
* @param {IVendorCredit} vendorCredit
diff --git a/packages/server/src/services/Purchases/VendorCredits/VendorCreditsExportable.ts b/packages/server/src/services/Purchases/VendorCredits/VendorCreditsExportable.ts
new file mode 100644
index 000000000..4e0963165
--- /dev/null
+++ b/packages/server/src/services/Purchases/VendorCredits/VendorCreditsExportable.ts
@@ -0,0 +1,30 @@
+import { Inject, Service } from 'typedi';
+import { IVendorCreditsQueryDTO } from '@/interfaces';
+import ListVendorCredits from './ListVendorCredits';
+import { Exportable } from '@/services/Export/Exportable';
+
+@Service()
+export class VendorCreditsExportable extends Exportable {
+ @Inject()
+ private getVendorCredits: ListVendorCredits;
+
+ /**
+ * Retrieves the vendor credits data to exportable sheet.
+ * @param {number} tenantId -
+ * @param {IVendorCreditsQueryDTO} query -
+ * @returns {}
+ */
+ public exportable(tenantId: number, query: IVendorCreditsQueryDTO) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 12000,
+ } as IVendorCreditsQueryDTO;
+
+ return this.getVendorCredits
+ .getVendorCredits(tenantId, parsedQuery)
+ .then((output) => output.vendorCredits);
+ }
+}
diff --git a/packages/server/src/services/Resource/ResourceService.ts b/packages/server/src/services/Resource/ResourceService.ts
index 653599d05..3e0ffbafe 100644
--- a/packages/server/src/services/Resource/ResourceService.ts
+++ b/packages/server/src/services/Resource/ResourceService.ts
@@ -105,7 +105,11 @@ export default class ResourceService {
const $enumerationType = (field) =>
field.fieldType === 'enumeration' ? field : undefined;
- const $hasFields = (field) => 'undefined' !== typeof field.fields ? field : undefined;
+ const $hasFields = (field) =>
+ 'undefined' !== typeof field.fields ? field : undefined;
+
+ const $hasColumns = (column) =>
+ 'undefined' !== typeof column.columns ? column : undefined;
const naviagations = [
['fields', qim.$each, 'name'],
@@ -113,6 +117,8 @@ export default class ResourceService {
['fields2', qim.$each, 'name'],
['fields2', qim.$each, $enumerationType, 'options', qim.$each, 'label'],
['fields2', qim.$each, $hasFields, 'fields', qim.$each, 'name'],
+ ['columns', qim.$each, 'name'],
+ ['columns', qim.$each, $hasColumns, 'columns', qim.$each, 'name'],
];
return this.i18nService.i18nApply(naviagations, meta, tenantId);
}
diff --git a/packages/server/src/services/Sales/Estimates/GetSaleEstimates.ts b/packages/server/src/services/Sales/Estimates/GetSaleEstimates.ts
index e0b53adb3..bba1db943 100644
--- a/packages/server/src/services/Sales/Estimates/GetSaleEstimates.ts
+++ b/packages/server/src/services/Sales/Estimates/GetSaleEstimates.ts
@@ -51,6 +51,7 @@ export class GetSaleEstimates {
.onBuild((builder) => {
builder.withGraphFetched('customer');
builder.withGraphFetched('entries');
+ builder.withGraphFetched('entries.item');
dynamicFilter.buildQuery()(builder);
})
.pagination(filter.page - 1, filter.pageSize);
diff --git a/packages/server/src/services/Sales/Estimates/SaleEstimatesExportable.ts b/packages/server/src/services/Sales/Estimates/SaleEstimatesExportable.ts
new file mode 100644
index 000000000..455805df9
--- /dev/null
+++ b/packages/server/src/services/Sales/Estimates/SaleEstimatesExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { ISalesInvoicesFilter } from '@/interfaces';
+import { Exportable } from '@/services/Export/Exportable';
+import { SaleEstimatesApplication } from './SaleEstimatesApplication';
+
+@Service()
+export class SaleEstimatesExportable extends Exportable {
+ @Inject()
+ private saleEstimatesApplication: SaleEstimatesApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: ISalesInvoicesFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 12000,
+ } as ISalesInvoicesFilter;
+
+ return this.saleEstimatesApplication
+ .getSaleEstimates(tenantId, parsedQuery)
+ .then((output) => output.salesEstimates);
+ }
+}
diff --git a/packages/server/src/services/Sales/Invoices/GetSaleInvoices.ts b/packages/server/src/services/Sales/Invoices/GetSaleInvoices.ts
index b1d9b93db..569aceccb 100644
--- a/packages/server/src/services/Sales/Invoices/GetSaleInvoices.ts
+++ b/packages/server/src/services/Sales/Invoices/GetSaleInvoices.ts
@@ -49,7 +49,7 @@ export class GetSaleInvoices {
);
const { results, pagination } = await SaleInvoice.query()
.onBuild((builder) => {
- builder.withGraphFetched('entries');
+ builder.withGraphFetched('entries.item');
builder.withGraphFetched('customer');
dynamicFilter.buildQuery()(builder);
})
diff --git a/packages/server/src/services/Sales/Invoices/SaleInvoicesExportable.ts b/packages/server/src/services/Sales/Invoices/SaleInvoicesExportable.ts
new file mode 100644
index 000000000..e806b0939
--- /dev/null
+++ b/packages/server/src/services/Sales/Invoices/SaleInvoicesExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { ISalesInvoicesFilter } from '@/interfaces';
+import { SaleInvoiceApplication } from './SaleInvoicesApplication';
+import { Exportable } from '@/services/Export/Exportable';
+
+@Service()
+export class SaleInvoicesExportable extends Exportable {
+ @Inject()
+ private saleInvoicesApplication: SaleInvoiceApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: ISalesInvoicesFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 120000,
+ } as ISalesInvoicesFilter;
+
+ return this.saleInvoicesApplication
+ .getSaleInvoices(tenantId, parsedQuery)
+ .then((output) => output.salesInvoices);
+ }
+}
diff --git a/packages/server/src/services/Sales/PaymentReceives/PaymentsReceivedExportable.ts b/packages/server/src/services/Sales/PaymentReceives/PaymentsReceivedExportable.ts
new file mode 100644
index 000000000..932c0f5f3
--- /dev/null
+++ b/packages/server/src/services/Sales/PaymentReceives/PaymentsReceivedExportable.ts
@@ -0,0 +1,30 @@
+import { Inject, Service } from 'typedi';
+import { IAccountsStructureType, IPaymentReceivesFilter } from '@/interfaces';
+import { Exportable } from '@/services/Export/Exportable';
+import { PaymentReceivesApplication } from './PaymentReceivesApplication';
+
+@Service()
+export class PaymentsReceivedExportable extends Exportable {
+ @Inject()
+ private paymentReceivedApp: PaymentReceivesApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @param {IPaymentReceivesFilter} query -
+ * @returns
+ */
+ public exportable(tenantId: number, query: IPaymentReceivesFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ inactiveMode: false,
+ ...query,
+ structure: IAccountsStructureType.Flat,
+ } as IPaymentReceivesFilter;
+
+ return this.paymentReceivedApp
+ .getPaymentReceives(tenantId, parsedQuery)
+ .then((output) => output.paymentReceives);
+ }
+}
diff --git a/packages/server/src/services/Sales/Receipts/GetSaleReceipts.ts b/packages/server/src/services/Sales/Receipts/GetSaleReceipts.ts
index 24150e349..1916c5e75 100644
--- a/packages/server/src/services/Sales/Receipts/GetSaleReceipts.ts
+++ b/packages/server/src/services/Sales/Receipts/GetSaleReceipts.ts
@@ -11,6 +11,9 @@ import { SaleReceiptTransformer } from './SaleReceiptTransformer';
import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable';
import DynamicListingService from '@/services/DynamicListing/DynamicListService';
+interface GetSaleReceiptsSettings {
+ fetchEntriesGraph?: boolean;
+}
@Service()
export class GetSaleReceipts {
@Inject()
@@ -50,7 +53,7 @@ export class GetSaleReceipts {
.onBuild((builder) => {
builder.withGraphFetched('depositAccount');
builder.withGraphFetched('customer');
- builder.withGraphFetched('entries');
+ builder.withGraphFetched('entries.item');
dynamicFilter.buildQuery()(builder);
})
diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptsExportable.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptsExportable.ts
new file mode 100644
index 000000000..199c2e5a8
--- /dev/null
+++ b/packages/server/src/services/Sales/Receipts/SaleReceiptsExportable.ts
@@ -0,0 +1,29 @@
+import { Inject, Service } from 'typedi';
+import { ISalesReceiptsFilter } from '@/interfaces';
+import { Exportable } from '@/services/Export/Exportable';
+import { SaleReceiptApplication } from './SaleReceiptApplication';
+
+@Service()
+export class SaleReceiptsExportable extends Exportable {
+ @Inject()
+ private saleReceiptsApp: SaleReceiptApplication;
+
+ /**
+ * Retrieves the accounts data to exportable sheet.
+ * @param {number} tenantId
+ * @returns
+ */
+ public exportable(tenantId: number, query: ISalesReceiptsFilter) {
+ const parsedQuery = {
+ sortOrder: 'desc',
+ columnSortBy: 'created_at',
+ ...query,
+ page: 1,
+ pageSize: 12,
+ } as ISalesReceiptsFilter;
+
+ return this.saleReceiptsApp
+ .getSaleReceipts(tenantId, parsedQuery)
+ .then((output) => output.data);
+ }
+}
diff --git a/packages/server/src/subscribers/events.ts b/packages/server/src/subscribers/events.ts
index 0243cd172..b96cadf95 100644
--- a/packages/server/src/subscribers/events.ts
+++ b/packages/server/src/subscribers/events.ts
@@ -9,6 +9,9 @@ export default {
signUp: 'onSignUp',
signingUp: 'onSigningUp',
+ signUpConfirming: 'signUpConfirming',
+ signUpConfirmed: 'signUpConfirmed',
+
sendingResetPassword: 'onSendingResetPassword',
sendResetPassword: 'onSendResetPassword',
diff --git a/packages/server/src/system/migrations/20240425100821_add_confirmation_columns_to_users.js b/packages/server/src/system/migrations/20240425100821_add_confirmation_columns_to_users.js
new file mode 100644
index 000000000..fada1380f
--- /dev/null
+++ b/packages/server/src/system/migrations/20240425100821_add_confirmation_columns_to_users.js
@@ -0,0 +1,12 @@
+exports.up = function (knex) {
+ return knex.schema
+ .table('users', (table) => {
+ table.string('verify_token');
+ table.boolean('verified').defaultTo(false);
+ })
+ .then(() => {
+ return knex('USERS').update({ verified: true });
+ });
+};
+
+exports.down = (knex) => {};
diff --git a/packages/server/src/system/models/SystemUser.ts b/packages/server/src/system/models/SystemUser.ts
index a341ccedf..ce17186df 100644
--- a/packages/server/src/system/models/SystemUser.ts
+++ b/packages/server/src/system/models/SystemUser.ts
@@ -4,6 +4,12 @@ import SystemModel from '@/system/models/SystemModel';
import SoftDeleteQueryBuilder from '@/collection/SoftDeleteQueryBuilder';
export default class SystemUser extends SystemModel {
+ firstName!: string;
+ lastName!: string;
+ verified!: boolean;
+ inviteAcceptedAt!: Date | null;
+ deletedAt!: Date | null;
+
/**
* Table name.
*/
@@ -29,23 +35,33 @@ export default class SystemUser extends SystemModel {
* Virtual attributes.
*/
static get virtualAttributes() {
- return ['fullName', 'isDeleted', 'isInviteAccepted'];
+ return ['fullName', 'isDeleted', 'isInviteAccepted', 'isVerified'];
}
/**
- *
+ * Detarmines whether the user is deleted.
+ * @returns {boolean}
*/
get isDeleted() {
return !!this.deletedAt;
}
/**
- *
+ * Detarmines whether the sent invite is accepted.
+ * @returns {boolean}
*/
get isInviteAccepted() {
return !!this.inviteAcceptedAt;
}
+ /**
+ * Detarmines whether the user's email is verified.
+ * @returns {boolean}
+ */
+ get isVerified() {
+ return !!this.verified;
+ }
+
/**
* Full name attribute.
*/
diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts
index 919cd7af7..ceef5f572 100644
--- a/packages/server/src/utils/index.ts
+++ b/packages/server/src/utils/index.ts
@@ -1,6 +1,6 @@
import bcrypt from 'bcryptjs';
import moment from 'moment';
-import _ from 'lodash';
+import _, { isEmpty } from 'lodash';
import path from 'path';
import * as R from 'ramda';
@@ -329,7 +329,7 @@ const booleanValuesRepresentingTrue: string[] = ['true', '1'];
const booleanValuesRepresentingFalse: string[] = ['false', '0'];
const normalizeValue = (value: any): string =>
- value.toString().trim().toLowerCase();
+ value?.toString().trim().toLowerCase();
const booleanValues: string[] = [
...booleanValuesRepresentingTrue,
@@ -338,7 +338,7 @@ const booleanValues: string[] = [
export const parseBoolean = (value: any, defaultValue: T): T | boolean => {
const normalizedValue = normalizeValue(value);
- if (booleanValues.indexOf(normalizedValue) === -1) {
+ if (isEmpty(value) || booleanValues.indexOf(normalizedValue) === -1) {
return defaultValue;
}
return booleanValuesRepresentingTrue.indexOf(normalizedValue) !== -1;
diff --git a/packages/server/views/mail/SignupVerifyEmail.html b/packages/server/views/mail/SignupVerifyEmail.html
new file mode 100644
index 000000000..637e78c12
--- /dev/null
+++ b/packages/server/views/mail/SignupVerifyEmail.html
@@ -0,0 +1,424 @@
+
+
+
+
+
+ Bigcapital | Reset your password
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Verify your email
+
+ Hi {{ fullName }},
+ To continue setting up your Bigcapital account, please verify that this is your email address.
+
+
+ If this was a mistake, just ignore this email and nothing will happen.
+ This is an automatically generated email please do not reply to this email.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/webapp/Dockerfile b/packages/webapp/Dockerfile
index 41054a525..72db05769 100644
--- a/packages/webapp/Dockerfile
+++ b/packages/webapp/Dockerfile
@@ -7,8 +7,8 @@ WORKDIR /app
# Copy application dependency manifests to the container image.
COPY ./package*.json ./
COPY ./pnpm-lock.yaml ./pnpm-lock.yaml
-COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY ./lerna.json ./lerna.json
+COPY ./pnpm-workspace.yaml ./pnpm-workspace.yaml
COPY ./packages/webapp/package*.json ./packages/webapp/
# Install application dependencies
@@ -24,7 +24,7 @@ RUN pnpm install
# Build webapp package
COPY ./packages/webapp /app/packages/webapp
-RUN npm run build:webapp
+RUN pnpm run build:webapp
FROM nginx
diff --git a/packages/webapp/src/components/App.tsx b/packages/webapp/src/components/App.tsx
index 949a1861f..4f43a8613 100644
--- a/packages/webapp/src/components/App.tsx
+++ b/packages/webapp/src/components/App.tsx
@@ -9,13 +9,24 @@ import 'moment/locale/ar-ly';
import 'moment/locale/es-us';
import AppIntlLoader from './AppIntlLoader';
-import PrivateRoute from '@/components/Guards/PrivateRoute';
+import { EnsureAuthenticated } from '@/components/Guards/EnsureAuthenticated';
import GlobalErrors from '@/containers/GlobalErrors/GlobalErrors';
import DashboardPrivatePages from '@/components/Dashboard/PrivatePages';
import { Authentication } from '@/containers/Authentication/Authentication';
+import LazyLoader from '@/components/LazyLoader';
import { SplashScreen, DashboardThemeProvider } from '../components';
import { queryConfig } from '../hooks/query/base';
+import { EnsureUserEmailVerified } from './Guards/EnsureUserEmailVerified';
+import { EnsureAuthNotAuthenticated } from './Guards/EnsureAuthNotAuthenticated';
+import { EnsureUserEmailNotVerified } from './Guards/EnsureUserEmailNotVerified';
+
+const EmailConfirmation = LazyLoader({
+ loader: () => import('@/containers/Authentication/EmailConfirmation'),
+});
+const RegisterVerify = LazyLoader({
+ loader: () => import('@/containers/Authentication/RegisterVerify'),
+});
/**
* App inner.
@@ -26,9 +37,30 @@ function AppInsider({ history }) {
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
diff --git a/packages/webapp/src/components/Dashboard/DashboardBoot.tsx b/packages/webapp/src/components/Dashboard/DashboardBoot.tsx
index bae18273e..0d105c112 100644
--- a/packages/webapp/src/components/Dashboard/DashboardBoot.tsx
+++ b/packages/webapp/src/components/Dashboard/DashboardBoot.tsx
@@ -1,5 +1,5 @@
// @ts-nocheck
-import React from 'react';
+import React, { useEffect } from 'react';
import {
useAuthenticatedAccount,
useCurrentOrganization,
@@ -116,6 +116,14 @@ export function useApplicationBoot() {
isBooted.current = true;
},
);
+ // Reset the loading states once the hook unmount.
+ useEffect(
+ () => () => {
+ isAuthUserLoading && !isBooted.current && stopLoading();
+ isOrgLoading && !isBooted.current && stopLoading();
+ },
+ [isAuthUserLoading, isOrgLoading, stopLoading],
+ );
return {
isLoading: isOrgLoading || isAuthUserLoading,
diff --git a/packages/webapp/src/components/DialogsContainer.tsx b/packages/webapp/src/components/DialogsContainer.tsx
index fc1195545..02f18d071 100644
--- a/packages/webapp/src/components/DialogsContainer.tsx
+++ b/packages/webapp/src/components/DialogsContainer.tsx
@@ -51,6 +51,7 @@ import EstimateMailDialog from '@/containers/Sales/Estimates/EstimateMailDialog/
import ReceiptMailDialog from '@/containers/Sales/Receipts/ReceiptMailDialog/ReceiptMailDialog';
import PaymentMailDialog from '@/containers/Sales/PaymentReceives/PaymentMailDialog/PaymentMailDialog';
import { ConnectBankDialog } from '@/containers/CashFlow/ConnectBankDialog';
+import { ExportDialog } from '@/containers/Dialogs/ExportDialog';
/**
* Dialogs container.
@@ -148,6 +149,8 @@ export default function DialogsContainer() {
+
+
);
}
diff --git a/packages/webapp/src/components/Guards/EnsureAuthNotAuthenticated.tsx b/packages/webapp/src/components/Guards/EnsureAuthNotAuthenticated.tsx
new file mode 100644
index 000000000..97539a32d
--- /dev/null
+++ b/packages/webapp/src/components/Guards/EnsureAuthNotAuthenticated.tsx
@@ -0,0 +1,22 @@
+// @ts-nocheck
+import React from 'react';
+import { Redirect } from 'react-router-dom';
+import { useIsAuthenticated } from '@/hooks/state';
+
+interface EnsureAuthNotAuthenticatedProps {
+ children: React.ReactNode;
+ redirectTo?: string;
+}
+
+export function EnsureAuthNotAuthenticated({
+ children,
+ redirectTo = '/',
+}: EnsureAuthNotAuthenticatedProps) {
+ const isAuthenticated = useIsAuthenticated();
+
+ return !isAuthenticated ? (
+ <>{children}>
+ ) : (
+
+ );
+}
diff --git a/packages/webapp/src/components/Guards/EnsureAuthenticated.tsx b/packages/webapp/src/components/Guards/EnsureAuthenticated.tsx
new file mode 100644
index 000000000..0a223a9ae
--- /dev/null
+++ b/packages/webapp/src/components/Guards/EnsureAuthenticated.tsx
@@ -0,0 +1,22 @@
+// @ts-nocheck
+import React from 'react';
+import { Redirect } from 'react-router-dom';
+import { useIsAuthenticated } from '@/hooks/state';
+
+interface EnsureAuthenticatedProps {
+ children: React.ReactNode;
+ redirectTo?: string;
+}
+
+export function EnsureAuthenticated({
+ children,
+ redirectTo = '/auth/login',
+}: EnsureAuthenticatedProps) {
+ const isAuthenticated = useIsAuthenticated();
+
+ return isAuthenticated ? (
+ <>{children}>
+ ) : (
+
+ );
+}
diff --git a/packages/webapp/src/components/Guards/EnsureUserEmailNotVerified.tsx b/packages/webapp/src/components/Guards/EnsureUserEmailNotVerified.tsx
new file mode 100644
index 000000000..ac35b649f
--- /dev/null
+++ b/packages/webapp/src/components/Guards/EnsureUserEmailNotVerified.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { Redirect } from 'react-router-dom';
+import { useAuthUserVerified } from '@/hooks/state';
+
+interface EnsureUserEmailNotVerifiedProps {
+ children: React.ReactNode;
+ redirectTo?: string;
+}
+
+/**
+ * Higher Order Component to ensure that the user's email is not verified.
+ * If is verified, redirects to the inner setup page.
+ */
+export function EnsureUserEmailNotVerified({
+ children,
+ redirectTo = '/',
+}: EnsureUserEmailNotVerifiedProps) {
+ const isAuthVerified = useAuthUserVerified();
+
+ if (isAuthVerified) {
+ return ;
+ }
+ return <>{children}>;
+}
diff --git a/packages/webapp/src/components/Guards/EnsureUserEmailVerified.tsx b/packages/webapp/src/components/Guards/EnsureUserEmailVerified.tsx
new file mode 100644
index 000000000..f24d93533
--- /dev/null
+++ b/packages/webapp/src/components/Guards/EnsureUserEmailVerified.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { Redirect } from 'react-router-dom';
+import { useAuthUserVerified } from '@/hooks/state';
+
+interface EnsureUserEmailVerifiedProps {
+ children: React.ReactNode;
+ redirectTo?: string;
+}
+
+/**
+ * Higher Order Component to ensure that the user's email is verified.
+ * If not verified, redirects to the email verification page.
+ */
+export function EnsureUserEmailVerified({
+ children,
+ redirectTo = '/auth/register/verify',
+}: EnsureUserEmailVerifiedProps) {
+ const isAuthVerified = useAuthUserVerified();
+
+ if (!isAuthVerified) {
+ return ;
+ }
+ return <>{children}>;
+}
diff --git a/packages/webapp/src/components/Guards/PrivateRoute.tsx b/packages/webapp/src/components/Guards/PrivateRoute.tsx
deleted file mode 100644
index 8e8e167b9..000000000
--- a/packages/webapp/src/components/Guards/PrivateRoute.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-// @ts-nocheck
-import React from 'react';
-import BodyClassName from 'react-body-classname';
-import { Redirect } from 'react-router-dom';
-import { useIsAuthenticated } from '@/hooks/state';
-
-export default function PrivateRoute({ component: Component, ...rest }) {
- const isAuthenticated = useIsAuthenticated();
-
- return (
-
- {isAuthenticated ? (
-
- ) : (
-
- )}
-
- );
-}
diff --git a/packages/webapp/src/constants/dialogs.ts b/packages/webapp/src/constants/dialogs.ts
index 34d30bd46..cd425ce58 100644
--- a/packages/webapp/src/constants/dialogs.ts
+++ b/packages/webapp/src/constants/dialogs.ts
@@ -73,5 +73,6 @@ export enum DialogsName {
CustomerTransactionsPdfPreview = 'CustomerTransactionsPdfPreview',
VendorTransactionsPdfPreview = 'VendorTransactionsPdfPreview',
GeneralLedgerPdfPreview = 'GeneralLedgerPdfPreview',
- SalesTaxLiabilitySummaryPdfPreview = 'SalesTaxLiabilitySummaryPdfPreview'
+ SalesTaxLiabilitySummaryPdfPreview = 'SalesTaxLiabilitySummaryPdfPreview',
+ Export = 'Export',
}
diff --git a/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalActionsBar.tsx b/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalActionsBar.tsx
index 676322da1..c6a8c447a 100644
--- a/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalActionsBar.tsx
+++ b/packages/webapp/src/containers/Accounting/JournalsLanding/ManualJournalActionsBar.tsx
@@ -18,7 +18,7 @@ import {
Can,
If,
DashboardActionViewsList,
- DashboardActionsBar
+ DashboardActionsBar,
} from '@/components';
import { useRefreshJournals } from '@/hooks/query/manualJournals';
import { useManualJournalsContext } from './ManualJournalsListProvider';
@@ -31,6 +31,7 @@ import withSettingsActions from '@/containers/Settings/withSettingsActions';
import withDialogActions from '@/containers/Dialog/withDialogActions';
import { compose } from '@/utils';
+import { DialogsName } from '@/constants/dialogs';
/**
* Manual journal actions bar.
@@ -47,6 +48,9 @@ function ManualJournalActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogActions
+ openDialog
}) {
// History context.
const history = useHistory();
@@ -75,13 +79,18 @@ function ManualJournalActionsBar({
// Handle import button click.
const handleImportBtnClick = () => {
history.push('/manual-journals/import');
- }
+ };
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
addSetting('manualJournals', 'tableSize', size);
};
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'manual_journal' });
+ };
+
return (
@@ -140,6 +149,7 @@ function ManualJournalActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
{
history.push('/accounts/import');
};
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'account' });
+ };
return (
@@ -182,17 +186,18 @@ function AccountsActionsBar({
icon={ }
text={ }
/>
- }
- text={ }
- />
}
text={ }
onClick={handleImportBtnClick}
/>
+ }
+ text={ }
+ onClick={handleExportBtnClick}
+ />
+
+
+
+
+
+ {children}
+
+
+ );
+}
+
+const AuthPage = styled.div``;
+const AuthInsider = styled.div`
+ width: 384px;
+ margin: 0 auto;
+ margin-bottom: 40px;
+ padding-top: 80px;
+`;
+
+const AuthLogo = styled.div`
+ text-align: center;
+ margin-bottom: 40px;
+`;
diff --git a/packages/webapp/src/containers/Authentication/Authentication.tsx b/packages/webapp/src/containers/Authentication/Authentication.tsx
index 8b05570c4..408dc78f0 100644
--- a/packages/webapp/src/containers/Authentication/Authentication.tsx
+++ b/packages/webapp/src/containers/Authentication/Authentication.tsx
@@ -1,24 +1,16 @@
// @ts-nocheck
-import React from 'react';
-import { Redirect, Route, Switch, useLocation } from 'react-router-dom';
+import { Route, Switch, useLocation } from 'react-router-dom';
import BodyClassName from 'react-body-classname';
import styled from 'styled-components';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import authenticationRoutes from '@/routes/authentication';
import { Icon, FormattedMessage as T } from '@/components';
-import { useIsAuthenticated } from '@/hooks/state';
import { AuthMetaBootProvider } from './AuthMetaBoot';
import '@/style/pages/Authentication/Auth.scss';
export function Authentication() {
- const to = { pathname: '/' };
- const isAuthenticated = useIsAuthenticated();
-
- if (isAuthenticated) {
- return ;
- }
return (
diff --git a/packages/webapp/src/containers/Authentication/EmailConfirmation.tsx b/packages/webapp/src/containers/Authentication/EmailConfirmation.tsx
new file mode 100644
index 000000000..e7fe66d5e
--- /dev/null
+++ b/packages/webapp/src/containers/Authentication/EmailConfirmation.tsx
@@ -0,0 +1,46 @@
+// @ts-nocheck
+import { useEffect, useMemo } from 'react';
+import { useLocation, useHistory } from 'react-router-dom';
+import { useAuthSignUpVerify } from '@/hooks/query';
+import { AppToaster } from '@/components';
+import { Intent } from '@blueprintjs/core';
+
+function useQuery() {
+ const { search } = useLocation();
+ return useMemo(() => new URLSearchParams(search), [search]);
+}
+
+export default function EmailConfirmation() {
+ const { mutateAsync: authSignupVerify } = useAuthSignUpVerify();
+ const history = useHistory();
+ const query = useQuery();
+
+ const token = query.get('token');
+ const email = query.get('email');
+
+ useEffect(() => {
+ if (!token || !email) {
+ history.push('/auth/login');
+ }
+ }, [history, token, email]);
+
+ useEffect(() => {
+ authSignupVerify({ token, email })
+ .then(() => {
+ AppToaster.show({
+ message: 'Your email has been verified, Congrats!',
+ intent: Intent.SUCCESS,
+ });
+ history.push('/');
+ })
+ .catch(() => {
+ AppToaster.show({
+ message: 'Something went wrong',
+ intent: Intent.DANGER,
+ });
+ history.push('/');
+ });
+ }, [token, email, authSignupVerify, history]);
+
+ return null;
+}
diff --git a/packages/webapp/src/containers/Authentication/RegisterVerify.module.scss b/packages/webapp/src/containers/Authentication/RegisterVerify.module.scss
new file mode 100644
index 000000000..f0754f470
--- /dev/null
+++ b/packages/webapp/src/containers/Authentication/RegisterVerify.module.scss
@@ -0,0 +1,18 @@
+
+.root {
+ text-align: center;
+}
+
+.title{
+ font-size: 18px;
+ font-weight: 600;
+ margin-bottom: 0.5rem;
+ color: #252A31;
+}
+
+.description{
+ margin-bottom: 1rem;
+ font-size: 15px;
+ line-height: 1.45;
+ color: #404854;
+}
\ No newline at end of file
diff --git a/packages/webapp/src/containers/Authentication/RegisterVerify.tsx b/packages/webapp/src/containers/Authentication/RegisterVerify.tsx
new file mode 100644
index 000000000..a707bfdb0
--- /dev/null
+++ b/packages/webapp/src/containers/Authentication/RegisterVerify.tsx
@@ -0,0 +1,70 @@
+// @ts-nocheck
+import { Button, Intent } from '@blueprintjs/core';
+import AuthInsider from './AuthInsider';
+import { AuthInsiderCard } from './_components';
+import styles from './RegisterVerify.module.scss';
+import { AppToaster, Stack } from '@/components';
+import { useAuthActions } from '@/hooks/state';
+import { useAuthSignUpVerifyResendMail } from '@/hooks/query';
+import { AuthContainer } from './AuthContainer';
+
+export default function RegisterVerify() {
+ const { setLogout } = useAuthActions();
+ const { mutateAsync: resendSignUpVerifyMail, isLoading } =
+ useAuthSignUpVerifyResendMail();
+
+ const handleResendMailBtnClick = () => {
+ resendSignUpVerifyMail()
+ .then(() => {
+ AppToaster.show({
+ intent: Intent.SUCCESS,
+ message: 'The verification mail has sent successfully.',
+ });
+ })
+ .catch(() => {
+ AppToaster.show({
+ intent: Intent.DANGER,
+ message: 'Something went wrong.',
+ });
+ });
+ };
+ const handleSignOutBtnClick = () => {
+ setLogout();
+ };
+
+ return (
+
+
+
+ Please verify your email
+
+ We sent an email to asdahmed@gmail.com Click the
+ link inside to get started.
+
+
+
+
+ Resend email
+
+
+
+ Not my email
+
+
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx b/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx
index 6d6c4bbbe..0515fdf8d 100644
--- a/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx
+++ b/packages/webapp/src/containers/CashFlow/CashFlowAccounts/CashFlowAccountsActionsBar.tsx
@@ -92,13 +92,13 @@ function CashFlowAccountsActionsBar({
/>
}
- text={ }
+ icon={ }
+ text={ }
/>
}
- text={ }
+ icon={ }
+ text={ }
/>
@@ -117,7 +117,7 @@ function CashFlowAccountsActionsBar({
text={'Connect to Bank / Credit Card'}
onClick={handleConnectToBank}
/>
-
+
{
+ openDialog(DialogsName.Export, { resource: 'customer' });
+ };
+
return (
@@ -154,6 +164,7 @@ function CustomerActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
;
+}
diff --git a/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogForm.schema.ts b/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogForm.schema.ts
new file mode 100644
index 000000000..88a2060d6
--- /dev/null
+++ b/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogForm.schema.ts
@@ -0,0 +1,9 @@
+// @ts-nocheck
+import * as Yup from 'yup';
+
+const Schema = Yup.object().shape({
+ resource: Yup.string().required().label('Resource'),
+ format: Yup.string().required().label('Format'),
+});
+
+export const ExportDialogFormSchema = Schema;
diff --git a/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogForm.tsx b/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogForm.tsx
new file mode 100644
index 000000000..bd919d0d5
--- /dev/null
+++ b/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogForm.tsx
@@ -0,0 +1,78 @@
+// @ts-nocheck
+import { Formik } from 'formik';
+
+import { compose, transformToForm } from '@/utils';
+
+import { ExportDialogFormSchema } from './ExportDialogForm.schema';
+import { ExportDialogFormContent } from './ExportDialogFormContent';
+import { useResourceExport } from '@/hooks/query/FinancialReports/use-export';
+import { ExportFormInitialValues } from './type';
+import { AppToaster } from '@/components';
+import { Intent } from '@blueprintjs/core';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
+
+// Default initial form values.
+const defaultInitialValues = {
+ resource: '',
+ format: 'csv',
+};
+
+interface ExportDialogFormProps {
+ initialValues?: ExportFormInitialValues;
+}
+
+/**
+ * Account form dialog content.
+ */
+function ExportDialogFormRoot({
+ // #ownProps
+ initialValues,
+
+ // #withDialogActions
+ closeDialog,
+}: ExportDialogFormProps) {
+ const { mutateAsync: mutateExport } = useResourceExport();
+
+ // Callbacks handles form submit.
+ const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
+ setSubmitting(true);
+ const { resource, format } = values;
+
+ mutateExport({ resource, format })
+ .then(() => {
+ setSubmitting(false);
+ closeDialog(DialogsName.Export);
+ })
+ .catch(() => {
+ setSubmitting(false);
+ AppToaster.show({
+ intent: Intent.DANGER,
+ message: 'Something went wrong!',
+ });
+ });
+ };
+
+ // Form initial values in create and edit mode.
+ const initialFormValues = {
+ ...defaultInitialValues,
+ /**
+ * We only care about the fields in the form. Previously unfilled optional
+ * values such as `notes` come back from the API as null, so remove those
+ * as well.
+ */
+ ...transformToForm(initialValues, defaultInitialValues),
+ };
+ return (
+
+
+
+ );
+}
+
+export const ExportDialogForm =
+ compose(withDialogActions)(ExportDialogFormRoot);
diff --git a/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogFormContent.tsx b/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogFormContent.tsx
new file mode 100644
index 000000000..06cd8bf7e
--- /dev/null
+++ b/packages/webapp/src/containers/Dialogs/ExportDialog/ExportDialogFormContent.tsx
@@ -0,0 +1,63 @@
+// @ts-nocheck
+import { FFormGroup, FRadioGroup, FSelect, Group } from '@/components';
+import { Button, Intent, Radio } from '@blueprintjs/core';
+import { Form, useFormikContext } from 'formik';
+import { ExportResources } from './constants';
+import styles from './ExportDialogContent.module.scss';
+import { compose } from '@/utils';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
+
+function ExportDialogFormContentRoot({
+ // #withDialogActions
+ closeDialog,
+}) {
+ const { isSubmitting } = useFormikContext();
+ const handleCancelBtnClick = () => {
+ closeDialog(DialogsName.Export);
+ };
+
+ return (
+
+ );
+}
+
+export const ExportDialogFormContent = compose(withDialogActions)(
+ ExportDialogFormContentRoot,
+);
diff --git a/packages/webapp/src/containers/Dialogs/ExportDialog/constants.ts b/packages/webapp/src/containers/Dialogs/ExportDialog/constants.ts
new file mode 100644
index 000000000..b971a8433
--- /dev/null
+++ b/packages/webapp/src/containers/Dialogs/ExportDialog/constants.ts
@@ -0,0 +1,17 @@
+export const ExportResources = [
+ { value: 'account', text: 'Accounts' },
+ { value: 'item', text: 'Items' },
+ { value: 'item_category', text: 'Item Categories' },
+ { value: 'customer', text: 'Customers' },
+ { value: 'vendor', text: 'Vendors' },
+ { value: 'manual_journal', text: 'Manual Journal' },
+ { value: 'expense', text: 'Expenses' },
+ { value: 'sale_invoice', text: 'Invoices' },
+ { value: 'sale_estimate', text: ' Estimates' },
+ { value: 'sale_receipt', text: 'Receipts' },
+ { value: 'payment_receive', text: 'Payments Received' },
+ { value: 'credit_note', text: 'Credit Notes' },
+ { value: 'bill', text: 'Bills' },
+ { value: 'bill_payment', text: 'Bill Payments' },
+ { value: 'vendor_credit', text: 'Vendor Credits' },
+];
diff --git a/packages/webapp/src/containers/Dialogs/ExportDialog/index.tsx b/packages/webapp/src/containers/Dialogs/ExportDialog/index.tsx
new file mode 100644
index 000000000..2ca7e562a
--- /dev/null
+++ b/packages/webapp/src/containers/Dialogs/ExportDialog/index.tsx
@@ -0,0 +1,31 @@
+// @ts-nocheck
+import React, { lazy } from 'react';
+import { Dialog, DialogSuspense, FormattedMessage as T } from '@/components';
+import withDialogRedux from '@/components/DialogReduxConnect';
+import { compose } from '@/utils';
+
+const ExportDialogContent = lazy(() => import('./ExportDialogContent'));
+
+// User form dialog.
+function ExportDialogRoot({ dialogName, payload, isOpen }) {
+ const { resource = null, format = null } = payload;
+
+ return (
+
+
+
+
+
+ );
+}
+
+export const ExportDialog = compose(withDialogRedux())(ExportDialogRoot);
diff --git a/packages/webapp/src/containers/Dialogs/ExportDialog/type.ts b/packages/webapp/src/containers/Dialogs/ExportDialog/type.ts
new file mode 100644
index 000000000..448c30cbc
--- /dev/null
+++ b/packages/webapp/src/containers/Dialogs/ExportDialog/type.ts
@@ -0,0 +1,6 @@
+
+
+export interface ExportFormInitialValues {
+ resource?: string;
+ format?: string;
+}
\ No newline at end of file
diff --git a/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpenseActionsBar.tsx b/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpenseActionsBar.tsx
index e5c7368e4..1a1fb0209 100644
--- a/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpenseActionsBar.tsx
+++ b/packages/webapp/src/containers/Expenses/ExpensesLanding/ExpenseActionsBar.tsx
@@ -33,6 +33,7 @@ import withDialogActions from '@/containers/Dialog/withDialogActions';
import withSettings from '@/containers/Settings/withSettings';
import { compose } from '@/utils';
+import { DialogsName } from '@/constants/dialogs';
/**
* Expenses actions bar.
@@ -49,6 +50,9 @@ function ExpensesActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogActions
+ openDialog,
}) {
// History context.
const history = useHistory();
@@ -63,7 +67,6 @@ function ExpensesActionsBar({
const onClickNewExpense = () => {
history.push('/expenses/new');
};
-
// Handle delete button click.
const handleBulkDelete = () => {};
@@ -73,21 +76,23 @@ function ExpensesActionsBar({
viewSlug: view ? view.slug : null,
});
};
-
// Handle click a refresh
const handleRefreshBtnClick = () => {
refresh();
};
-
// Handle the import button click.
const handleImportBtnClick = () => {
history.push('/expenses/import');
- }
-
+ };
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
addSetting('expenses', 'tableSize', size);
};
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'expense' });
+ };
+
return (
@@ -146,6 +151,7 @@ function ExpensesActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
{
+ openDialog(DialogsName.Export, { resource: 'item' });
+ }
+
return (
@@ -154,6 +164,7 @@ function ItemsActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
{
+ openDialog(DialogsName.Export, { resource: 'item_category' });
+ };
return (
@@ -105,6 +110,7 @@ function ItemsCategoryActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
diff --git a/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsActionsBar.tsx b/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsActionsBar.tsx
index da5415e45..3d0fbb2ff 100644
--- a/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsActionsBar.tsx
+++ b/packages/webapp/src/containers/Purchases/Bills/BillsLanding/BillsActionsBar.tsx
@@ -32,6 +32,8 @@ import withSettingsActions from '@/containers/Settings/withSettingsActions';
import { useBillsListContext } from './BillsListProvider';
import { useRefreshBills } from '@/hooks/query/bills';
import { compose } from '@/utils';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
/**
* Bills actions bar.
@@ -48,6 +50,9 @@ function BillActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogActions
+ openDialog,
}) {
const history = useHistory();
@@ -81,7 +86,12 @@ function BillActionsBar({
// Handle the import button click.
const handleImportBtnClick = () => {
history.push('/bills/import');
- }
+ };
+
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'bill' });
+ };
return (
@@ -141,6 +151,7 @@ function BillActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
@@ -170,4 +181,5 @@ export default compose(
withSettings(({ billsettings }) => ({
billsTableSize: billsettings?.tableSize,
})),
+ withDialogActions,
)(BillActionsBar);
diff --git a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.tsx b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.tsx
index e4a7b1ff9..7ba8e7531 100644
--- a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.tsx
+++ b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNotesLanding/VendorsCreditNoteActionsBar.tsx
@@ -22,14 +22,16 @@ import {
import { useVendorsCreditNoteListContext } from './VendorsCreditNoteListProvider';
import { VendorCreditAction, AbilitySubject } from '@/constants/abilityOption';
+
+import withVendorsCreditNotesActions from './withVendorsCreditNotesActions';
import withSettings from '@/containers/Settings/withSettings';
import withSettingsActions from '@/containers/Settings/withSettingsActions';
import withVendorsCreditNotes from './withVendorsCreditNotes';
-import withVendorsCreditNotesActions from './withVendorsCreditNotesActions';
-
+import withDialogActions from '@/containers/Dialog/withDialogActions';
import withVendorActions from './withVendorActions';
import { compose } from '@/utils';
+import { DialogsName } from '@/constants/dialogs';
/**
* Vendors Credit note table actions bar.
@@ -48,6 +50,9 @@ function VendorsCreditNoteActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogActions
+ openDialog,
}) {
const history = useHistory();
@@ -77,8 +82,13 @@ function VendorsCreditNoteActionsBar({
// Handle import button click.
const handleImportBtnClick = () => {
- history.push('/vendor-credits/import')
- }
+ history.push('/vendor-credits/import');
+ };
+
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'vendor_credit' });
+ };
return (
@@ -128,6 +138,7 @@ function VendorsCreditNoteActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
({
creditNoteTableSize: vendorsCreditNoteSetting?.tableSize,
})),
+ withDialogActions,
)(VendorsCreditNoteActionsBar);
diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeActionsBar.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeActionsBar.tsx
index 1d7e3d67d..f269f63ed 100644
--- a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeActionsBar.tsx
+++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentsLanding/PaymentMadeActionsBar.tsx
@@ -33,6 +33,8 @@ import { useRefreshPaymentMades } from '@/hooks/query/paymentMades';
import { PaymentMadeAction, AbilitySubject } from '@/constants/abilityOption';
import { compose } from '@/utils';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
/**
* Payment made actions bar.
@@ -47,6 +49,9 @@ function PaymentMadeActionsBar({
// #withSettings
paymentMadesTableSize,
+ // #withDialogActions
+ openDialog,
+
// #withSettingsActions
addSetting,
}) {
@@ -81,7 +86,12 @@ function PaymentMadeActionsBar({
// Handle the import button click.
const handleImportBtnClick = () => {
history.push('/payment-mades/import');
- }
+ };
+
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'bill_payment' });
+ };
return (
@@ -139,6 +149,7 @@ function PaymentMadeActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
@@ -168,4 +179,5 @@ export default compose(
withSettings(({ billPaymentSettings }) => ({
paymentMadesTableSize: billPaymentSettings?.tableSize,
})),
+ withDialogActions,
)(PaymentMadeActionsBar);
diff --git a/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.tsx b/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.tsx
index 7c8294858..7e55e6a13 100644
--- a/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.tsx
+++ b/packages/webapp/src/containers/Sales/CreditNotes/CreditNotesLanding/CreditNotesActionsBar.tsx
@@ -25,8 +25,10 @@ import withCreditNotes from './withCreditNotes';
import withCreditNotesActions from './withCreditNotesActions';
import withSettings from '@/containers/Settings/withSettings';
import withSettingsActions from '@/containers/Settings/withSettingsActions';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
import { compose } from '@/utils';
+import { DialogsName } from '@/constants/dialogs';
/**
* Credit note table actions bar.
@@ -43,6 +45,9 @@ function CreditNotesActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogActions
+ openDialog,
}) {
const history = useHistory();
@@ -74,6 +79,11 @@ function CreditNotesActionsBar({
history.push('/credit-notes/import');
};
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'credit_note' });
+ };
+
return (
@@ -122,6 +132,7 @@ function CreditNotesActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
({
creditNoteTableSize: creditNoteSettings?.tableSize,
})),
+ withDialogActions,
)(CreditNotesActionsBar);
diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesActionsBar.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesActionsBar.tsx
index ff4f5d6bd..2b374d2db 100644
--- a/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesActionsBar.tsx
+++ b/packages/webapp/src/containers/Sales/Estimates/EstimatesLanding/EstimatesActionsBar.tsx
@@ -31,6 +31,8 @@ import { useEstimatesListContext } from './EstimatesListProvider';
import { useRefreshEstimates } from '@/hooks/query/estimates';
import { SaleEstimateAction, AbilitySubject } from '@/constants/abilityOption';
import { compose } from '@/utils';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
/**
* Estimates list actions bar.
@@ -45,6 +47,9 @@ function EstimateActionsBar({
// #withSettings
estimatesTableSize,
+ // #withDialogActions
+ openDialog,
+
// #withSettingsActions
addSetting,
}) {
@@ -80,7 +85,11 @@ function EstimateActionsBar({
// Handle the import button click.
const handleImportBtnClick = () => {
history.push('/estimates/import');
- }
+ };
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'sale_estimate' });
+ };
return (
@@ -141,6 +150,7 @@ function EstimateActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
({
estimatesTableSize: estimatesSettings?.tableSize,
})),
+ withDialogActions
)(EstimateActionsBar);
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx
index cdfa295a3..8f4a4d686 100644
--- a/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx
@@ -29,6 +29,8 @@ import withInvoiceActions from './withInvoiceActions';
import withSettings from '@/containers/Settings/withSettings';
import withSettingsActions from '@/containers/Settings/withSettingsActions';
import { compose } from '@/utils';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
/**
* Invoices table actions bar.
@@ -45,6 +47,9 @@ function InvoiceActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogsActions
+ openDialog
}) {
const history = useHistory();
@@ -79,6 +84,11 @@ function InvoiceActionsBar({
history.push('/invoices/import');
};
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'sale_invoice' });
+ };
+
return (
@@ -135,6 +145,7 @@ function InvoiceActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
({
invoicesTableSize: invoiceSettings?.tableSize,
})),
+ withDialogActions,
)(InvoiceActionsBar);
diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceiveActionsBar.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceiveActionsBar.tsx
index c1d510c1d..42bf63666 100644
--- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceiveActionsBar.tsx
+++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentsLanding/PaymentReceiveActionsBar.tsx
@@ -26,6 +26,7 @@ import withPaymentReceives from './withPaymentReceives';
import withPaymentReceivesActions from './withPaymentReceivesActions';
import withSettings from '@/containers/Settings/withSettings';
import withSettingsActions from '@/containers/Settings/withSettingsActions';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
import {
PaymentReceiveAction,
AbilitySubject,
@@ -33,6 +34,7 @@ import {
import { usePaymentReceivesListContext } from './PaymentReceiptsListProvider';
import { useRefreshPaymentReceive } from '@/hooks/query/paymentReceives';
import { compose } from '@/utils';
+import { DialogsName } from '@/constants/dialogs';
/**
* Payment receives actions bar.
@@ -49,6 +51,9 @@ function PaymentReceiveActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogActions
+ openDialog,
}) {
// History context.
const history = useHistory();
@@ -82,6 +87,10 @@ function PaymentReceiveActionsBar({
const handleImportBtnClick = () => {
history.push('/payment-receives/import');
};
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'payment_receive' });
+ };
return (
@@ -139,6 +148,7 @@ function PaymentReceiveActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
@@ -169,4 +179,5 @@ export default compose(
withSettings(({ paymentReceiveSettings }) => ({
paymentReceivesTableSize: paymentReceiveSettings?.tableSize,
})),
+ withDialogActions,
)(PaymentReceiveActionsBar);
diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptsLanding/ReceiptActionsBar.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptsLanding/ReceiptActionsBar.tsx
index f27a505c9..f4ecfe39f 100644
--- a/packages/webapp/src/containers/Sales/Receipts/ReceiptsLanding/ReceiptActionsBar.tsx
+++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptsLanding/ReceiptActionsBar.tsx
@@ -35,6 +35,8 @@ import { useRefreshReceipts } from '@/hooks/query/receipts';
import { SaleReceiptAction, AbilitySubject } from '@/constants/abilityOption';
import { compose } from '@/utils';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
/**
* Receipts actions bar.
@@ -49,6 +51,9 @@ function ReceiptActionsBar({
// #withSettings
receiptsTableSize,
+ // #withDialogActions
+ openDialog,
+
// #withSettingsActions
addSetting,
}) {
@@ -86,6 +91,11 @@ function ReceiptActionsBar({
history.push('/receipts/import');
};
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'sale_receipt' });
+ };
+
return (
@@ -145,6 +155,7 @@ function ReceiptActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
({
receiptsTableSize: receiptSettings?.tableSize,
})),
+ withDialogActions,
)(ReceiptActionsBar);
diff --git a/packages/webapp/src/containers/Vendors/VendorsLanding/VendorActionsBar.tsx b/packages/webapp/src/containers/Vendors/VendorsLanding/VendorActionsBar.tsx
index bd54a6b16..86c11ea8a 100644
--- a/packages/webapp/src/containers/Vendors/VendorsLanding/VendorActionsBar.tsx
+++ b/packages/webapp/src/containers/Vendors/VendorsLanding/VendorActionsBar.tsx
@@ -31,8 +31,10 @@ import withVendors from './withVendors';
import withVendorsActions from './withVendorsActions';
import withSettings from '@/containers/Settings/withSettings';
import withSettingsActions from '@/containers/Settings/withSettingsActions';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
import { compose } from '@/utils';
+import { DialogsName } from '@/constants/dialogs';
/**
* Vendors actions bar.
@@ -50,6 +52,9 @@ function VendorActionsBar({
// #withSettingsActions
addSetting,
+
+ // #withDialogActions
+ openDialog,
}) {
const history = useHistory();
@@ -83,10 +88,17 @@ function VendorActionsBar({
const handleTableRowSizeChange = (size) => {
addSetting('vendors', 'tableSize', size);
};
+
// Handle import button success.
const handleImportBtnSuccess = () => {
history.push('/vendors/import');
};
+
+ // Handle the export button click.
+ const handleExportBtnClick = () => {
+ openDialog(DialogsName.Export, { resource: 'vendor' });
+ };
+
return (
@@ -138,6 +150,7 @@ function VendorActionsBar({
className={Classes.MINIMAL}
icon={ }
text={ }
+ onClick={handleExportBtnClick}
/>
({
vendorsTableSize: vendorsSettings?.tableSize,
})),
+ withDialogActions,
)(VendorActionsBar);
diff --git a/packages/webapp/src/hooks/query/FinancialReports/use-export.ts b/packages/webapp/src/hooks/query/FinancialReports/use-export.ts
new file mode 100644
index 000000000..63e1e5d74
--- /dev/null
+++ b/packages/webapp/src/hooks/query/FinancialReports/use-export.ts
@@ -0,0 +1,38 @@
+// @ts-nocheck
+import { downloadFile } from '@/hooks/useDownloadFile';
+import useApiRequest from '@/hooks/useRequest';
+import { AxiosError } from 'axios';
+import { useMutation } from 'react-query';
+
+interface ResourceExportValues {
+ resource: string;
+ format: string;
+}
+/**
+ * Initiates a download of the balance sheet in XLSX format.
+ * @param {Object} query - The query parameters for the request.
+ * @param {Object} args - Additional configurations for the download.
+ * @returns {Function} A function to trigger the file download.
+ */
+export const useResourceExport = () => {
+ const apiRequest = useApiRequest();
+
+ return useMutation((data: ResourceExportValues) => {
+ return apiRequest
+ .get('/export', {
+ responseType: 'blob',
+ headers: {
+ accept:
+ data.format === 'xlsx' ? 'application/xlsx' : 'application/csv',
+ },
+ params: {
+ resource: data.resource,
+ format: data.format,
+ },
+ })
+ .then((res) => {
+ downloadFile(res.data, `${data.resource}.${data.format}`);
+ return res;
+ });
+ });
+};
diff --git a/packages/webapp/src/hooks/query/authentication.tsx b/packages/webapp/src/hooks/query/authentication.tsx
index b2877ec8e..16ee67d7f 100644
--- a/packages/webapp/src/hooks/query/authentication.tsx
+++ b/packages/webapp/src/hooks/query/authentication.tsx
@@ -137,7 +137,7 @@ export const useAuthResetPassword = (props) => {
*/
export const useAuthMetadata = (props) => {
return useRequestQuery(
- [t.AUTH_METADATA_PAGE,],
+ [t.AUTH_METADATA_PAGE],
{
method: 'get',
url: `auth/meta`,
@@ -147,5 +147,35 @@ export const useAuthMetadata = (props) => {
defaultData: {},
...props,
},
- );
+ );
+};
+
+/**
+ *
+ */
+export const useAuthSignUpVerifyResendMail = (props) => {
+ const apiRequest = useApiRequest();
+
+ return useMutation(
+ () => apiRequest.post('auth/register/verify/resend'),
+ props,
+ );
+};
+
+interface AuthSignUpVerifyValues {
+ token: string;
+ email: string;
}
+
+/**
+ *
+ */
+export const useAuthSignUpVerify = (props) => {
+ const apiRequest = useApiRequest();
+
+ return useMutation(
+ (values: AuthSignUpVerifyValues) =>
+ apiRequest.post('auth/register/verify', values),
+ props,
+ );
+};
diff --git a/packages/webapp/src/hooks/query/users.tsx b/packages/webapp/src/hooks/query/users.tsx
index 73bcf0691..646308353 100644
--- a/packages/webapp/src/hooks/query/users.tsx
+++ b/packages/webapp/src/hooks/query/users.tsx
@@ -5,6 +5,7 @@ import { useQueryTenant, useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest';
import { useSetFeatureDashboardMeta } from '../state/feature';
import t from './types';
+import { useSetAuthEmailConfirmed } from '../state';
// Common invalidate queries.
const commonInvalidateQueries = (queryClient) => {
@@ -130,6 +131,8 @@ export function useUser(id, props) {
}
export function useAuthenticatedAccount(props) {
+ const setEmailConfirmed = useSetAuthEmailConfirmed();
+
return useRequestQuery(
['AuthenticatedAccount'],
{
@@ -139,6 +142,9 @@ export function useAuthenticatedAccount(props) {
{
select: (response) => response.data.data,
defaultData: {},
+ onSuccess: (data) => {
+ setEmailConfirmed(data.is_verified);
+ },
...props,
},
);
@@ -166,4 +172,3 @@ export const useDashboardMeta = (props) => {
}, [state.isSuccess, state.data, setFeatureDashboardMeta]);
return state;
};
-
diff --git a/packages/webapp/src/hooks/state/authentication.tsx b/packages/webapp/src/hooks/state/authentication.tsx
index 77351693f..7e57e5508 100644
--- a/packages/webapp/src/hooks/state/authentication.tsx
+++ b/packages/webapp/src/hooks/state/authentication.tsx
@@ -2,7 +2,10 @@
import { useDispatch, useSelector } from 'react-redux';
import { useCallback } from 'react';
import { isAuthenticated } from '@/store/authentication/authentication.reducer';
-import { setLogin } from '@/store/authentication/authentication.actions';
+import {
+ setEmailConfirmed,
+ setLogin,
+} from '@/store/authentication/authentication.actions';
import { useQueryClient } from 'react-query';
import { removeCookie } from '@/utils';
@@ -68,3 +71,22 @@ export const useAuthUser = () => {
export const useAuthOrganizationId = () => {
return useSelector((state) => state.authentication.organizationId);
};
+
+/**
+ * Retrieves the user's email verification status.
+ */
+export const useAuthUserVerified = () => {
+ return useSelector((state) => state.authentication.verified);
+};
+
+/**
+ * Sets the user's email verification status.
+ */
+export const useSetAuthEmailConfirmed = () => {
+ const dispatch = useDispatch();
+
+ return useCallback(
+ (verified?: boolean = true) => dispatch(setEmailConfirmed(verified)),
+ [dispatch],
+ );
+};
diff --git a/packages/webapp/src/routes/authentication.tsx b/packages/webapp/src/routes/authentication.tsx
index 77b1fce6f..7ce79dbbc 100644
--- a/packages/webapp/src/routes/authentication.tsx
+++ b/packages/webapp/src/routes/authentication.tsx
@@ -28,10 +28,16 @@ export default [
loader: () => import('@/containers/Authentication/InviteAccept'),
}),
},
+ {
+ path: `${BASE_URL}/register/email_confirmation`,
+ component: LazyLoader({
+ loader: () => import('@/containers/Authentication/EmailConfirmation'),
+ }),
+ },
{
path: `${BASE_URL}/register`,
component: LazyLoader({
loader: () => import('@/containers/Authentication/Register'),
}),
- }
+ },
];
diff --git a/packages/webapp/src/store/authentication/authentication.actions.tsx b/packages/webapp/src/store/authentication/authentication.actions.tsx
index 4d2d5f048..daefd8f48 100644
--- a/packages/webapp/src/store/authentication/authentication.actions.tsx
+++ b/packages/webapp/src/store/authentication/authentication.actions.tsx
@@ -3,4 +3,8 @@ import t from '@/store/types';
export const setLogin = () => ({ type: t.LOGIN_SUCCESS });
export const setLogout = () => ({ type: t.LOGOUT });
-export const setStoreReset = () => ({ type: t.RESET });
\ No newline at end of file
+export const setStoreReset = () => ({ type: t.RESET });
+export const setEmailConfirmed = (verified?: boolean) => ({
+ type: t.SET_EMAIL_VERIFIED,
+ action: { verified },
+});
diff --git a/packages/webapp/src/store/authentication/authentication.reducer.tsx b/packages/webapp/src/store/authentication/authentication.reducer.tsx
index 9972bf2a8..ce56b81ec 100644
--- a/packages/webapp/src/store/authentication/authentication.reducer.tsx
+++ b/packages/webapp/src/store/authentication/authentication.reducer.tsx
@@ -1,8 +1,9 @@
// @ts-nocheck
-import { createReducer } from '@reduxjs/toolkit';
+import { PayloadAction, createReducer } from '@reduxjs/toolkit';
import { persistReducer } from 'redux-persist';
import purgeStoredState from 'redux-persist/es/purgeStoredState';
import storage from 'redux-persist/lib/storage';
+import { isUndefined } from 'lodash';
import { getCookie } from '@/utils';
import t from '@/store/types';
@@ -13,6 +14,7 @@ const initialState = {
tenantId: getCookie('tenant_id'),
userId: getCookie('authenticated_user_id'),
locale: getCookie('locale'),
+ verified: true, // Let's be optimistic and assume the user's email is confirmed.
errors: [],
};
@@ -32,6 +34,15 @@ const reducerInstance = createReducer(initialState, {
state.errors = [];
},
+ [t.SET_EMAIL_VERIFIED]: (
+ state,
+ payload: PayloadAction<{ verified?: boolean }>,
+ ) => {
+ state.verified = !isUndefined(payload.action.verified)
+ ? payload.action.verified
+ : true;
+ },
+
[t.RESET]: (state) => {
purgeStoredState(CONFIG);
},
diff --git a/packages/webapp/src/store/authentication/authentication.types.tsx b/packages/webapp/src/store/authentication/authentication.types.tsx
index c5a5b3c3f..f64af4652 100644
--- a/packages/webapp/src/store/authentication/authentication.types.tsx
+++ b/packages/webapp/src/store/authentication/authentication.types.tsx
@@ -7,4 +7,5 @@ export default {
LOGOUT: 'LOGOUT',
LOGIN_CLEAR_ERRORS: 'LOGIN_CLEAR_ERRORS',
RESET: 'RESET',
+ SET_EMAIL_VERIFIED: 'SET_EMAIL_VERIFIED'
};
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index e00f9c85f..0c1e9e860 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -224,6 +224,9 @@ importers:
mysql2:
specifier: ^1.6.5
version: 1.7.0
+ newrelic:
+ specifier: ^11.15.0
+ version: 11.16.0
node-cache:
specifier: ^4.2.1
version: 4.2.1
@@ -1879,7 +1882,7 @@ packages:
'@babel/helper-plugin-utils': 7.20.2
debug: 4.3.4(supports-color@5.5.0)
lodash.debounce: 4.0.8
- resolve: 1.22.1
+ resolve: 1.22.6
semver: 6.3.0
transitivePeerDependencies:
- supports-color
@@ -1895,7 +1898,7 @@ packages:
'@babel/helper-plugin-utils': 7.22.5
debug: 4.3.4(supports-color@5.5.0)
lodash.debounce: 4.0.8
- resolve: 1.22.1
+ resolve: 1.22.6
transitivePeerDependencies:
- supports-color
dev: false
@@ -3783,6 +3786,16 @@ packages:
chalk: 4.1.2
dev: true
+ /@contrast/fn-inspect@3.4.0:
+ resolution: {integrity: sha512-Jw6dMFEIt/FXF1ihJri2GFNayeEKQ6r+WRjjWl7MdgMup2D4vCPu99ZV8eHSMqNNkj3BEzUNC91ZaJVB1XJmfg==}
+ engines: {node: '>=12.13.0'}
+ requiresBuild: true
+ dependencies:
+ nan: 2.17.0
+ node-gyp-build: 4.8.1
+ dev: false
+ optional: true
+
/@craco/craco@5.9.0(react-scripts@5.0.1):
resolution: {integrity: sha512-2Q8gIB4W0/nPiUxr9iAKUhGsFlXYN0/wngUdK1VWtfV2NtBv+yllNn2AjieaLbttgpQinuOYmDU65vocC0NMDg==}
engines: {node: '>=6'}
@@ -4093,6 +4106,25 @@ packages:
deprecated: the package is rather renamed to @formatjs/ecma-abstract with some changes in functionality (primarily selectUnit is removed and we don't plan to make any further changes to this package
dev: false
+ /@grpc/grpc-js@1.10.7:
+ resolution: {integrity: sha512-ZMBVjSeDAz3tFSehyO6Pd08xZT1HfIwq3opbeM4cDlBh52gmwp0wVIPcQur53NN0ac68HMZ/7SF2rGRD5KmVmg==}
+ engines: {node: '>=12.10.0'}
+ dependencies:
+ '@grpc/proto-loader': 0.7.13
+ '@js-sdsl/ordered-map': 4.4.2
+ dev: false
+
+ /@grpc/proto-loader@0.7.13:
+ resolution: {integrity: sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==}
+ engines: {node: '>=6'}
+ hasBin: true
+ dependencies:
+ lodash.camelcase: 4.3.0
+ long: 5.2.3
+ protobufjs: 7.2.6
+ yargs: 17.7.2
+ dev: false
+
/@hapi/boom@7.4.11:
resolution: {integrity: sha512-VSU/Cnj1DXouukYxxkes4nNJonCnlogHvIff1v1RVoN4xzkKhMXX+GRmb3NyH1iar10I9WFPDv2JPwfH3GaV0A==}
deprecated: This version has been deprecated and is no longer supported or maintained
@@ -4142,6 +4174,7 @@ packages:
/@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
+ requiresBuild: true
dependencies:
string-width: 5.1.2
string-width-cjs: /string-width@4.2.3
@@ -4149,7 +4182,6 @@ packages:
strip-ansi-cjs: /strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: /wrap-ansi@7.0.0
- dev: true
/@istanbuljs/load-nyc-config@1.1.0:
resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
@@ -4638,6 +4670,10 @@ packages:
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
+ /@js-sdsl/ordered-map@4.4.2:
+ resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==}
+ dev: false
+
/@juggle/resize-observer@3.4.0:
resolution: {integrity: sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==}
dev: false
@@ -4743,6 +4779,63 @@ packages:
glob-to-regexp: 0.3.0
dev: false
+ /@newrelic/native-metrics@10.1.1:
+ resolution: {integrity: sha512-BvdTMAqS3d94ZwJ6u70dWqZVkX8ev3dybkxRInHMbKV2DE1koQR3nzH2ut3hf1MaRQh4SF6SpUNTUznzCZZtjw==}
+ engines: {node: '>=16', npm: '>=6'}
+ requiresBuild: true
+ dependencies:
+ nan: 2.19.0
+ node-gyp: 10.1.0
+ node-gyp-build: 4.8.1
+ prebuildify: 6.0.1
+ semver: 7.5.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+ optional: true
+
+ /@newrelic/ritm@7.2.0:
+ resolution: {integrity: sha512-I4iVhm+wlTEDJXQT8EydF/U5vlR9bBHrtBGyvd/D9WCucoMtrPrCNyILQh9bZ+46E8QRE7zh6QEGyQcnc3qNMg==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ debug: 4.3.4(supports-color@5.5.0)
+ module-details-from-path: 1.0.3
+ resolve: 1.22.6
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
+ /@newrelic/security-agent@1.2.0:
+ resolution: {integrity: sha512-Snk++TQmqHKuxPYOH5bEU4GCr5xKYurUZWx3oiuoQUV73pw61qeEMrb/8iuGgAghwpCEC/8n+308efqCIZkiiQ==}
+ dependencies:
+ axios: 1.6.8
+ check-disk-space: 3.4.0
+ content-type: 1.0.5
+ fast-safe-stringify: 2.1.1
+ find-package-json: 1.2.0
+ hash.js: 1.1.7
+ html-entities: 2.4.0
+ is-invalid-path: 1.0.2
+ js-yaml: 4.1.0
+ jsonschema: 1.4.1
+ lodash: 4.17.21
+ log4js: 6.9.1
+ pretty-bytes: 5.6.0
+ request-ip: 3.3.0
+ ringbufferjs: 2.0.0
+ semver: 7.5.4
+ sync-request: 6.1.0
+ unescape: 1.0.1
+ unescape-js: 1.1.4
+ uuid: 9.0.1
+ ws: 8.14.2
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - utf-8-validate
+ dev: false
+
/@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1:
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
dependencies:
@@ -4775,22 +4868,22 @@ packages:
/@npmcli/agent@2.2.2:
resolution: {integrity: sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==}
engines: {node: ^16.14.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
agent-base: 7.1.1
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.4
- lru-cache: 10.2.0
+ lru-cache: 10.2.1
socks-proxy-agent: 8.0.3
transitivePeerDependencies:
- supports-color
- dev: true
/@npmcli/fs@3.1.0:
resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
semver: 7.5.4
- dev: true
/@npmcli/git@5.0.6:
resolution: {integrity: sha512-4x/182sKXmQkf0EtXxT26GEsaOATpD7WVtza5hrYivWZeo6QefC6xq9KAXrnjtFKBZ4rZwR7aX/zClYYXgtwLw==}
@@ -5117,7 +5210,6 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
requiresBuild: true
- dev: true
optional: true
/@pkgr/utils@2.3.1:
@@ -5191,6 +5283,55 @@ packages:
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
dev: false
+ /@prisma/prisma-fmt-wasm@4.17.0-16.27eb2449f178cd9fe1a4b892d732cc4795f75085:
+ resolution: {integrity: sha512-zYz3rFwPB82mVlHGknAPdnSY/a308dhPOblxQLcZgZTDRtDXOE1MgxoRAys+jekwR4/bm3+rZDPs1xsFMsPZig==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /@protobufjs/aspromise@1.1.2:
+ resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
+ dev: false
+
+ /@protobufjs/base64@1.1.2:
+ resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==}
+ dev: false
+
+ /@protobufjs/codegen@2.0.4:
+ resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==}
+ dev: false
+
+ /@protobufjs/eventemitter@1.1.0:
+ resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==}
+ dev: false
+
+ /@protobufjs/fetch@1.1.0:
+ resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==}
+ dependencies:
+ '@protobufjs/aspromise': 1.1.2
+ '@protobufjs/inquire': 1.1.0
+ dev: false
+
+ /@protobufjs/float@1.0.2:
+ resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
+ dev: false
+
+ /@protobufjs/inquire@1.1.0:
+ resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==}
+ dev: false
+
+ /@protobufjs/path@1.1.2:
+ resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
+ dev: false
+
+ /@protobufjs/pool@1.1.0:
+ resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==}
+ dev: false
+
+ /@protobufjs/utf8@1.1.0:
+ resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
+ dev: false
+
/@reduxjs/toolkit@1.9.2(react-redux@7.2.9)(react@18.2.0):
resolution: {integrity: sha512-5ZAZ7hwAKWSii5T6NTPmgIBUqyVdlDs+6JjThz6J6dmHLDm6zCzv2OjHIFAi3Vvs1qjmXU0bm6eBojukYXjVMQ==}
peerDependencies:
@@ -5266,7 +5407,7 @@ packages:
builtin-modules: 3.3.0
deepmerge: 4.3.1
is-module: 1.0.0
- resolve: 1.22.1
+ resolve: 1.22.6
rollup: 2.79.1
dev: false
@@ -5988,6 +6129,12 @@ packages:
resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==}
dev: true
+ /@types/concat-stream@1.6.1:
+ resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==}
+ dependencies:
+ '@types/node': 14.18.36
+ dev: false
+
/@types/connect-history-api-fallback@1.5.1:
resolution: {integrity: sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==}
dependencies:
@@ -6063,6 +6210,12 @@ packages:
'@types/serve-static': 1.15.3
dev: false
+ /@types/form-data@0.0.33:
+ resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==}
+ dependencies:
+ '@types/node': 14.18.36
+ dev: false
+
/@types/glob@7.2.0:
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
dependencies:
@@ -6206,6 +6359,10 @@ packages:
'@types/node': 18.13.0
dev: false
+ /@types/node@10.17.60:
+ resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==}
+ dev: false
+
/@types/node@14.18.36:
resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==}
dev: false
@@ -6213,6 +6370,10 @@ packages:
/@types/node@18.13.0:
resolution: {integrity: sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==}
+ /@types/node@8.10.66:
+ resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==}
+ dev: false
+
/@types/normalize-package-data@2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
@@ -6810,7 +6971,7 @@ packages:
debug: 4.3.4(supports-color@5.5.0)
globby: 11.1.0
is-glob: 4.0.3
- semver: 7.3.8
+ semver: 7.5.4
tsutils: 3.21.0(typescript@4.9.5)
typescript: 4.9.5
transitivePeerDependencies:
@@ -6871,7 +7032,7 @@ packages:
'@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5)
eslint: 8.33.0
eslint-scope: 5.1.1
- semver: 7.3.8
+ semver: 7.5.4
transitivePeerDependencies:
- supports-color
- typescript
@@ -6892,6 +7053,10 @@ packages:
eslint-visitor-keys: 3.3.0
dev: false
+ /@tyriar/fibonacci-heap@2.0.9:
+ resolution: {integrity: sha512-bYuSNomfn4hu2tPiDN+JZtnzCpSpbJ/PNeulmocDy3xN2X5OkJL65zo6rPZp65cPPhLF9vfT/dgE+RtFRCSxOA==}
+ dev: false
+
/@ucast/core@1.10.1:
resolution: {integrity: sha512-sXKbvQiagjFh2JCpaHUa64P4UdJbOxYeC5xiZFn8y6iYdb0WkismduE+RmiJrIjw/eLDYmIEXiQeIYYowmkcAw==}
dev: false
@@ -7092,7 +7257,7 @@ packages:
/abbrev@2.0.0:
resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
- dev: true
+ requiresBuild: true
/accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
@@ -7127,6 +7292,14 @@ packages:
dependencies:
acorn: 8.8.2
+ /acorn-import-attributes@1.9.5(acorn@8.8.2):
+ resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==}
+ peerDependencies:
+ acorn: ^8
+ dependencies:
+ acorn: 8.8.2
+ dev: false
+
/acorn-jsx@5.3.2(acorn@8.8.2):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@@ -7246,7 +7419,7 @@ packages:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
dependencies:
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
@@ -7254,16 +7427,15 @@ packages:
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
engines: {node: '>= 14'}
dependencies:
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
- dev: true
/agentkeepalive@4.2.1:
resolution: {integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==}
engines: {node: '>= 8.0.0'}
dependencies:
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
depd: 1.1.2
humanize-ms: 1.2.1
transitivePeerDependencies:
@@ -7408,7 +7580,7 @@ packages:
/ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
- dev: true
+ requiresBuild: true
/ansi-wrap@0.1.0:
resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==}
@@ -7844,6 +8016,16 @@ packages:
transitivePeerDependencies:
- debug
+ /axios@1.6.8:
+ resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==}
+ dependencies:
+ follow-redirects: 1.15.6
+ form-data: 4.0.0
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+ dev: false
+
/axobject-query@3.2.1:
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
dependencies:
@@ -8737,11 +8919,12 @@ packages:
/cacache@18.0.2:
resolution: {integrity: sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==}
engines: {node: ^16.14.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
'@npmcli/fs': 3.1.0
fs-minipass: 3.0.3
glob: 10.3.12
- lru-cache: 10.2.0
+ lru-cache: 10.2.1
minipass: 7.0.4
minipass-collect: 2.0.1
minipass-flush: 1.0.5
@@ -8750,7 +8933,6 @@ packages:
ssri: 10.0.5
tar: 6.1.13
unique-filename: 3.0.0
- dev: true
/cache-base@1.0.1:
resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
@@ -8995,6 +9177,11 @@ packages:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
dev: true
+ /check-disk-space@3.4.0:
+ resolution: {integrity: sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==}
+ engines: {node: '>=16'}
+ dev: false
+
/check-error@1.0.2:
resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
dev: true
@@ -9045,7 +9232,6 @@ packages:
/chownr@2.0.0:
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
engines: {node: '>=10'}
- dev: true
/chrome-trace-event@1.0.3:
resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==}
@@ -9155,7 +9341,6 @@ packages:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
- dev: true
/clone-buffer@1.0.0:
resolution: {integrity: sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==}
@@ -9447,9 +9632,8 @@ packages:
dependencies:
buffer-from: 1.1.2
inherits: 2.0.4
- readable-stream: 3.6.0
+ readable-stream: 3.6.2
typedarray: 0.0.6
- dev: true
/configstore@3.1.5:
resolution: {integrity: sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==}
@@ -10314,6 +10498,11 @@ packages:
whatwg-url: 8.7.0
dev: false
+ /date-format@4.0.14:
+ resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==}
+ engines: {node: '>=4.0'}
+ dev: false
+
/date.js@0.3.3:
resolution: {integrity: sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw==}
dependencies:
@@ -10387,17 +10576,6 @@ packages:
ms: 2.1.2
dev: false
- /debug@4.3.4:
- resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.2
-
/debug@4.3.4(supports-color@5.5.0):
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
@@ -10950,7 +11128,7 @@ packages:
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
- dev: true
+ requiresBuild: true
/ecc-jsbn@0.1.2:
resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
@@ -11032,7 +11210,6 @@ packages:
requiresBuild: true
dependencies:
iconv-lite: 0.6.3
- dev: true
optional: true
/end-of-stream@1.4.4:
@@ -11114,7 +11291,6 @@ packages:
/env-paths@2.2.1:
resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
engines: {node: '>=6'}
- dev: true
/envinfo@7.8.1:
resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==}
@@ -11123,7 +11299,6 @@ packages:
/err-code@2.0.3:
resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
- dev: true
/error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
@@ -12059,7 +12234,7 @@ packages:
/exponential-backoff@3.1.1:
resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
- dev: true
+ requiresBuild: true
/express-basic-auth@1.2.1:
resolution: {integrity: sha512-L6YQ1wQ/mNjVLAmK3AG1RK6VkokA1BIY6wmiH304Xtt/cLTps40EusZsU1Uop+v9lTDPxdtzbFmdXfFO3KEnwA==}
@@ -12257,6 +12432,10 @@ packages:
resolution: {integrity: sha512-8EZzEP0eKkEEVX+drtd9mtuQ+/QrlfW/5MlwcwK5Nds6EkZ/tRzEexkzUY2mIssnAyVLT+TKHuRXmFNNXYUd6g==}
dev: false
+ /fast-safe-stringify@2.1.1:
+ resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ dev: false
+
/fast-shallow-equal@1.0.0:
resolution: {integrity: sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw==}
dev: false
@@ -12426,6 +12605,10 @@ packages:
pkg-dir: 4.2.0
dev: false
+ /find-package-json@1.2.0:
+ resolution: {integrity: sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==}
+ dev: false
+
/find-root@1.1.0:
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
@@ -12542,6 +12725,16 @@ packages:
debug:
optional: true
+ /follow-redirects@1.15.6:
+ resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+ dev: false
+
/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
@@ -12569,10 +12762,10 @@ packages:
/foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
engines: {node: '>=14'}
+ requiresBuild: true
dependencies:
cross-spawn: 7.0.3
signal-exit: 4.1.0
- dev: true
/forever-agent@0.6.1:
resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
@@ -12632,7 +12825,7 @@ packages:
memfs: 3.5.3
minimatch: 3.1.2
schema-utils: 2.7.0
- semver: 7.3.8
+ semver: 7.5.4
tapable: 1.1.3
typescript: 4.9.5
webpack: 5.76.0(webpack-cli@4.10.0)
@@ -12654,7 +12847,6 @@ packages:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
- dev: true
/form-data@3.0.1:
resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
@@ -12753,6 +12945,15 @@ packages:
universalify: 2.0.0
dev: true
+ /fs-extra@8.1.0:
+ resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
+ engines: {node: '>=6 <7 || >=8'}
+ dependencies:
+ graceful-fs: 4.2.11
+ jsonfile: 4.0.0
+ universalify: 0.1.2
+ dev: false
+
/fs-extra@9.1.0:
resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
engines: {node: '>=10'}
@@ -12768,14 +12969,13 @@ packages:
engines: {node: '>= 8'}
dependencies:
minipass: 3.3.6
- dev: true
/fs-minipass@3.0.3:
resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
minipass: 7.0.4
- dev: true
/fs-mkdirp-stream@1.0.0:
resolution: {integrity: sha512-+vSd9frUnapVC2RZYfL3FCB2p3g4TBhaUmrsWlSudsGdnxIuUvBB2QM1VZeBtc49QFwrp+wQLrDs3+xxDgI5gQ==}
@@ -12923,6 +13123,11 @@ packages:
yargs: 16.2.0
dev: true
+ /get-port@3.2.0:
+ resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==}
+ engines: {node: '>=4'}
+ dev: false
+
/get-port@5.1.1:
resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==}
engines: {node: '>=8'}
@@ -13104,13 +13309,13 @@ packages:
resolution: {integrity: sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==}
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
+ requiresBuild: true
dependencies:
foreground-child: 3.1.1
jackspeak: 2.3.6
minimatch: 9.0.4
minipass: 7.0.4
path-scurry: 1.10.2
- dev: true
/glob@7.1.2:
resolution: {integrity: sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==}
@@ -13559,7 +13764,6 @@ packages:
dependencies:
inherits: 2.0.4
minimalistic-assert: 1.0.1
- dev: true
/hasha@3.0.0:
resolution: {integrity: sha512-w0Kz8lJFBoyaurBiNrIvxPqr/gJ6fOfSkpAPOepN3oECqGJag37xPbOv57izi/KP8auHgNYxn5fXtAb+1LsJ6w==}
@@ -13776,9 +13980,18 @@ packages:
entities: 2.2.0
dev: false
+ /http-basic@8.1.3:
+ resolution: {integrity: sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ caseless: 0.12.0
+ concat-stream: 1.6.2
+ http-response-object: 3.0.2
+ parse-cache-control: 1.0.1
+ dev: false
+
/http-cache-semantics@4.1.1:
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
- dev: true
/http-deceiver@1.2.7:
resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==}
@@ -13837,7 +14050,7 @@ packages:
dependencies:
'@tootallnate/once': 2.0.0
agent-base: 6.0.2
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
dev: true
@@ -13845,12 +14058,12 @@ packages:
/http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
+ requiresBuild: true
dependencies:
agent-base: 7.1.1
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
- dev: true
/http-proxy-middleware@1.3.1:
resolution: {integrity: sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg==}
@@ -13895,6 +14108,12 @@ packages:
- debug
dev: false
+ /http-response-object@3.0.2:
+ resolution: {integrity: sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==}
+ dependencies:
+ '@types/node': 10.17.60
+ dev: false
+
/http-signature@1.2.0:
resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==}
engines: {node: '>=0.8', npm: '>=1.3.7'}
@@ -13923,7 +14142,7 @@ packages:
engines: {node: '>= 6'}
dependencies:
agent-base: 6.0.2
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
@@ -13932,10 +14151,9 @@ packages:
engines: {node: '>= 14'}
dependencies:
agent-base: 7.1.1
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
transitivePeerDependencies:
- supports-color
- dev: true
/human-interval@2.0.1:
resolution: {integrity: sha512-r4Aotzf+OtKIGQCB3odUowy4GfUDTy3aTWTfLd7ZF2gBCy3XW3v/dJLRefZnOFFnjqs5B1TypvS8WarpBkYUNQ==}
@@ -14070,6 +14288,15 @@ packages:
engines: {node: '>=12.2'}
dev: true
+ /import-in-the-middle@1.7.4:
+ resolution: {integrity: sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg==}
+ dependencies:
+ acorn: 8.8.2
+ acorn-import-attributes: 1.9.5(acorn@8.8.2)
+ cjs-module-lexer: 1.2.3
+ module-details-from-path: 1.0.3
+ dev: false
+
/import-lazy@2.1.0:
resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==}
engines: {node: '>=4'}
@@ -14487,6 +14714,11 @@ packages:
engines: {node: '>=8'}
dev: true
+ /is-invalid-path@1.0.2:
+ resolution: {integrity: sha512-6KLcFrPCEP3AFXMfnWrIFkZpYNBVzZAoBJJDEZKtI3LXkaDjM3uFMJQjxiizUuZTZ9Oh9FNv/soXbx5TcpaDmA==}
+ engines: {node: '>=6.0'}
+ dev: false
+
/is-ip@2.0.0:
resolution: {integrity: sha512-9MTn0dteHETtyUx8pxqMwg5hMBi3pvlyglJ+b79KOCca0po23337LbVV2Hl4xmMvfw++ljnO0/+5G6G+0Szh6g==}
engines: {node: '>=4'}
@@ -14496,7 +14728,6 @@ packages:
/is-lambda@1.0.1:
resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
- dev: true
/is-map@2.0.2:
resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
@@ -14787,7 +15018,7 @@ packages:
/isexe@3.1.1:
resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
engines: {node: '>=16'}
- dev: true
+ requiresBuild: true
/isobject@2.1.0:
resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==}
@@ -14914,11 +15145,11 @@ packages:
/jackspeak@2.3.6:
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
engines: {node: '>=14'}
+ requiresBuild: true
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
- dev: true
/jake@10.8.5:
resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
@@ -15732,7 +15963,7 @@ packages:
jest-util: 27.5.1
natural-compare: 1.4.0
pretty-format: 27.5.1
- semver: 7.3.8
+ semver: 7.5.4
transitivePeerDependencies:
- supports-color
dev: false
@@ -16116,6 +16347,12 @@ packages:
engines: {node: '>=4'}
hasBin: true
+ /json-bigint@1.0.0:
+ resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
+ dependencies:
+ bignumber.js: 9.0.0
+ dev: false
+
/json-parse-better-errors@1.0.2:
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
@@ -16158,12 +16395,18 @@ packages:
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
dev: true
+ /jsonfile@4.0.0:
+ resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
+ optionalDependencies:
+ graceful-fs: 4.2.11
+ dev: false
+
/jsonfile@6.1.0:
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
dependencies:
universalify: 2.0.0
optionalDependencies:
- graceful-fs: 4.2.10
+ graceful-fs: 4.2.11
/jsonparse@1.3.1:
resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==}
@@ -16183,6 +16426,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
+ /jsonschema@1.4.1:
+ resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==}
+ dev: false
+
/jsonwebtoken@8.5.1:
resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==}
engines: {node: '>=4', npm: '>=1.4.28'}
@@ -16671,7 +16918,7 @@ packages:
resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==}
engines: {node: '>=4'}
dependencies:
- graceful-fs: 4.2.11
+ graceful-fs: 4.2.10
parse-json: 4.0.0
pify: 3.0.0
strip-bom: 3.0.0
@@ -16680,7 +16927,7 @@ packages:
resolution: {integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==}
engines: {node: '>=8'}
dependencies:
- graceful-fs: 4.2.11
+ graceful-fs: 4.2.10
parse-json: 5.2.0
strip-bom: 4.0.0
type-fest: 0.6.0
@@ -16761,7 +17008,6 @@ packages:
/lodash.camelcase@4.3.0:
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
- dev: true
/lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
@@ -16879,6 +17125,19 @@ packages:
is-unicode-supported: 0.1.0
dev: true
+ /log4js@6.9.1:
+ resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ date-format: 4.0.14
+ debug: 4.3.4(supports-color@5.5.0)
+ flatted: 3.2.7
+ rfdc: 1.3.1
+ streamroller: 3.1.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/logform@2.5.1:
resolution: {integrity: sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==}
dependencies:
@@ -16904,6 +17163,10 @@ packages:
resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==}
dev: false
+ /long@5.2.3:
+ resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==}
+ dev: false
+
/loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@@ -16933,6 +17196,11 @@ packages:
engines: {node: 14 || >=16.14}
dev: true
+ /lru-cache@10.2.1:
+ resolution: {integrity: sha512-tS24spDe/zXhWbNPErCHs/AGOzbKGHT+ybSBqmdLm8WZ1xXLWvH8Qn71QPAlqVhd0qUTWjy+Kl9JmISgDdEjsA==}
+ engines: {node: 14 || >=16.14}
+ requiresBuild: true
+
/lru-cache@4.1.5:
resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==}
dependencies:
@@ -17026,6 +17294,7 @@ packages:
/make-fetch-happen@13.0.0:
resolution: {integrity: sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==}
engines: {node: ^16.14.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
'@npmcli/agent': 2.2.2
cacache: 18.0.2
@@ -17040,7 +17309,6 @@ packages:
ssri: 10.0.5
transitivePeerDependencies:
- supports-color
- dev: true
/make-iterator@1.0.1:
resolution: {integrity: sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==}
@@ -17393,9 +17661,9 @@ packages:
/minimatch@9.0.4:
resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
engines: {node: '>=16 || 14 >=14.17'}
+ requiresBuild: true
dependencies:
brace-expansion: 2.0.1
- dev: true
/minimist-options@4.1.0:
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
@@ -17422,27 +17690,26 @@ packages:
/minipass-collect@2.0.1:
resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==}
engines: {node: '>=16 || 14 >=14.17'}
+ requiresBuild: true
dependencies:
minipass: 7.0.4
- dev: true
/minipass-fetch@3.0.4:
resolution: {integrity: sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
minipass: 7.0.4
minipass-sized: 1.0.3
minizlib: 2.1.2
optionalDependencies:
encoding: 0.1.13
- dev: true
/minipass-flush@1.0.5:
resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
engines: {node: '>= 8'}
dependencies:
minipass: 3.3.6
- dev: true
/minipass-json-stream@1.0.1:
resolution: {integrity: sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==}
@@ -17456,26 +17723,22 @@ packages:
engines: {node: '>=8'}
dependencies:
minipass: 3.3.6
- dev: true
/minipass-sized@1.0.3:
resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==}
engines: {node: '>=8'}
dependencies:
minipass: 3.3.6
- dev: true
/minipass@3.3.6:
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
engines: {node: '>=8'}
dependencies:
yallist: 4.0.0
- dev: true
/minipass@4.0.2:
resolution: {integrity: sha512-4Hbzei7ZyBp+1aw0874YWpKOubZd/jc53/XU+gkYry1QV+VvrbO8icLM5CUtm4F0hyXn85DXYKEMIS26gitD3A==}
engines: {node: '>=8'}
- dev: true
/minipass@4.2.8:
resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==}
@@ -17490,7 +17753,7 @@ packages:
/minipass@7.0.4:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
engines: {node: '>=16 || 14 >=14.17'}
- dev: true
+ requiresBuild: true
/minizlib@2.1.2:
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
@@ -17498,7 +17761,6 @@ packages:
dependencies:
minipass: 3.3.6
yallist: 4.0.0
- dev: true
/mixin-deep@1.3.2:
resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
@@ -17508,6 +17770,12 @@ packages:
is-extendable: 1.0.1
dev: false
+ /mkdirp-classic@0.5.3:
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
/mkdirp@0.5.1:
resolution: {integrity: sha512-SknJC52obPfGQPnjIkXbmA6+5H15E+fR+E4iR2oQ3zzCLbd7/ONua69R/Gw7AgkTLsRG+r5fzksYwWe1AgTyWA==}
deprecated: Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)
@@ -17526,7 +17794,6 @@ packages:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
hasBin: true
- dev: true
/mocha@5.2.0:
resolution: {integrity: sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==}
@@ -17551,6 +17818,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /module-details-from-path@1.0.3:
+ resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==}
+ dev: false
+
/moment-range@4.0.2(moment@2.29.4):
resolution: {integrity: sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==}
peerDependencies:
@@ -17827,6 +18098,12 @@ packages:
dev: false
optional: true
+ /nan@2.19.0:
+ resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==}
+ requiresBuild: true
+ dev: false
+ optional: true
+
/nano-css@5.3.5(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg==}
peerDependencies:
@@ -17896,6 +18173,36 @@ packages:
/nested-error-stacks@2.1.1:
resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==}
+ /newrelic@11.16.0:
+ resolution: {integrity: sha512-oEgsJxK9IgP11DS/rZ78S6lUUGNLwGY91tGCIzGkEkhjFpi0nzWp2LaIRDv6hiNX5lQTZb2RWufRFN42f3XqTw==}
+ engines: {node: '>=16', npm: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ '@grpc/grpc-js': 1.10.7
+ '@grpc/proto-loader': 0.7.13
+ '@newrelic/ritm': 7.2.0
+ '@newrelic/security-agent': 1.2.0
+ '@tyriar/fibonacci-heap': 2.0.9
+ concat-stream: 2.0.0
+ https-proxy-agent: 7.0.4
+ import-in-the-middle: 1.7.4
+ json-bigint: 1.0.0
+ json-stringify-safe: 5.0.1
+ module-details-from-path: 1.0.3
+ readable-stream: 3.6.2
+ semver: 7.5.4
+ winston-transport: 4.5.0
+ optionalDependencies:
+ '@contrast/fn-inspect': 3.4.0
+ '@newrelic/native-metrics': 10.1.1
+ '@prisma/prisma-fmt-wasm': 4.17.0-16.27eb2449f178cd9fe1a4b892d732cc4795f75085
+ transitivePeerDependencies:
+ - bufferutil
+ - debug
+ - supports-color
+ - utf-8-validate
+ dev: false
+
/next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
dev: false
@@ -17925,6 +18232,15 @@ packages:
engines: {node: '>=4.0.0'}
dev: false
+ /node-abi@3.62.0:
+ resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==}
+ engines: {node: '>=10'}
+ requiresBuild: true
+ dependencies:
+ semver: 7.5.4
+ dev: false
+ optional: true
+
/node-cache@4.2.1:
resolution: {integrity: sha512-BOb67bWg2dTyax5kdef5WfU3X8xu4wPg+zHzkvls0Q/QpYycIFRLEEIdAx9Wma43DxG6Qzn4illdZoYseKWa4A==}
engines: {node: '>= 0.4.6'}
@@ -17967,15 +18283,23 @@ packages:
engines: {node: '>= 6.13.0'}
dev: false
+ /node-gyp-build@4.8.1:
+ resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
+ hasBin: true
+ requiresBuild: true
+ dev: false
+ optional: true
+
/node-gyp@10.1.0:
resolution: {integrity: sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==}
engines: {node: ^16.14.0 || >=18.0.0}
hasBin: true
+ requiresBuild: true
dependencies:
env-paths: 2.2.1
exponential-backoff: 3.1.1
glob: 10.3.12
- graceful-fs: 4.2.11
+ graceful-fs: 4.2.10
make-fetch-happen: 13.0.0
nopt: 7.2.0
proc-log: 3.0.0
@@ -17984,7 +18308,6 @@ packages:
which: 4.0.0
transitivePeerDependencies:
- supports-color
- dev: true
/node-int64@0.4.0:
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
@@ -18077,9 +18400,9 @@ packages:
resolution: {integrity: sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
hasBin: true
+ requiresBuild: true
dependencies:
abbrev: 2.0.0
- dev: true
/normalize-package-data@2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
@@ -18095,7 +18418,7 @@ packages:
dependencies:
hosted-git-info: 4.1.0
is-core-module: 2.11.0
- semver: 7.3.8
+ semver: 7.5.4
validate-npm-package-license: 3.0.4
dev: true
@@ -18205,7 +18528,7 @@ packages:
engines: {node: '>=10'}
dependencies:
hosted-git-info: 3.0.8
- semver: 7.5.4
+ semver: 7.3.8
validate-npm-package-name: 3.0.0
dev: true
@@ -18291,6 +18614,15 @@ packages:
path-key: 2.0.1
dev: false
+ /npm-run-path@3.1.0:
+ resolution: {integrity: sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==}
+ engines: {node: '>=8'}
+ requiresBuild: true
+ dependencies:
+ path-key: 3.1.1
+ dev: false
+ optional: true
+
/npm-run-path@4.0.1:
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
engines: {node: '>=8'}
@@ -18889,7 +19221,6 @@ packages:
engines: {node: '>=10'}
dependencies:
aggregate-error: 3.1.0
- dev: true
/p-pipe@3.1.0:
resolution: {integrity: sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==}
@@ -19019,6 +19350,10 @@ packages:
safe-buffer: 5.2.1
dev: true
+ /parse-cache-control@1.0.1:
+ resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==}
+ dev: false
+
/parse-filepath@1.0.2:
resolution: {integrity: sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==}
engines: {node: '>=0.8'}
@@ -19168,10 +19503,10 @@ packages:
/path-scurry@1.10.2:
resolution: {integrity: sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==}
engines: {node: '>=16 || 14 >=14.17'}
+ requiresBuild: true
dependencies:
- lru-cache: 10.2.0
+ lru-cache: 10.2.1
minipass: 7.0.4
- dev: true
/path-to-regexp@0.1.7:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
@@ -20195,6 +20530,20 @@ packages:
picocolors: 1.0.0
source-map-js: 1.0.2
+ /prebuildify@6.0.1:
+ resolution: {integrity: sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==}
+ hasBin: true
+ requiresBuild: true
+ dependencies:
+ minimist: 1.2.7
+ mkdirp-classic: 0.5.3
+ node-abi: 3.62.0
+ npm-run-path: 3.1.0
+ pump: 3.0.0
+ tar-fs: 2.1.1
+ dev: false
+ optional: true
+
/prelude-ls@1.1.2:
resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
engines: {node: '>= 0.8.0'}
@@ -20295,7 +20644,7 @@ packages:
/proc-log@3.0.0:
resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
- dev: true
+ requiresBuild: true
/proc-log@4.2.0:
resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==}
@@ -20345,7 +20694,6 @@ packages:
dependencies:
err-code: 2.0.3
retry: 0.12.0
- dev: true
/promise@7.3.1:
resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
@@ -20546,6 +20894,25 @@ packages:
prosemirror-transform: 1.8.0
dev: false
+ /protobufjs@7.2.6:
+ resolution: {integrity: sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==}
+ engines: {node: '>=12.0.0'}
+ requiresBuild: true
+ dependencies:
+ '@protobufjs/aspromise': 1.1.2
+ '@protobufjs/base64': 1.1.2
+ '@protobufjs/codegen': 2.0.4
+ '@protobufjs/eventemitter': 1.1.0
+ '@protobufjs/fetch': 1.1.0
+ '@protobufjs/float': 1.0.2
+ '@protobufjs/inquire': 1.1.0
+ '@protobufjs/path': 1.1.2
+ '@protobufjs/pool': 1.1.0
+ '@protobufjs/utf8': 1.1.0
+ '@types/node': 14.18.36
+ long: 5.2.3
+ dev: false
+
/protocols@2.0.1:
resolution: {integrity: sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==}
dev: true
@@ -21796,6 +22163,14 @@ packages:
string_decoder: 1.3.0
util-deprecate: 1.0.2
+ /readable-stream@3.6.2:
+ resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+
/readdirp@2.2.1(supports-color@5.5.0):
resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
engines: {node: '>=0.10'}
@@ -21824,7 +22199,7 @@ packages:
resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==}
engines: {node: '>= 0.10'}
dependencies:
- resolve: 1.22.1
+ resolve: 1.22.6
dev: false
/rechoir@0.7.0:
@@ -22111,6 +22486,10 @@ packages:
remove-trailing-separator: 1.1.0
dev: false
+ /request-ip@3.3.0:
+ resolution: {integrity: sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==}
+ dev: false
+
/request-promise-core@1.1.4(request@2.88.2):
resolution: {integrity: sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==}
engines: {node: '>=0.10.0'}
@@ -22327,7 +22706,6 @@ packages:
/retry@0.12.0:
resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
engines: {node: '>= 4'}
- dev: true
/retry@0.13.1:
resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==}
@@ -22338,6 +22716,10 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ /rfdc@1.3.1:
+ resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
+ dev: false
+
/rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
hasBin: true
@@ -22358,6 +22740,10 @@ packages:
glob: 9.3.5
dev: true
+ /ringbufferjs@2.0.0:
+ resolution: {integrity: sha512-GCOqTzUsTHF7nrqcgtNGAFotXztLgiePpIDpyWZ7R5I02tmfJWV+/yuJc//Hlsd8G+WzI1t/dc2y/w2imDZdog==}
+ dev: false
+
/ripemd160@2.0.2:
resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==}
dependencies:
@@ -22875,7 +23261,7 @@ packages:
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
- dev: true
+ requiresBuild: true
/sigstore@1.9.0:
resolution: {integrity: sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==}
@@ -23052,7 +23438,7 @@ packages:
engines: {node: '>= 10'}
dependencies:
agent-base: 6.0.2
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
socks: 2.7.1
transitivePeerDependencies:
- supports-color
@@ -23061,13 +23447,13 @@ packages:
/socks-proxy-agent@8.0.3:
resolution: {integrity: sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==}
engines: {node: '>= 14'}
+ requiresBuild: true
dependencies:
agent-base: 7.1.1
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
socks: 2.7.1
transitivePeerDependencies:
- supports-color
- dev: true
/socks@2.7.1:
resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==}
@@ -23304,9 +23690,9 @@ packages:
/ssri@10.0.5:
resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
minipass: 7.0.4
- dev: true
/ssri@9.0.1:
resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==}
@@ -23433,6 +23819,17 @@ packages:
resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
dev: false
+ /streamroller@3.1.5:
+ resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ date-format: 4.0.14
+ debug: 4.3.4(supports-color@5.5.0)
+ fs-extra: 8.1.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: false
+
/streamsearch@1.1.0:
resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==}
engines: {node: '>=10.0.0'}
@@ -23515,11 +23912,15 @@ packages:
/string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
+ requiresBuild: true
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.0
- dev: true
+
+ /string.fromcodepoint@0.2.1:
+ resolution: {integrity: sha512-n69H31OnxSGSZyZbgBlvYIXlrMhJQ0dQAX1js1QDhpaUH6zmU3QYlj07bCwCNlPOu3oRXIubGPl2gDGnHsiCqg==}
+ dev: false
/string.prototype.matchall@4.0.8:
resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==}
@@ -23891,6 +24292,21 @@ packages:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: false
+ /sync-request@6.1.0:
+ resolution: {integrity: sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ http-response-object: 3.0.2
+ sync-rpc: 1.3.6
+ then-request: 6.0.2
+ dev: false
+
+ /sync-rpc@1.3.6:
+ resolution: {integrity: sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==}
+ dependencies:
+ get-port: 3.2.0
+ dev: false
+
/synchronous-promise@2.0.17:
resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==}
dev: false
@@ -23957,6 +24373,17 @@ packages:
tar-stream: 2.2.0
dev: false
+ /tar-fs@2.1.1:
+ resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
+ requiresBuild: true
+ dependencies:
+ chownr: 1.1.4
+ mkdirp-classic: 0.5.3
+ pump: 3.0.0
+ tar-stream: 2.2.0
+ dev: false
+ optional: true
+
/tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
@@ -23989,7 +24416,6 @@ packages:
minizlib: 2.1.2
mkdirp: 1.0.4
yallist: 4.0.0
- dev: true
/tarn@3.0.2:
resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==}
@@ -24094,6 +24520,23 @@ packages:
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ /then-request@6.0.2:
+ resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@types/concat-stream': 1.6.1
+ '@types/form-data': 0.0.33
+ '@types/node': 8.10.66
+ '@types/qs': 6.9.8
+ caseless: 0.12.0
+ concat-stream: 1.6.2
+ form-data: 2.5.1
+ http-basic: 8.1.3
+ http-response-object: 3.0.2
+ promise: 8.3.0
+ qs: 6.11.0
+ dev: false
+
/thenify-all@1.6.0:
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
engines: {node: '>=0.8'}
@@ -24518,7 +24961,7 @@ packages:
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
dependencies:
'@tufjs/models': 1.0.4
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
make-fetch-happen: 11.1.1
transitivePeerDependencies:
- supports-color
@@ -24529,7 +24972,7 @@ packages:
engines: {node: ^16.14.0 || >=18.0.0}
dependencies:
'@tufjs/models': 2.0.0
- debug: 4.3.4
+ debug: 4.3.4(supports-color@5.5.0)
make-fetch-happen: 13.0.0
transitivePeerDependencies:
- supports-color
@@ -24764,6 +25207,19 @@ packages:
undertaker-registry: 1.0.1
dev: false
+ /unescape-js@1.1.4:
+ resolution: {integrity: sha512-42SD8NOQEhdYntEiUQdYq/1V/YHwr1HLwlHuTJB5InVVdOSbgI6xu8jK5q65yIzuFCfczzyDF/7hbGzVbyCw0g==}
+ dependencies:
+ string.fromcodepoint: 0.2.1
+ dev: false
+
+ /unescape@1.0.1:
+ resolution: {integrity: sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ extend-shallow: 2.0.1
+ dev: false
+
/unicode-canonical-property-names-ecmascript@2.0.0:
resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
engines: {node: '>=4'}
@@ -24804,16 +25260,16 @@ packages:
/unique-filename@3.0.0:
resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
unique-slug: 4.0.0
- dev: true
/unique-slug@4.0.0:
resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ requiresBuild: true
dependencies:
imurmurhash: 0.1.4
- dev: true
/unique-stream@2.3.1:
resolution: {integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==}
@@ -24840,6 +25296,11 @@ packages:
resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==}
dev: true
+ /universalify@0.1.2:
+ resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
+ engines: {node: '>= 4.0.0'}
+ dev: false
+
/universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
@@ -25029,7 +25490,6 @@ packages:
/uuid@9.0.1:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true
- dev: true
/v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
@@ -25590,9 +26050,9 @@ packages:
resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==}
engines: {node: ^16.13.0 || >=18.0.0}
hasBin: true
+ requiresBuild: true
dependencies:
isexe: 3.1.1
- dev: true
/wide-align@1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
@@ -25861,11 +26321,11 @@ packages:
/wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
+ requiresBuild: true
dependencies:
ansi-styles: 6.2.1
string-width: 5.1.2
strip-ansi: 7.1.0
- dev: true
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
@@ -25881,7 +26341,7 @@ packages:
/write-file-atomic@2.4.3:
resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==}
dependencies:
- graceful-fs: 4.2.11
+ graceful-fs: 4.2.10
imurmurhash: 0.1.4
signal-exit: 3.0.7
@@ -25907,7 +26367,7 @@ packages:
engines: {node: '>=6'}
dependencies:
detect-indent: 5.0.0
- graceful-fs: 4.2.11
+ graceful-fs: 4.2.10
make-dir: 2.1.0
pify: 4.0.1
sort-keys: 2.0.0
@@ -26082,7 +26542,6 @@ packages:
/yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
- dev: true
/yargs-parser@5.0.1:
resolution: {integrity: sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==}
@@ -26141,7 +26600,6 @@ packages:
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
- dev: true
/yargs@7.1.2:
resolution: {integrity: sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index ccdc80cde..067a01bf0 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,2 +1,3 @@
packages:
- - "packages/*"
\ No newline at end of file
+ # all packages in direct subdirs of packages/
+ - 'packages/*'