Compare commits
4 Commits
feat/add-e
...
feat/updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e2d1fb148 | ||
|
|
81f9b2f776 | ||
|
|
334671ef85 | ||
|
|
e5fa2f4490 |
14
.env.example
14
.env.example
@@ -15,20 +15,6 @@ NEXT_PRIVATE_DATABASE_URL="postgres://documenso:password@127.0.0.1:54320/documen
|
|||||||
# Defines the URL to use for the database when running migrations and other commands that won't work with a connection pool.
|
# Defines the URL to use for the database when running migrations and other commands that won't work with a connection pool.
|
||||||
NEXT_PRIVATE_DIRECT_DATABASE_URL="postgres://documenso:password@127.0.0.1:54320/documenso"
|
NEXT_PRIVATE_DIRECT_DATABASE_URL="postgres://documenso:password@127.0.0.1:54320/documenso"
|
||||||
|
|
||||||
# [[E2E Tests]]
|
|
||||||
E2E_TEST_SIGNER_NAME="Test Signer"
|
|
||||||
E2E_TEST_SIGNER_EMAIL="testsigner@mail.com"
|
|
||||||
E2E_TEST_SIGNING_SUBJECT="Test subject"
|
|
||||||
E2E_TEST_SIGNING_MESSAGE="Test message"
|
|
||||||
# User for the "auth.setup.ts" file and the authenticated tests
|
|
||||||
E2E_TEST_AUTHENTICATE_USERNAME="New user"
|
|
||||||
E2E_TEST_AUTHENTICATE_USER_EMAIL="mytestnewuser@mail.com"
|
|
||||||
E2E_TEST_AUTHENTICATE_USER_PASSWORD="new_test_password"
|
|
||||||
# User for the *.unauthenticated.ts files
|
|
||||||
E2E_TEST_USERNAME="Test"
|
|
||||||
E2E_TEST_USER_EMAIL="mytestuser@mail.com"
|
|
||||||
E2E_TEST_USER_PASSWORD="test_password"
|
|
||||||
|
|
||||||
# [[STORAGE]]
|
# [[STORAGE]]
|
||||||
# OPTIONAL: Defines the storage transport to use. Available options: database (default) | s3
|
# OPTIONAL: Defines the storage transport to use. Available options: database (default) | s3
|
||||||
NEXT_PUBLIC_UPLOAD_TRANSPORT="database"
|
NEXT_PUBLIC_UPLOAD_TRANSPORT="database"
|
||||||
|
|||||||
53
.github/workflows/e2e-tests.yml
vendored
53
.github/workflows/e2e-tests.yml
vendored
@@ -1,53 +0,0 @@
|
|||||||
name: Playwright Tests
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [feat/refresh, feat/add-e2e-testing]
|
|
||||||
pull_request:
|
|
||||||
branches: [feat/refresh, feat/add-e2e-testing]
|
|
||||||
jobs:
|
|
||||||
e2e_tests:
|
|
||||||
timeout-minutes: 60
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres
|
|
||||||
env:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
options: >-
|
|
||||||
--health-cmd pg_isready
|
|
||||||
--health-interval 10s
|
|
||||||
--health-timeout 5s
|
|
||||||
--health-retries 5
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
env:
|
|
||||||
NEXT_PRIVATE_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/documenso
|
|
||||||
NEXT_PRIVATE_DIRECT_DATABASE_URL: postgresql://postgres:postgres@localhost:5432/documenso
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version: 18
|
|
||||||
- name: Generate package-lock.json
|
|
||||||
run: npm cache clean --force && npm install
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
- name: Copy env
|
|
||||||
run: cp .env.example .env
|
|
||||||
- name: Install Playwright Browsers
|
|
||||||
run: npx playwright install --with-deps
|
|
||||||
- name: Install Prisma Client
|
|
||||||
run: npm install @prisma/client
|
|
||||||
- name: Generate Prisma Client
|
|
||||||
run: npm run prisma:generate -w @documenso/prisma
|
|
||||||
- name: Create the database
|
|
||||||
run: npm run prisma:migrate-dev -w @documenso/prisma
|
|
||||||
- name: Run Playwright tests
|
|
||||||
run: npm run ci
|
|
||||||
- uses: actions/upload-artifact@v3
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: playwright-report
|
|
||||||
path: playwright-report/
|
|
||||||
retention-days: 30
|
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -47,8 +47,3 @@ yarn-error.log*
|
|||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
**/test-results/
|
|
||||||
/playwright-report/
|
|
||||||
/playwright/.cache/
|
|
||||||
|
|
||||||
playwright/.auth
|
|
||||||
|
|||||||
@@ -177,9 +177,7 @@ export const createSinglePlayerDocument = async (
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Todo: Handle `downloadLink`
|
|
||||||
const template = createElement(DocumentSelfSignedEmailTemplate, {
|
const template = createElement(DocumentSelfSignedEmailTemplate, {
|
||||||
downloadLink: `${process.env.NEXT_PUBLIC_MARKETING_URL}/single-player-mode/${documentToken}`,
|
|
||||||
documentName: documentName,
|
documentName: documentName,
|
||||||
assetBaseUrl: process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000',
|
assetBaseUrl: process.env.NEXT_PUBLIC_WEBAPP_URL || 'http://localhost:3000',
|
||||||
});
|
});
|
||||||
@@ -197,6 +195,7 @@ export const createSinglePlayerDocument = async (
|
|||||||
subject: 'Document signed',
|
subject: 'Document signed',
|
||||||
html: render(template),
|
html: render(template),
|
||||||
text: render(template, { plainText: true }),
|
text: render(template, { plainText: true }),
|
||||||
|
attachments: [{ content: Buffer.from(pdfBytes), filename: documentName }],
|
||||||
});
|
});
|
||||||
|
|
||||||
return documentToken;
|
return documentToken;
|
||||||
|
|||||||
3
apps/web/.gitignore
vendored
3
apps/web/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
playwright-report/
|
|
||||||
playwright/.auth
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { deleteUserAndItsData } from '@documenso/lib/server-only/user/delete-user-and-data';
|
|
||||||
|
|
||||||
async function teardown() {
|
|
||||||
if (!process.env.E2E_TEST_USERNAME || !process.env.E2E_TEST_AUTHENTICATE_USERNAME) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await deleteUserAndItsData(process.env.E2E_TEST_USERNAME);
|
|
||||||
await deleteUserAndItsData(process.env.E2E_TEST_AUTHENTICATE_USERNAME);
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error(`Error deleting user: ${e}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default teardown;
|
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"test:dev": "playwright test",
|
|
||||||
"test:e2e": "start-server-and-test \"npm run start\" http://localhost:3000 \"playwright test\"",
|
|
||||||
"clean": "rimraf .next && rimraf node_modules",
|
"clean": "rimraf .next && rimraf node_modules",
|
||||||
"copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs"
|
"copy:pdfjs": "node ../../scripts/copy-pdfjs.cjs"
|
||||||
},
|
},
|
||||||
@@ -43,11 +41,9 @@
|
|||||||
"sharp": "0.32.5",
|
"sharp": "0.32.5",
|
||||||
"ts-pattern": "^5.0.5",
|
"ts-pattern": "^5.0.5",
|
||||||
"typescript": "5.1.6",
|
"typescript": "5.1.6",
|
||||||
"zod": "^3.21.4",
|
"zod": "^3.21.4"
|
||||||
"start-server-and-test": "^2.0.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.38.0",
|
|
||||||
"@types/formidable": "^2.0.6",
|
"@types/formidable": "^2.0.6",
|
||||||
"@types/luxon": "^3.3.1",
|
"@types/luxon": "^3.3.1",
|
||||||
"@types/node": "20.1.0",
|
"@types/node": "20.1.0",
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import { defineConfig, devices } from '@playwright/test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read environment variables from file.
|
|
||||||
* https://github.com/motdotla/dotenv
|
|
||||||
*/
|
|
||||||
import { config as dotenvConfig } from 'dotenv';
|
|
||||||
|
|
||||||
dotenvConfig();
|
|
||||||
|
|
||||||
export const STORAGE_STATE = 'playwright/.auth/user.json';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See https://playwright.dev/docs/test-configuration.
|
|
||||||
*/
|
|
||||||
export default defineConfig({
|
|
||||||
testDir: './src/tests/e2e',
|
|
||||||
/* Run tests in files in parallel */
|
|
||||||
fullyParallel: true,
|
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
||||||
forbidOnly: !!process.env.CI,
|
|
||||||
/* Retry on CI only */
|
|
||||||
retries: process.env.CI ? 2 : 0,
|
|
||||||
/* Opt out of parallel tests on CI. */
|
|
||||||
workers: process.env.CI ? 1 : undefined,
|
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
||||||
reporter: 'html',
|
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
||||||
use: {
|
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
||||||
baseURL: 'http://localhost:3000',
|
|
||||||
|
|
||||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
||||||
trace: 'on-first-retry',
|
|
||||||
navigationTimeout: 60 * 1000,
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
|
||||||
projects: [
|
|
||||||
{ name: 'setup', testMatch: '**/*.setup.ts' },
|
|
||||||
{
|
|
||||||
name: 'Authenticated User Tests',
|
|
||||||
testMatch: '*.authenticated.spec.ts',
|
|
||||||
dependencies: ['setup', 'cleanup db'],
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Chrome'],
|
|
||||||
storageState: STORAGE_STATE,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Unauthenticated User Tests',
|
|
||||||
dependencies: ['cleanup db'],
|
|
||||||
use: {
|
|
||||||
...devices['Desktop Chrome'],
|
|
||||||
},
|
|
||||||
testMatch: '*.unauthenticated.spec.ts',
|
|
||||||
testIgnore: ['*.setup.ts', '*.authenticated.spec.ts'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'cleanup db',
|
|
||||||
testMatch: /global.teardown\.ts/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
globalTeardown: './global.teardown.ts',
|
|
||||||
});
|
|
||||||
BIN
apps/web/public/static/user-plus.png
Normal file
BIN
apps/web/public/static/user-plus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 367 B |
@@ -1,35 +0,0 @@
|
|||||||
import { type Page, expect, test as setup } from '@playwright/test';
|
|
||||||
|
|
||||||
import { STORAGE_STATE } from '../../../playwright.config';
|
|
||||||
|
|
||||||
const username = process.env.E2E_TEST_AUTHENTICATE_USERNAME || '';
|
|
||||||
const email = process.env.E2E_TEST_AUTHENTICATE_USER_EMAIL || '';
|
|
||||||
const password = process.env.E2E_TEST_AUTHENTICATE_USER_PASSWORD || '';
|
|
||||||
|
|
||||||
setup('authenticate', async ({ page }: { page: Page }) => {
|
|
||||||
await page.goto('/signup');
|
|
||||||
await page.getByLabel('Name').fill(username);
|
|
||||||
await page.getByLabel('Email').fill(email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(password);
|
|
||||||
|
|
||||||
const canvas = page.locator('canvas');
|
|
||||||
const box = await canvas.boundingBox();
|
|
||||||
|
|
||||||
if (box) {
|
|
||||||
await page.mouse.move(box.x + box.width / 8, box.y + box.height / 6);
|
|
||||||
await page.mouse.down();
|
|
||||||
await page.mouse.move(box.x + box.width / 8, box.y + box.height / 6);
|
|
||||||
await page.mouse.up();
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Sign Up' }).click();
|
|
||||||
|
|
||||||
await page.goto('/');
|
|
||||||
await page.getByLabel('Email').fill(email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
await expect(page).toHaveURL('/documents');
|
|
||||||
await page.context().storageState({ path: STORAGE_STATE });
|
|
||||||
});
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
%PDF-1.4
|
|
||||||
%<25><><EFBFBD><EFBFBD>
|
|
||||||
1 0 obj
|
|
||||||
<</Title (documenso)
|
|
||||||
/Producer (Skia/PDF m118 Google Docs Renderer)>>
|
|
||||||
endobj
|
|
||||||
3 0 obj
|
|
||||||
<</ca 1
|
|
||||||
/BM /Normal>>
|
|
||||||
endobj
|
|
||||||
4 0 obj
|
|
||||||
<</Length 84>> stream
|
|
||||||
1 0 0 -1 0 842 cm
|
|
||||||
q
|
|
||||||
.75 0 0 .75 0 0 cm
|
|
||||||
1 1 1 RG 1 1 1 rg
|
|
||||||
/G3 gs
|
|
||||||
0 0 794 1123 re
|
|
||||||
f
|
|
||||||
Q
|
|
||||||
|
|
||||||
endstream
|
|
||||||
endobj
|
|
||||||
2 0 obj
|
|
||||||
<</Type /Page
|
|
||||||
/Resources <</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]
|
|
||||||
/ExtGState <</G3 3 0 R>>>>
|
|
||||||
/MediaBox [0 0 596 842]
|
|
||||||
/Contents 4 0 R
|
|
||||||
/StructParents 0
|
|
||||||
/Parent 5 0 R>>
|
|
||||||
endobj
|
|
||||||
5 0 obj
|
|
||||||
<</Type /Pages
|
|
||||||
/Count 1
|
|
||||||
/Kids [2 0 R]>>
|
|
||||||
endobj
|
|
||||||
6 0 obj
|
|
||||||
<</Type /Catalog
|
|
||||||
/Pages 5 0 R>>
|
|
||||||
endobj
|
|
||||||
xref
|
|
||||||
0 7
|
|
||||||
0000000000 65535 f
|
|
||||||
0000000015 00000 n
|
|
||||||
0000000269 00000 n
|
|
||||||
0000000100 00000 n
|
|
||||||
0000000137 00000 n
|
|
||||||
0000000457 00000 n
|
|
||||||
0000000512 00000 n
|
|
||||||
trailer
|
|
||||||
<</Size 7
|
|
||||||
/Root 6 0 R
|
|
||||||
/Info 1 0 R>>
|
|
||||||
startxref
|
|
||||||
559
|
|
||||||
%%EOF
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import { type Page, expect, test } from '@playwright/test';
|
|
||||||
|
|
||||||
test.use({ storageState: { cookies: [], origins: [] } });
|
|
||||||
|
|
||||||
/*
|
|
||||||
Using them sequentially so the 2nd test
|
|
||||||
uses the details from the 1st (registration) test
|
|
||||||
*/
|
|
||||||
test.describe.configure({ mode: 'serial' });
|
|
||||||
|
|
||||||
const username = process.env.E2E_TEST_USERNAME || '';
|
|
||||||
const email = process.env.E2E_TEST_USER_EMAIL || '';
|
|
||||||
const password = process.env.E2E_TEST_USER_PASSWORD || '';
|
|
||||||
|
|
||||||
test('user can sign up with email and password', async ({ page }: { page: Page }) => {
|
|
||||||
await page.goto('/signup');
|
|
||||||
await page.getByLabel('Name').fill(username);
|
|
||||||
await page.getByLabel('Email').fill(email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(password);
|
|
||||||
|
|
||||||
const canvas = page.locator('canvas');
|
|
||||||
const box = await canvas.boundingBox();
|
|
||||||
|
|
||||||
if (box) {
|
|
||||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
|
||||||
await page.mouse.down();
|
|
||||||
await page.mouse.move(box.x + box.width / 4, box.y + box.height / 4);
|
|
||||||
await page.mouse.up();
|
|
||||||
}
|
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Sign Up' }).click();
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
|
|
||||||
await expect(page).toHaveURL('/documents');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('user can login with user and password', async ({ page }: { page: Page }) => {
|
|
||||||
await page.goto('/signin');
|
|
||||||
await page.getByLabel('Email').fill(email);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
|
|
||||||
await page.waitForURL('/documents');
|
|
||||||
await expect(page).toHaveURL('/documents');
|
|
||||||
});
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import path from 'path';
|
|
||||||
|
|
||||||
import { expect, test } from '../test-fixtures/documents-page/documents-page';
|
|
||||||
|
|
||||||
const signer_name = process.env.E2E_TEST_SIGNER_NAME;
|
|
||||||
const signer_email = process.env.E2E_TEST_SIGNER_EMAIL;
|
|
||||||
const signing_subject = process.env.E2E_TEST_SIGNING_SUBJECT;
|
|
||||||
const signing_message = process.env.E2E_TEST_SIGNING_MESSAGE;
|
|
||||||
|
|
||||||
if (!signer_name || !signer_email || !signing_subject || !signing_message) {
|
|
||||||
throw new Error('Required environment variables for tests are not defined');
|
|
||||||
}
|
|
||||||
|
|
||||||
test.describe('Document upload test', () => {
|
|
||||||
test.beforeEach(async ({ documentsPage }) => {
|
|
||||||
await documentsPage.uploadDocument(path.join(__dirname, './documenso.pdf'));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('user can see /documents page', async ({ page, documentsPage }) => {
|
|
||||||
await documentsPage.goToDocumentsPage();
|
|
||||||
await expect(page).toHaveTitle('Documenso - The Open Source DocuSign Alternative');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('user can upload a document succesfully', async ({ page }) => {
|
|
||||||
await expect(page.getByText('Drag & drop your document here.')).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('user can send the document for signing succesfully', async ({ documentsPage, page }) => {
|
|
||||||
await documentsPage.addSigner(signer_email, signer_name);
|
|
||||||
await documentsPage.addSignatureField(signer_name);
|
|
||||||
await documentsPage.addSubjectAndMessage(signing_subject, signing_message);
|
|
||||||
|
|
||||||
await expect(page).toHaveURL('/documents');
|
|
||||||
await expect(page.getByRole('status').locator('div').nth(2)).toHaveText(
|
|
||||||
'Your document has been sent successfully.',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import type { Locator, Page } from '@playwright/test';
|
|
||||||
|
|
||||||
export class DocumentsPage {
|
|
||||||
private readonly fileInput: Locator;
|
|
||||||
private readonly subject: Locator;
|
|
||||||
private readonly message: Locator;
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
constructor(public readonly page: Page) {
|
|
||||||
this.fileInput = this.page.locator('input[type=file]');
|
|
||||||
this.subject = this.page
|
|
||||||
.locator('div')
|
|
||||||
.filter({ hasText: /^Subject \(Optional\)$/ })
|
|
||||||
.locator('input');
|
|
||||||
this.message = this.page
|
|
||||||
.locator('div')
|
|
||||||
.filter({ hasText: /^Message \(Optional\)$/ })
|
|
||||||
.locator('textarea');
|
|
||||||
}
|
|
||||||
|
|
||||||
async goToDocumentsPage() {
|
|
||||||
await this.page.goto('/documents');
|
|
||||||
}
|
|
||||||
|
|
||||||
async uploadDocument(filePath: string) {
|
|
||||||
await this.goToDocumentsPage();
|
|
||||||
|
|
||||||
await this.fileInput.setInputFiles(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
async addSigner(email: string, name: string) {
|
|
||||||
await this.page.getByLabel('Email*').fill(email);
|
|
||||||
await this.page.getByLabel('Name').fill(name);
|
|
||||||
await this.page.getByRole('button', { name: 'Continue' }).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
async addSignatureField(name: string) {
|
|
||||||
await this.page
|
|
||||||
.getByRole('button', { name: `${name} Signature` })
|
|
||||||
.dragTo(this.page.locator('canvas'));
|
|
||||||
await this.page.getByRole('button', { name: 'Continue' }).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
async addSubjectAndMessage(subject: string, message: string) {
|
|
||||||
await this.subject.fill(subject);
|
|
||||||
await this.message.fill(message);
|
|
||||||
await this.page.getByRole('button', { name: 'Send' }).click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { test as base } from '@playwright/test';
|
|
||||||
|
|
||||||
import { DocumentsPage } from './DocumentsPageObject';
|
|
||||||
|
|
||||||
export const test = base.extend<{ documentsPage: DocumentsPage }>({
|
|
||||||
documentsPage: async ({ page }, use) => {
|
|
||||||
const documentsPage = new DocumentsPage(page);
|
|
||||||
|
|
||||||
await use(documentsPage);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export { expect } from '@playwright/test';
|
|
||||||
320
package-lock.json
generated
320
package-lock.json
generated
@@ -98,13 +98,11 @@
|
|||||||
"react-icons": "^4.8.0",
|
"react-icons": "^4.8.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.1",
|
||||||
"sharp": "0.32.5",
|
"sharp": "0.32.5",
|
||||||
"start-server-and-test": "^2.0.1",
|
|
||||||
"ts-pattern": "^5.0.5",
|
"ts-pattern": "^5.0.5",
|
||||||
"typescript": "5.1.6",
|
"typescript": "5.1.6",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.38.0",
|
|
||||||
"@types/formidable": "^2.0.6",
|
"@types/formidable": "^2.0.6",
|
||||||
"@types/luxon": "^3.3.1",
|
"@types/luxon": "^3.3.1",
|
||||||
"@types/node": "20.1.0",
|
"@types/node": "20.1.0",
|
||||||
@@ -2452,19 +2450,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@hapi/hoek": {
|
|
||||||
"version": "9.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
|
|
||||||
"integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ=="
|
|
||||||
},
|
|
||||||
"node_modules/@hapi/topo": {
|
|
||||||
"version": "5.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
|
|
||||||
"integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@hapi/hoek": "^9.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@hookform/resolvers": {
|
"node_modules/@hookform/resolvers": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.3.0.tgz",
|
||||||
@@ -3801,21 +3786,6 @@
|
|||||||
"url": "https://opencollective.com/unts"
|
"url": "https://opencollective.com/unts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@playwright/test": {
|
|
||||||
"version": "1.38.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz",
|
|
||||||
"integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"playwright": "1.38.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@prisma/client": {
|
"node_modules/@prisma/client": {
|
||||||
"version": "5.3.1",
|
"version": "5.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.3.1.tgz",
|
||||||
@@ -5465,24 +5435,6 @@
|
|||||||
"url": "https://ko-fi.com/killymxi"
|
"url": "https://ko-fi.com/killymxi"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sideway/address": {
|
|
||||||
"version": "4.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
|
||||||
"integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==",
|
|
||||||
"dependencies": {
|
|
||||||
"@hapi/hoek": "^9.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sideway/formula": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg=="
|
|
||||||
},
|
|
||||||
"node_modules/@sideway/pinpoint": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="
|
|
||||||
},
|
|
||||||
"node_modules/@sindresorhus/slugify": {
|
"node_modules/@sindresorhus/slugify": {
|
||||||
"version": "2.2.1",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz",
|
||||||
@@ -7667,14 +7619,6 @@
|
|||||||
"url": "https://github.com/sponsors/wooorm"
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/check-more-types": {
|
|
||||||
"version": "2.24.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
|
|
||||||
"integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
@@ -9180,11 +9124,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/duplexer": {
|
|
||||||
"version": "0.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
|
||||||
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="
|
|
||||||
},
|
|
||||||
"node_modules/duplexer2": {
|
"node_modules/duplexer2": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
|
||||||
@@ -10389,20 +10328,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/event-stream": {
|
|
||||||
"version": "3.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
|
|
||||||
"integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
|
|
||||||
"dependencies": {
|
|
||||||
"duplexer": "~0.1.1",
|
|
||||||
"from": "~0",
|
|
||||||
"map-stream": "~0.1.0",
|
|
||||||
"pause-stream": "0.0.11",
|
|
||||||
"split": "0.3",
|
|
||||||
"stream-combiner": "~0.0.4",
|
|
||||||
"through": "~2.3.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/eventemitter3": {
|
"node_modules/eventemitter3": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
@@ -10802,11 +10727,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/from": {
|
|
||||||
"version": "0.1.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
|
|
||||||
"integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g=="
|
|
||||||
},
|
|
||||||
"node_modules/fs-constants": {
|
"node_modules/fs-constants": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
@@ -12245,18 +12165,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz",
|
||||||
"integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="
|
"integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="
|
||||||
},
|
},
|
||||||
"node_modules/joi": {
|
|
||||||
"version": "17.10.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/joi/-/joi-17.10.2.tgz",
|
|
||||||
"integrity": "sha512-hcVhjBxRNW/is3nNLdGLIjkgXetkeGc2wyhydhz8KumG23Aerk4HPjU5zaPAMRqXQFc0xNqXTC7+zQjxr0GlKA==",
|
|
||||||
"dependencies": {
|
|
||||||
"@hapi/hoek": "^9.0.0",
|
|
||||||
"@hapi/topo": "^5.0.0",
|
|
||||||
"@sideway/address": "^4.1.3",
|
|
||||||
"@sideway/formula": "^3.0.1",
|
|
||||||
"@sideway/pinpoint": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/jose": {
|
"node_modules/jose": {
|
||||||
"version": "4.14.4",
|
"version": "4.14.4",
|
||||||
"resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
|
"resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz",
|
||||||
@@ -12491,14 +12399,6 @@
|
|||||||
"language-subtag-registry": "~0.3.2"
|
"language-subtag-registry": "~0.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lazy-ass": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
|
|
||||||
"integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==",
|
|
||||||
"engines": {
|
|
||||||
"node": "> 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/leac": {
|
"node_modules/leac": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
||||||
@@ -13046,11 +12946,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/map-stream": {
|
|
||||||
"version": "0.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
|
|
||||||
"integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g=="
|
|
||||||
},
|
|
||||||
"node_modules/markdown-extensions": {
|
"node_modules/markdown-extensions": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-1.1.1.tgz",
|
||||||
@@ -15104,14 +14999,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pause-stream": {
|
|
||||||
"version": "0.0.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
|
|
||||||
"integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
|
|
||||||
"dependencies": {
|
|
||||||
"through": "~2.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pdf-lib": {
|
"node_modules/pdf-lib": {
|
||||||
"version": "1.17.1",
|
"version": "1.17.1",
|
||||||
"resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
|
||||||
@@ -15210,36 +15097,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
|
||||||
"version": "1.38.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz",
|
|
||||||
"integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"playwright-core": "1.38.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/playwright-core": {
|
|
||||||
"version": "1.38.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz",
|
|
||||||
"integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==",
|
|
||||||
"dev": true,
|
|
||||||
"bin": {
|
|
||||||
"playwright-core": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.27",
|
"version": "8.4.27",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
|
||||||
@@ -15790,20 +15647,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
|
||||||
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
"integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q=="
|
||||||
},
|
},
|
||||||
"node_modules/ps-tree": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==",
|
|
||||||
"dependencies": {
|
|
||||||
"event-stream": "=3.3.4"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"ps-tree": "bin/ps-tree.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/pump": {
|
"node_modules/pump": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||||
@@ -17424,14 +17267,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz",
|
"resolved": "https://registry.npmjs.org/rusha/-/rusha-0.8.14.tgz",
|
||||||
"integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA=="
|
"integrity": "sha512-cLgakCUf6PedEu15t8kbsjnwIFFR2D4RfL+W3iWFJ4iac7z4B0ZI8fxy4R3J956kAI68HclCFGL8MPoUVC3qVA=="
|
||||||
},
|
},
|
||||||
"node_modules/rxjs": {
|
|
||||||
"version": "7.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
|
|
||||||
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": "^2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/sade": {
|
"node_modules/sade": {
|
||||||
"version": "1.8.1",
|
"version": "1.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
||||||
@@ -17807,17 +17642,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
|
||||||
"integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w=="
|
"integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w=="
|
||||||
},
|
},
|
||||||
"node_modules/split": {
|
|
||||||
"version": "0.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
|
|
||||||
"integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
|
|
||||||
"dependencies": {
|
|
||||||
"through": "2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/split2": {
|
"node_modules/split2": {
|
||||||
"version": "3.2.2",
|
"version": "3.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz",
|
||||||
@@ -17849,121 +17673,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||||
},
|
},
|
||||||
"node_modules/start-server-and-test": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-8PFo4DLLLCDMuS51/BEEtE1m9CAXw1LNVtZSS1PzkYQh6Qf9JUwM4huYeSoUumaaoAyuwYBwCa9OsrcpMqcOdQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"arg": "^5.0.2",
|
|
||||||
"bluebird": "3.7.2",
|
|
||||||
"check-more-types": "2.24.0",
|
|
||||||
"debug": "4.3.4",
|
|
||||||
"execa": "5.1.1",
|
|
||||||
"lazy-ass": "1.6.0",
|
|
||||||
"ps-tree": "1.2.0",
|
|
||||||
"wait-on": "7.0.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"server-test": "src/bin/start.js",
|
|
||||||
"start-server-and-test": "src/bin/start.js",
|
|
||||||
"start-test": "src/bin/start.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/arg": {
|
|
||||||
"version": "5.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
|
||||||
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/bluebird": {
|
|
||||||
"version": "3.7.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
|
||||||
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/execa": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
|
|
||||||
"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
|
|
||||||
"dependencies": {
|
|
||||||
"cross-spawn": "^7.0.3",
|
|
||||||
"get-stream": "^6.0.0",
|
|
||||||
"human-signals": "^2.1.0",
|
|
||||||
"is-stream": "^2.0.0",
|
|
||||||
"merge-stream": "^2.0.0",
|
|
||||||
"npm-run-path": "^4.0.1",
|
|
||||||
"onetime": "^5.1.2",
|
|
||||||
"signal-exit": "^3.0.3",
|
|
||||||
"strip-final-newline": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/human-signals": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.17.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/is-stream": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/mimic-fn": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/npm-run-path": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
|
||||||
"dependencies": {
|
|
||||||
"path-key": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/onetime": {
|
|
||||||
"version": "5.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
|
||||||
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
|
||||||
"dependencies": {
|
|
||||||
"mimic-fn": "^2.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/start-server-and-test/node_modules/strip-final-newline": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||||
@@ -17972,14 +17681,6 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stream-combiner": {
|
|
||||||
"version": "0.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
|
|
||||||
"integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
|
|
||||||
"dependencies": {
|
|
||||||
"duplexer": "~0.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/stream-shift": {
|
"node_modules/stream-shift": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
|
||||||
@@ -18525,7 +18226,8 @@
|
|||||||
"node_modules/through": {
|
"node_modules/through": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||||
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
|
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/through2": {
|
"node_modules/through2": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
@@ -19786,24 +19488,6 @@
|
|||||||
"d3-timer": "^3.0.1"
|
"d3-timer": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wait-on": {
|
|
||||||
"version": "7.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.0.1.tgz",
|
|
||||||
"integrity": "sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==",
|
|
||||||
"dependencies": {
|
|
||||||
"axios": "^0.27.2",
|
|
||||||
"joi": "^17.7.0",
|
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"minimist": "^1.2.7",
|
|
||||||
"rxjs": "^7.8.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"wait-on": "bin/wait-on"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/watchpack": {
|
"node_modules/watchpack": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||||
|
|||||||
@@ -4,12 +4,10 @@
|
|||||||
"build": "turbo run build",
|
"build": "turbo run build",
|
||||||
"dev": "turbo run dev --filter=@documenso/web --filter=@documenso/marketing",
|
"dev": "turbo run dev --filter=@documenso/web --filter=@documenso/marketing",
|
||||||
"start": "cd apps && cd web && next start",
|
"start": "cd apps && cd web && next start",
|
||||||
"test": "cd apps && cd web && npm run test:e2e",
|
|
||||||
"lint": "turbo run lint",
|
"lint": "turbo run lint",
|
||||||
"format": "prettier --write \"**/*.{js,jsx,cjs,mjs,ts,tsx,cts,mts,mdx}\"",
|
"format": "prettier --write \"**/*.{js,jsx,cjs,mjs,ts,tsx,cts,mts,mdx}\"",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"commitlint": "commitlint --edit",
|
"commitlint": "commitlint --edit",
|
||||||
"ci": "turbo run build test:e2e lint",
|
|
||||||
"clean": "turbo run clean && rimraf node_modules"
|
"clean": "turbo run clean && rimraf node_modules"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
BIN
packages/email/static/user-plus.png
Normal file
BIN
packages/email/static/user-plus.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 367 B |
@@ -1,7 +1,9 @@
|
|||||||
import { Button, Column, Img, Row, Section, Tailwind, Text } from '@react-email/components';
|
import { Button, Column, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||||
|
|
||||||
import * as config from '@documenso/tailwind-config';
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
export interface TemplateDocumentCompletedProps {
|
export interface TemplateDocumentCompletedProps {
|
||||||
downloadLink: string;
|
downloadLink: string;
|
||||||
documentName: string;
|
documentName: string;
|
||||||
@@ -27,27 +29,20 @@ export const TemplateDocumentCompleted = ({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Section>
|
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
||||||
<Row className="table-fixed">
|
|
||||||
<Column />
|
|
||||||
|
|
||||||
<Column>
|
<Section>
|
||||||
<Img
|
<Section className="mb-4">
|
||||||
className="h-42 mx-auto"
|
<Column align="center">
|
||||||
src={getAssetUrl('/static/document.png')}
|
<Text className="text-base font-semibold text-[#7AC455]">
|
||||||
alt="Documenso"
|
<Img
|
||||||
/>
|
src={getAssetUrl('/static/completed.png')}
|
||||||
|
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
||||||
|
/>
|
||||||
|
Completed
|
||||||
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
|
</Section>
|
||||||
<Column />
|
|
||||||
</Row>
|
|
||||||
</Section>
|
|
||||||
|
|
||||||
<Section>
|
|
||||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-[#7AC455]">
|
|
||||||
<Img src={getAssetUrl('/static/completed.png')} className="-mb-0.5 mr-2 inline h-7 w-7" />
|
|
||||||
Completed
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||||
“{documentName}” was signed by all signers
|
“{documentName}” was signed by all signers
|
||||||
@@ -66,10 +61,13 @@ export const TemplateDocumentCompleted = ({
|
|||||||
Review
|
Review
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button
|
<Button
|
||||||
className="inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
className="rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||||
href={downloadLink}
|
href={downloadLink}
|
||||||
>
|
>
|
||||||
<Img src={getAssetUrl('/static/download.png')} className="-mb-1 mr-2 inline h-5 w-5" />
|
<Img
|
||||||
|
src={getAssetUrl('/static/download.png')}
|
||||||
|
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
||||||
|
/>
|
||||||
Download
|
Download
|
||||||
</Button>
|
</Button>
|
||||||
</Section>
|
</Section>
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Column, Img, Row, Section } from '@react-email/components';
|
||||||
|
|
||||||
|
export interface TemplateDocumentImageProps {
|
||||||
|
assetBaseUrl: string;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TemplateDocumentImage = ({ assetBaseUrl, className }: TemplateDocumentImageProps) => {
|
||||||
|
const getAssetUrl = (path: string) => {
|
||||||
|
return new URL(path, assetBaseUrl).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section className={className}>
|
||||||
|
<Row className="table-fixed">
|
||||||
|
<Column />
|
||||||
|
|
||||||
|
<Column>
|
||||||
|
<Img className="h-42 mx-auto" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
||||||
|
</Column>
|
||||||
|
|
||||||
|
<Column />
|
||||||
|
</Row>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TemplateDocumentImage;
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Button, Column, Img, Row, Section, Tailwind, Text } from '@react-email/components';
|
import { Button, Section, Tailwind, Text } from '@react-email/components';
|
||||||
|
|
||||||
import * as config from '@documenso/tailwind-config';
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
export interface TemplateDocumentInviteProps {
|
export interface TemplateDocumentInviteProps {
|
||||||
inviterName: string;
|
inviterName: string;
|
||||||
inviterEmail: string;
|
inviterEmail: string;
|
||||||
@@ -16,10 +18,6 @@ export const TemplateDocumentInvite = ({
|
|||||||
signDocumentLink,
|
signDocumentLink,
|
||||||
assetBaseUrl,
|
assetBaseUrl,
|
||||||
}: TemplateDocumentInviteProps) => {
|
}: TemplateDocumentInviteProps) => {
|
||||||
const getAssetUrl = (path: string) => {
|
|
||||||
return new URL(path, assetBaseUrl).toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tailwind
|
<Tailwind
|
||||||
config={{
|
config={{
|
||||||
@@ -30,21 +28,7 @@ export const TemplateDocumentInvite = ({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Section className="mt-4">
|
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
||||||
<Row className="table-fixed">
|
|
||||||
<Column />
|
|
||||||
|
|
||||||
<Column>
|
|
||||||
<Img
|
|
||||||
className="h-42 mx-auto"
|
|
||||||
src={getAssetUrl('/static/document.png')}
|
|
||||||
alt="Documenso"
|
|
||||||
/>
|
|
||||||
</Column>
|
|
||||||
|
|
||||||
<Column />
|
|
||||||
</Row>
|
|
||||||
</Section>
|
|
||||||
|
|
||||||
<Section>
|
<Section>
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Column, Img, Row, Section, Tailwind, Text } from '@react-email/components';
|
import { Column, Img, Section, Tailwind, Text } from '@react-email/components';
|
||||||
|
|
||||||
import * as config from '@documenso/tailwind-config';
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
export interface TemplateDocumentPendingProps {
|
export interface TemplateDocumentPendingProps {
|
||||||
documentName: string;
|
documentName: string;
|
||||||
assetBaseUrl: string;
|
assetBaseUrl: string;
|
||||||
@@ -25,27 +27,20 @@ export const TemplateDocumentPending = ({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Section>
|
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
||||||
<Row className="table-fixed">
|
|
||||||
<Column />
|
|
||||||
|
|
||||||
<Column>
|
<Section>
|
||||||
<Img
|
<Section className="mb-4">
|
||||||
className="h-42 mx-auto"
|
<Column align="center">
|
||||||
src={getAssetUrl('/static/document.png')}
|
<Text className="text-base font-semibold text-blue-500">
|
||||||
alt="Documenso"
|
<Img
|
||||||
/>
|
src={getAssetUrl('/static/clock.png')}
|
||||||
|
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
||||||
|
/>
|
||||||
|
Waiting for others
|
||||||
|
</Text>
|
||||||
</Column>
|
</Column>
|
||||||
|
</Section>
|
||||||
<Column />
|
|
||||||
</Row>
|
|
||||||
</Section>
|
|
||||||
|
|
||||||
<Section>
|
|
||||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-blue-500">
|
|
||||||
<Img src={getAssetUrl('/static/clock.png')} className="-mb-0.5 mr-2 inline h-7 w-7" />
|
|
||||||
Waiting for others
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||||
“{documentName}” has been signed
|
“{documentName}” has been signed
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
import { Button, Column, Img, Link, Section, Tailwind, Text } from '@react-email/components';
|
||||||
|
|
||||||
import * as config from '@documenso/tailwind-config';
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
export interface TemplateDocumentSelfSignedProps {
|
export interface TemplateDocumentSelfSignedProps {
|
||||||
downloadLink: string;
|
|
||||||
documentName: string;
|
documentName: string;
|
||||||
assetBaseUrl: string;
|
assetBaseUrl: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TemplateDocumentSelfSigned = ({
|
export const TemplateDocumentSelfSigned = ({
|
||||||
downloadLink,
|
|
||||||
documentName,
|
documentName,
|
||||||
assetBaseUrl,
|
assetBaseUrl,
|
||||||
}: TemplateDocumentSelfSignedProps) => {
|
}: TemplateDocumentSelfSignedProps) => {
|
||||||
|
const signUpUrl = `${process.env.NEXT_PUBLIC_WEBAPP_URL ?? 'http://localhost:3000'}/signup`;
|
||||||
|
|
||||||
const getAssetUrl = (path: string) => {
|
const getAssetUrl = (path: string) => {
|
||||||
return new URL(path, assetBaseUrl).toString();
|
return new URL(path, assetBaseUrl).toString();
|
||||||
};
|
};
|
||||||
@@ -27,39 +29,59 @@ export const TemplateDocumentSelfSigned = ({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
||||||
|
|
||||||
<Section className="flex-row items-center justify-center">
|
<Section className="flex-row items-center justify-center">
|
||||||
<div className="flex items-center justify-center p-4">
|
<Section>
|
||||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
<Column align="center">
|
||||||
</div>
|
<Text className="text-base font-semibold text-[#7AC455]">
|
||||||
|
<Img
|
||||||
|
src={getAssetUrl('/static/completed.png')}
|
||||||
|
className="-mt-0.5 mr-2 inline h-7 w-7 align-middle"
|
||||||
|
/>
|
||||||
|
Completed
|
||||||
|
</Text>
|
||||||
|
</Column>
|
||||||
|
</Section>
|
||||||
|
|
||||||
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-[#7AC455]">
|
<Text className="text-primary mb-0 mt-6 text-center text-lg font-semibold">
|
||||||
<Img src={getAssetUrl('/static/completed.png')} className="-mb-0.5 mr-2 inline h-7 w-7" />
|
|
||||||
Completed
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
|
||||||
You have signed “{documentName}”
|
You have signed “{documentName}”
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||||
Check out our plans to access the full suite of features.
|
Create a{' '}
|
||||||
|
<Link
|
||||||
|
href={signUpUrl}
|
||||||
|
target="_blank"
|
||||||
|
className="text-documenso-700 hover:text-documenso-600 whitespace-nowrap"
|
||||||
|
>
|
||||||
|
free account
|
||||||
|
</Link>{' '}
|
||||||
|
to access your signed documents at any time.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Section className="mb-6 mt-8 text-center">
|
<Section className="mb-6 mt-8 text-center">
|
||||||
<Button
|
<Button
|
||||||
className="mr-4 inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
href={signUpUrl}
|
||||||
|
className="mr-4 rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||||
|
>
|
||||||
|
<Img
|
||||||
|
src={getAssetUrl('/static/user-plus.png')}
|
||||||
|
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
||||||
|
/>
|
||||||
|
Create account
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
className="rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||||
href="https://documenso.com/pricing"
|
href="https://documenso.com/pricing"
|
||||||
>
|
>
|
||||||
<Img src={getAssetUrl('/static/review.png')} className="-mb-1 mr-2 inline h-5 w-5" />
|
<Img
|
||||||
|
src={getAssetUrl('/static/review.png')}
|
||||||
|
className="mb-0.5 mr-2 inline h-5 w-5 align-middle"
|
||||||
|
/>
|
||||||
View plans
|
View plans
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
className="inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
|
||||||
href={downloadLink}
|
|
||||||
>
|
|
||||||
<Img src={getAssetUrl('/static/download.png')} className="-mb-1 mr-2 inline h-5 w-5" />
|
|
||||||
Download
|
|
||||||
</Button>
|
|
||||||
</Section>
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
</Tailwind>
|
</Tailwind>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Button, Img, Section, Tailwind, Text } from '@react-email/components';
|
import { Button, Section, Tailwind, Text } from '@react-email/components';
|
||||||
|
|
||||||
import * as config from '@documenso/tailwind-config';
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
export type TemplateForgotPasswordProps = {
|
export type TemplateForgotPasswordProps = {
|
||||||
resetPasswordLink: string;
|
resetPasswordLink: string;
|
||||||
assetBaseUrl: string;
|
assetBaseUrl: string;
|
||||||
@@ -11,10 +13,6 @@ export const TemplateForgotPassword = ({
|
|||||||
resetPasswordLink,
|
resetPasswordLink,
|
||||||
assetBaseUrl,
|
assetBaseUrl,
|
||||||
}: TemplateForgotPasswordProps) => {
|
}: TemplateForgotPasswordProps) => {
|
||||||
const getAssetUrl = (path: string) => {
|
|
||||||
return new URL(path, assetBaseUrl).toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tailwind
|
<Tailwind
|
||||||
config={{
|
config={{
|
||||||
@@ -25,11 +23,9 @@ export const TemplateForgotPassword = ({
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Section className="mt-4 flex-row items-center justify-center">
|
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
||||||
<div className="flex items-center justify-center p-4">
|
|
||||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<Section className="flex-row items-center justify-center">
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
Forgot your password?
|
Forgot your password?
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { Img, Section, Tailwind, Text } from '@react-email/components';
|
import { Button, Section, Tailwind, Text } from '@react-email/components';
|
||||||
|
|
||||||
import * as config from '@documenso/tailwind-config';
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
import { TemplateDocumentImage } from './template-document-image';
|
||||||
|
|
||||||
export interface TemplateResetPasswordProps {
|
export interface TemplateResetPasswordProps {
|
||||||
userName: string;
|
userName: string;
|
||||||
userEmail: string;
|
userEmail: string;
|
||||||
@@ -9,10 +11,6 @@ export interface TemplateResetPasswordProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TemplateResetPassword = ({ assetBaseUrl }: TemplateResetPasswordProps) => {
|
export const TemplateResetPassword = ({ assetBaseUrl }: TemplateResetPasswordProps) => {
|
||||||
const getAssetUrl = (path: string) => {
|
|
||||||
return new URL(path, assetBaseUrl).toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tailwind
|
<Tailwind
|
||||||
config={{
|
config={{
|
||||||
@@ -23,11 +21,9 @@ export const TemplateResetPassword = ({ assetBaseUrl }: TemplateResetPasswordPro
|
|||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Section className="mt-4 flex-row items-center justify-center">
|
<TemplateDocumentImage className="mt-6" assetBaseUrl={assetBaseUrl} />
|
||||||
<div className="flex items-center justify-center p-4">
|
|
||||||
<Img className="h-42" src={getAssetUrl('/static/document.png')} alt="Documenso" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<Section className="flex-row items-center justify-center">
|
||||||
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
Password updated!
|
Password updated!
|
||||||
</Text>
|
</Text>
|
||||||
@@ -35,6 +31,15 @@ export const TemplateResetPassword = ({ assetBaseUrl }: TemplateResetPasswordPro
|
|||||||
<Text className="my-1 text-center text-base text-slate-400">
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
Your password has been updated.
|
Your password has been updated.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
<Section className="mb-6 mt-8 text-center">
|
||||||
|
<Button
|
||||||
|
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||||
|
href={`${process.env.NEXT_PUBLIC_WEBAPP_URL ?? 'http://localhost:3000'}/signin`}
|
||||||
|
>
|
||||||
|
Sign In
|
||||||
|
</Button>
|
||||||
|
</Section>
|
||||||
</Section>
|
</Section>
|
||||||
</Tailwind>
|
</Tailwind>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
TemplateDocumentCompleted,
|
TemplateDocumentCompleted,
|
||||||
TemplateDocumentCompletedProps,
|
TemplateDocumentCompletedProps,
|
||||||
} from '../template-components/template-document-completed';
|
} from '../template-components/template-document-completed';
|
||||||
import TemplateFooter from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
|
|
||||||
export type DocumentCompletedEmailTemplateProps = Partial<TemplateDocumentCompletedProps>;
|
export type DocumentCompletedEmailTemplateProps = Partial<TemplateDocumentCompletedProps>;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
TemplateDocumentInvite,
|
TemplateDocumentInvite,
|
||||||
TemplateDocumentInviteProps,
|
TemplateDocumentInviteProps,
|
||||||
} from '../template-components/template-document-invite';
|
} from '../template-components/template-document-invite';
|
||||||
import TemplateFooter from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
|
|
||||||
export type DocumentInviteEmailTemplateProps = Partial<TemplateDocumentInviteProps> & {
|
export type DocumentInviteEmailTemplateProps = Partial<TemplateDocumentInviteProps> & {
|
||||||
customBody?: string;
|
customBody?: string;
|
||||||
|
|||||||
@@ -15,12 +15,11 @@ import {
|
|||||||
TemplateDocumentSelfSigned,
|
TemplateDocumentSelfSigned,
|
||||||
TemplateDocumentSelfSignedProps,
|
TemplateDocumentSelfSignedProps,
|
||||||
} from '../template-components/template-document-self-signed';
|
} from '../template-components/template-document-self-signed';
|
||||||
import TemplateFooter from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
|
|
||||||
export type DocumentSelfSignedTemplateProps = TemplateDocumentSelfSignedProps;
|
export type DocumentSelfSignedTemplateProps = TemplateDocumentSelfSignedProps;
|
||||||
|
|
||||||
export const DocumentSelfSignedEmailTemplate = ({
|
export const DocumentSelfSignedEmailTemplate = ({
|
||||||
downloadLink = 'https://documenso.com',
|
|
||||||
documentName = 'Open Source Pledge.pdf',
|
documentName = 'Open Source Pledge.pdf',
|
||||||
assetBaseUrl = 'http://localhost:3002',
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
}: DocumentSelfSignedTemplateProps) => {
|
}: DocumentSelfSignedTemplateProps) => {
|
||||||
@@ -54,7 +53,6 @@ export const DocumentSelfSignedEmailTemplate = ({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TemplateDocumentSelfSigned
|
<TemplateDocumentSelfSigned
|
||||||
downloadLink={downloadLink}
|
|
||||||
documentName={documentName}
|
documentName={documentName}
|
||||||
assetBaseUrl={assetBaseUrl}
|
assetBaseUrl={assetBaseUrl}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
|
|
||||||
import config from '@documenso/tailwind-config';
|
import config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
import TemplateFooter from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
import {
|
import {
|
||||||
TemplateForgotPassword,
|
TemplateForgotPassword,
|
||||||
TemplateForgotPasswordProps,
|
TemplateForgotPasswordProps,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
|
|
||||||
import config from '@documenso/tailwind-config';
|
import config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
import TemplateFooter from '../template-components/template-footer';
|
import { TemplateFooter } from '../template-components/template-footer';
|
||||||
import {
|
import {
|
||||||
TemplateResetPassword,
|
TemplateResetPassword,
|
||||||
TemplateResetPasswordProps,
|
TemplateResetPasswordProps,
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import { prisma } from '@documenso/prisma';
|
|
||||||
|
|
||||||
export const deleteUserAndItsData = async (name: string) => {
|
|
||||||
const user = await prisma.user.findFirst({
|
|
||||||
where: {
|
|
||||||
name: {
|
|
||||||
contains: name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
throw new Error(`User with name ${name} not found`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const document = await prisma.document.findMany({
|
|
||||||
where: {
|
|
||||||
userId: user.id,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
documentData: {
|
|
||||||
select: {
|
|
||||||
data: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return Promise.all([
|
|
||||||
await prisma.user.delete({
|
|
||||||
where: {
|
|
||||||
id: user.id,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
await prisma.documentData.deleteMany({
|
|
||||||
where: {
|
|
||||||
data: document[0]?.documentData.data,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
-- CreateTable
|
|
||||||
CREATE TABLE "PasswordResetToken" (
|
|
||||||
"id" SERIAL NOT NULL,
|
|
||||||
"token" TEXT NOT NULL,
|
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"userId" INTEGER NOT NULL,
|
|
||||||
|
|
||||||
CONSTRAINT "PasswordResetToken_pkey" PRIMARY KEY ("id")
|
|
||||||
);
|
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE UNIQUE INDEX "PasswordResetToken_token_key" ON "PasswordResetToken"("token");
|
|
||||||
|
|
||||||
-- AddForeignKey
|
|
||||||
ALTER TABLE "PasswordResetToken" ADD CONSTRAINT "PasswordResetToken_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
/*
|
|
||||||
Warnings:
|
|
||||||
|
|
||||||
- Added the required column `expiry` to the `PasswordResetToken` table without a default value. This is not possible if the table is not empty.
|
|
||||||
|
|
||||||
*/
|
|
||||||
-- AlterTable
|
|
||||||
ALTER TABLE "PasswordResetToken" ADD COLUMN "expiry" TIMESTAMP(3) NOT NULL;
|
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
DROP TABLE IF EXISTS "PasswordResetToken" CASCADE;
|
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "PasswordResetToken" (
|
CREATE TABLE "PasswordResetToken" (
|
||||||
"id" SERIAL NOT NULL,
|
"id" SERIAL NOT NULL,
|
||||||
|
|||||||
28
turbo.json
28
turbo.json
@@ -2,8 +2,13 @@
|
|||||||
"$schema": "https://turbo.build/schema.json",
|
"$schema": "https://turbo.build/schema.json",
|
||||||
"pipeline": {
|
"pipeline": {
|
||||||
"build": {
|
"build": {
|
||||||
"dependsOn": ["^build"],
|
"dependsOn": [
|
||||||
"outputs": [".next/**", "!.next/cache/**"]
|
"^build"
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
".next/**",
|
||||||
|
"!.next/cache/**"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"lint": {},
|
"lint": {},
|
||||||
"clean": {
|
"clean": {
|
||||||
@@ -12,26 +17,13 @@
|
|||||||
"dev": {
|
"dev": {
|
||||||
"cache": false,
|
"cache": false,
|
||||||
"persistent": true
|
"persistent": true
|
||||||
},
|
|
||||||
"test:e2e": {
|
|
||||||
"dependsOn": ["^build"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"globalDependencies": ["**/.env.*local"],
|
"globalDependencies": [
|
||||||
|
"**/.env.*local"
|
||||||
|
],
|
||||||
"globalEnv": [
|
"globalEnv": [
|
||||||
"APP_VERSION",
|
"APP_VERSION",
|
||||||
|
|
||||||
"E2E_TEST_USERNAME",
|
|
||||||
"E2E_TEST_USER_EMAIL",
|
|
||||||
"E2E_TEST_USER_PASSWORD",
|
|
||||||
"E2E_TEST_SIGNER_NAME",
|
|
||||||
"E2E_TEST_SIGNER_EMAIL",
|
|
||||||
"E2E_TEST_SIGNING_SUBJECT",
|
|
||||||
"E2E_TEST_SIGNING_MESSAGE",
|
|
||||||
"E2E_TEST_AUTHENTICATE_USERNAME",
|
|
||||||
"E2E_TEST_AUTHENTICATE_USER_EMAIL",
|
|
||||||
"E2E_TEST_AUTHENTICATE_USER_PASSWORD",
|
|
||||||
|
|
||||||
"NEXTAUTH_URL",
|
"NEXTAUTH_URL",
|
||||||
"NEXTAUTH_SECRET",
|
"NEXTAUTH_SECRET",
|
||||||
"NEXT_PUBLIC_PROJECT",
|
"NEXT_PUBLIC_PROJECT",
|
||||||
|
|||||||
Reference in New Issue
Block a user