Compare commits
174 Commits
8b10e991ac
...
c4d2f741ab
Author | SHA1 | Date | |
---|---|---|---|
|
c4d2f741ab | ||
|
fd71c57aab | ||
|
0be82b4f96 | ||
|
f83ec3a8b4 | ||
|
d00e2ed37c | ||
|
1a963974d8 | ||
|
7b9c67edc4 | ||
|
5655c93ea1 | ||
|
1db399d12d | ||
|
29862b5323 | ||
|
409aa2541d | ||
|
1a94e6033f | ||
|
9162b1af83 | ||
|
8ec45611e7 | ||
|
ce03fbcb62 | ||
|
4a22febc70 | ||
|
b720b424da | ||
|
2a2e472dc4 | ||
|
c576aa3369 | ||
|
7affeea418 | ||
|
53f24492c8 | ||
|
4fade907f3 | ||
|
3af17dff7b | ||
|
5aeee6f802 | ||
|
2632023981 | ||
|
42e1f1a308 | ||
|
6d875b7bb2 | ||
|
1ef8faecac | ||
|
0ec731507e | ||
|
1e74f6f57d | ||
|
68738e69a6 | ||
|
de53bbc13e | ||
|
b9352ef921 | ||
|
9c10fdd431 | ||
|
12bee9ca43 | ||
|
f3e998389a | ||
|
972c44894a | ||
|
8007008a78 | ||
|
6e20d52c09 | ||
|
ab84536c76 | ||
|
5764425a89 | ||
|
8d86682616 | ||
|
bb913d5809 | ||
|
55b963735a | ||
|
8c41fc086b | ||
|
df03d96800 | ||
|
9ffd4fdac8 | ||
|
0b4488b62f | ||
|
e65655594f | ||
|
514db60617 | ||
|
8bc6e75319 | ||
|
2f74cfb42c | ||
|
1302e3c959 | ||
|
a5b031f906 | ||
|
71e46c8c8e | ||
|
f583354748 | ||
|
d12e8ec923 | ||
|
89f84c9a95 | ||
|
6103a22feb | ||
|
42264f402d | ||
|
abda9bc00a | ||
|
eec639d84e | ||
|
56b9107c6b | ||
|
b35b62d59f | ||
|
1b9310e766 | ||
|
a62d8381be | ||
|
8b32e6c15a | ||
|
c8ccb2bac7 | ||
|
ef3de1050f | ||
|
2add15bd72 | ||
|
e6edd9340e | ||
|
654a7a5d03 | ||
|
dba8ab947f | ||
|
787e06e3d8 | ||
|
ccd486f2a9 | ||
|
22d078b47f | ||
|
03490d6597 | ||
|
5f46d71af0 | ||
|
4f890c431c | ||
|
c110a97d8a | ||
|
6872eb802c | ||
|
662110c269 | ||
|
5083188ed8 | ||
|
2036438203 | ||
|
476c2be5a6 | ||
|
ced66f1671 | ||
|
fb49371c6b | ||
|
fd07aa0f05 | ||
|
16518a4f89 | ||
|
bed2c29a33 | ||
|
e5b6d28bca | ||
|
1c9afcb84e | ||
|
1ebb0f8c93 | ||
|
8a13a9df80 | ||
|
ddf5f2543c | ||
|
dbb2fe3e59 | ||
|
aa1fac62d5 | ||
|
111a313d51 | ||
|
0039f893cc | ||
|
ad6b26ba97 | ||
|
1ef4044419 | ||
|
accf2565a0 | ||
|
ec965f28c0 | ||
|
ebf95f637a | ||
|
abbfd42a6c | ||
|
db4208a7eb | ||
|
da54e1d87c | ||
|
e8532ef4de | ||
|
fcc1c2968d | ||
|
b3d3b14f79 | ||
|
8939f310db | ||
|
efec752985 | ||
|
e94ad78ea7 | ||
|
a27a325af7 | ||
|
6b06d490c5 | ||
|
13f8f39dd5 | ||
|
fe05cff64f | ||
|
d86837ac07 | ||
|
9a7edc6e52 | ||
|
ce8c9dd079 | ||
|
c8f6b7e0d6 | ||
|
f284d31861 | ||
|
76b0d2d5d8 | ||
|
2cab778f19 | ||
|
b618287585 | ||
|
63f4b42453 | ||
|
c7c0df0964 | ||
|
fb87fb5750 | ||
|
634b0aaa07 | ||
|
5002a89754 | ||
|
b367490edc | ||
|
ea4c50c2c2 | ||
|
51d8044a54 | ||
|
2c96af9aea | ||
|
04c7e680fd | ||
|
a8f1160743 | ||
|
feca1f0502 | ||
|
d0a5a5ef37 | ||
|
97f570a4ee | ||
|
9ebbf7ce94 | ||
|
c2ecbf071f | ||
|
b1c489090e | ||
|
c9a03c5b01 | ||
|
517c578a5f | ||
|
f10ec3271a | ||
|
4e2820d6e3 | ||
|
72a0e081ca | ||
|
b1130cb1c3 | ||
|
59936631ec | ||
|
3af22ce754 | ||
|
5546b8ff43 | ||
|
a07092b7e6 | ||
|
ac01c62e6e | ||
|
f47f7dd9d2 | ||
|
13d970c7ce | ||
|
e2409a5fab | ||
|
9e43e03db4 | ||
|
a475cf68bf | ||
|
e889bc680b | ||
|
5c343638b6 | ||
|
0722960260 | ||
|
e959c468f6 | ||
|
ba871ec46a | ||
|
a74e04141c | ||
|
7c504a10a8 | ||
|
ae98745439 | ||
|
57259aee00 | ||
|
dc1a40ea74 | ||
|
483d9bf26c | ||
|
b24d60e98d | ||
|
0f8bd869d8 | ||
|
49546cd627 | ||
|
6e852d2e65 | ||
|
5a4f595341 |
@ -334,6 +334,11 @@ EXPORT_PAGE_SIZE=a4
|
||||
# Example: EXPORT_PDF_COMMAND="/scripts/convert.sh {input_html_path} {output_pdf_path}"
|
||||
EXPORT_PDF_COMMAND=false
|
||||
|
||||
# Export PDF Command Timeout
|
||||
# The number of seconds that the export PDF command will run before a timeout occurs.
|
||||
# Only applies for the EXPORT_PDF_COMMAND option, not for DomPDF or wkhtmltopdf.
|
||||
EXPORT_PDF_COMMAND_TIMEOUT=15
|
||||
|
||||
# Set path to wkhtmltopdf binary for PDF generation.
|
||||
# Can be 'false' or a path path like: '/home/bins/wkhtmltopdf'
|
||||
# When false, BookStack will attempt to find a wkhtmltopdf in the application
|
||||
|
4
.github/workflows/lint-js.yml
vendored
@ -13,9 +13,9 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ github.ref != 'refs/heads/l10n_development' }}
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install NPM deps
|
||||
run: npm ci
|
||||
|
29
.github/workflows/test-js.yml
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
name: test-js
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**.js'
|
||||
- '**.ts'
|
||||
- '**.json'
|
||||
pull_request:
|
||||
paths:
|
||||
- '**.js'
|
||||
- '**.ts'
|
||||
- '**.json'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
if: ${{ github.ref != 'refs/heads/l10n_development' }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install NPM deps
|
||||
run: npm ci
|
||||
|
||||
- name: Run TypeScript type checking
|
||||
run: npm run ts:lint
|
||||
|
||||
- name: Run JavaScript tests
|
||||
run: npm run test
|
1
.gitignore
vendored
@ -2,6 +2,7 @@
|
||||
/node_modules
|
||||
/.vscode
|
||||
/composer
|
||||
/coverage
|
||||
Homestead.yaml
|
||||
.env
|
||||
.idea
|
||||
|
10
app/Access/UserInviteException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Access;
|
||||
|
||||
use Exception;
|
||||
|
||||
class UserInviteException extends Exception
|
||||
{
|
||||
//
|
||||
}
|
@ -13,11 +13,17 @@ class UserInviteService extends UserTokenService
|
||||
/**
|
||||
* Send an invitation to a user to sign into BookStack
|
||||
* Removes existing invitation tokens.
|
||||
* @throws UserInviteException
|
||||
*/
|
||||
public function sendInvitation(User $user)
|
||||
{
|
||||
$this->deleteByUser($user);
|
||||
$token = $this->createTokenForUser($user);
|
||||
|
||||
try {
|
||||
$user->notify(new UserInviteNotification($token));
|
||||
} catch (\Exception $exception) {
|
||||
throw new UserInviteException($exception->getMessage(), $exception->getCode(), $exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,4 +64,14 @@ class MetaController extends Controller
|
||||
'jsLibData' => file_get_contents(base_path('dev/licensing/js-library-licenses.txt')),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the view for /opensearch.xml.
|
||||
*/
|
||||
public function opensearch()
|
||||
{
|
||||
return response()
|
||||
->view('misc.opensearch')
|
||||
->header('Content-Type', 'application/opensearchdescription+xml');
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,10 @@ return [
|
||||
// Example: EXPORT_PDF_COMMAND="/scripts/convert.sh {input_html_path} {output_pdf_path}"
|
||||
'pdf_command' => env('EXPORT_PDF_COMMAND', false),
|
||||
|
||||
// The amount of time allowed for PDF generation command to run
|
||||
// before the process times out and is stopped.
|
||||
'pdf_command_timeout' => env('EXPORT_PDF_COMMAND_TIMEOUT', 15),
|
||||
|
||||
// 2024-04: Snappy/WKHTMLtoPDF now considered deprecated in regard to BookStack support.
|
||||
'snappy' => [
|
||||
'pdf_binary' => env('WKHTMLTOPDF', false),
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace BookStack\Entities\Models;
|
||||
|
||||
use BookStack\Entities\Tools\PageContent;
|
||||
use BookStack\Entities\Tools\PageEditorType;
|
||||
use BookStack\Permissions\PermissionApplicator;
|
||||
use BookStack\Uploads\Attachment;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
@ -11,7 +11,7 @@ use BookStack\Entities\Models\PageRevision;
|
||||
use BookStack\Entities\Queries\EntityQueries;
|
||||
use BookStack\Entities\Tools\BookContents;
|
||||
use BookStack\Entities\Tools\PageContent;
|
||||
use BookStack\Entities\Tools\PageEditorData;
|
||||
use BookStack\Entities\Tools\PageEditorType;
|
||||
use BookStack\Entities\Tools\TrashCan;
|
||||
use BookStack\Exceptions\MoveOperationException;
|
||||
use BookStack\Exceptions\PermissionsException;
|
||||
@ -43,6 +43,7 @@ class PageRepo
|
||||
'owned_by' => user()->id,
|
||||
'updated_by' => user()->id,
|
||||
'draft' => true,
|
||||
'editor' => PageEditorType::getSystemDefault()->value,
|
||||
]);
|
||||
|
||||
if ($parent instanceof Chapter) {
|
||||
@ -127,7 +128,9 @@ class PageRepo
|
||||
}
|
||||
|
||||
$pageContent = new PageContent($page);
|
||||
$currentEditor = $page->editor ?: PageEditorData::getSystemDefaultEditor();
|
||||
$defaultEditor = PageEditorType::getSystemDefault();
|
||||
$currentEditor = PageEditorType::forPage($page) ?: $defaultEditor;
|
||||
$inputEditor = PageEditorType::fromRequestValue($input['editor'] ?? '') ?? $currentEditor;
|
||||
$newEditor = $currentEditor;
|
||||
|
||||
$haveInput = isset($input['markdown']) || isset($input['html']);
|
||||
@ -136,15 +139,17 @@ class PageRepo
|
||||
if ($haveInput && $inputEmpty) {
|
||||
$pageContent->setNewHTML('', user());
|
||||
} elseif (!empty($input['markdown']) && is_string($input['markdown'])) {
|
||||
$newEditor = 'markdown';
|
||||
$newEditor = PageEditorType::Markdown;
|
||||
$pageContent->setNewMarkdown($input['markdown'], user());
|
||||
} elseif (isset($input['html'])) {
|
||||
$newEditor = 'wysiwyg';
|
||||
$newEditor = ($inputEditor->isHtmlBased() ? $inputEditor : null) ?? ($defaultEditor->isHtmlBased() ? $defaultEditor : null) ?? PageEditorType::WysiwygTinymce;
|
||||
$pageContent->setNewHTML($input['html'], user());
|
||||
}
|
||||
|
||||
if ($newEditor !== $currentEditor && userCan('editor-change')) {
|
||||
$page->editor = $newEditor;
|
||||
if (($newEditor !== $currentEditor || empty($page->editor)) && userCan('editor-change')) {
|
||||
$page->editor = $newEditor->value;
|
||||
} elseif (empty($page->editor)) {
|
||||
$page->editor = $defaultEditor->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,17 +74,17 @@ class PageEditorData
|
||||
];
|
||||
}
|
||||
|
||||
protected function updateContentForEditor(Page $page, string $editorType): void
|
||||
protected function updateContentForEditor(Page $page, PageEditorType $editorType): void
|
||||
{
|
||||
$isHtml = !empty($page->html) && empty($page->markdown);
|
||||
|
||||
// HTML to markdown-clean conversion
|
||||
if ($editorType === 'markdown' && $isHtml && $this->requestedEditor === 'markdown-clean') {
|
||||
if ($editorType === PageEditorType::Markdown && $isHtml && $this->requestedEditor === 'markdown-clean') {
|
||||
$page->markdown = (new HtmlToMarkdown($page->html))->convert();
|
||||
}
|
||||
|
||||
// Markdown to HTML conversion if we don't have HTML
|
||||
if ($editorType === 'wysiwyg' && !$isHtml) {
|
||||
if ($editorType->isHtmlBased() && !$isHtml) {
|
||||
$page->html = (new MarkdownToHtml($page->markdown))->convert();
|
||||
}
|
||||
}
|
||||
@ -94,24 +94,16 @@ class PageEditorData
|
||||
* Defaults based upon the current content of the page otherwise will fall back
|
||||
* to system default but will take a requested type (if provided) if permissions allow.
|
||||
*/
|
||||
protected function getEditorType(Page $page): string
|
||||
protected function getEditorType(Page $page): PageEditorType
|
||||
{
|
||||
$editorType = $page->editor ?: self::getSystemDefaultEditor();
|
||||
$editorType = PageEditorType::forPage($page) ?: PageEditorType::getSystemDefault();
|
||||
|
||||
// Use requested editor if valid and if we have permission
|
||||
$requestedType = explode('-', $this->requestedEditor)[0];
|
||||
if (($requestedType === 'markdown' || $requestedType === 'wysiwyg') && userCan('editor-change')) {
|
||||
$requestedType = PageEditorType::fromRequestValue($this->requestedEditor);
|
||||
if ($requestedType && userCan('editor-change')) {
|
||||
$editorType = $requestedType;
|
||||
}
|
||||
|
||||
return $editorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured system default editor.
|
||||
*/
|
||||
public static function getSystemDefaultEditor(): string
|
||||
{
|
||||
return setting('app-editor') === 'markdown' ? 'markdown' : 'wysiwyg';
|
||||
}
|
||||
}
|
||||
|
37
app/Entities/Tools/PageEditorType.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace BookStack\Entities\Tools;
|
||||
|
||||
use BookStack\Entities\Models\Page;
|
||||
|
||||
enum PageEditorType: string
|
||||
{
|
||||
case WysiwygTinymce = 'wysiwyg';
|
||||
case WysiwygLexical = 'wysiwyg2024';
|
||||
case Markdown = 'markdown';
|
||||
|
||||
public function isHtmlBased(): bool
|
||||
{
|
||||
return match ($this) {
|
||||
self::WysiwygTinymce, self::WysiwygLexical => true,
|
||||
self::Markdown => false,
|
||||
};
|
||||
}
|
||||
|
||||
public static function fromRequestValue(string $value): static|null
|
||||
{
|
||||
$editor = explode('-', $value)[0];
|
||||
return static::tryFrom($editor);
|
||||
}
|
||||
|
||||
public static function forPage(Page $page): static|null
|
||||
{
|
||||
return static::tryFrom($page->editor);
|
||||
}
|
||||
|
||||
public static function getSystemDefault(): static
|
||||
{
|
||||
$setting = setting('app-editor');
|
||||
return static::tryFrom($setting) ?? static::WysiwygTinymce;
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ namespace BookStack\Entities\Tools;
|
||||
use BookStack\Exceptions\PdfExportException;
|
||||
use Knp\Snappy\Pdf as SnappyPdf;
|
||||
use Dompdf\Dompdf;
|
||||
use Symfony\Component\Process\Exception\ProcessTimedOutException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class PdfGenerator
|
||||
@ -85,9 +86,15 @@ class PdfGenerator
|
||||
|
||||
file_put_contents($inputHtml, $html);
|
||||
|
||||
$timeout = intval(config('exports.pdf_command_timeout'));
|
||||
$process = Process::fromShellCommandline($command);
|
||||
$process->setTimeout(15);
|
||||
$process->setTimeout($timeout);
|
||||
|
||||
try {
|
||||
$process->run();
|
||||
} catch (ProcessTimedOutException $e) {
|
||||
throw new PdfExportException("PDF Export via command failed due to timeout at {$timeout} second(s)");
|
||||
}
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
throw new PdfExportException("PDF Export via command failed with exit code {$process->getExitCode()}, stdout: {$process->getOutput()}, stderr: {$process->getErrorOutput()}");
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace BookStack\Users\Controllers;
|
||||
|
||||
use BookStack\Access\SocialDriverManager;
|
||||
use BookStack\Access\UserInviteException;
|
||||
use BookStack\Exceptions\ImageUploadException;
|
||||
use BookStack\Exceptions\UserUpdateException;
|
||||
use BookStack\Http\Controller;
|
||||
@ -14,6 +15,7 @@ use BookStack\Util\SimpleListOptions;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Rules\Password;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
@ -91,9 +93,15 @@ class UserController extends Controller
|
||||
|
||||
$validated = $this->validate($request, array_filter($validationRules));
|
||||
|
||||
try {
|
||||
DB::transaction(function () use ($validated, $sendInvite) {
|
||||
$this->userRepo->create($validated, $sendInvite);
|
||||
});
|
||||
} catch (UserInviteException $e) {
|
||||
Log::error("Failed to send user invite with error: {$e->getMessage()}");
|
||||
$this->showErrorNotification(trans('errors.users_could_not_send_invite'));
|
||||
return redirect('/settings/users/create')->withInput();
|
||||
}
|
||||
|
||||
return redirect('/settings/users');
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace BookStack\Users;
|
||||
|
||||
use BookStack\Access\UserInviteException;
|
||||
use BookStack\Access\UserInviteService;
|
||||
use BookStack\Activity\ActivityType;
|
||||
use BookStack\Entities\EntityProvider;
|
||||
@ -83,6 +84,7 @@ class UserRepo
|
||||
* As per "createWithoutActivity" but records a "create" activity.
|
||||
*
|
||||
* @param array{name: string, email: string, password: ?string, external_auth_id: ?string, language: ?string, roles: ?array} $data
|
||||
* @throws UserInviteException
|
||||
*/
|
||||
public function create(array $data, bool $sendInvite = false): User
|
||||
{
|
||||
|
@ -16,9 +16,9 @@
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"bacon/bacon-qr-code": "^3.0",
|
||||
"doctrine/dbal": "^3.5",
|
||||
"dompdf/dompdf": "^2.0",
|
||||
"dompdf/dompdf": "^3.0",
|
||||
"guzzlehttp/guzzle": "^7.4",
|
||||
"intervention/image": "^3.5",
|
||||
"knplabs/knp-snappy": "^1.5",
|
||||
|
801
composer.lock
generated
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// Ensure we have an "editor" value set for pages
|
||||
|
||||
// Get default
|
||||
$default = DB::table('settings')
|
||||
->where('setting_key', '=', 'app-editor')
|
||||
->first()
|
||||
->value ?? 'wysiwyg';
|
||||
$default = ($default === 'markdown') ? 'markdown' : 'wysiwyg';
|
||||
|
||||
// We set it to 'markdown' for pages currently with markdown content
|
||||
DB::table('pages')
|
||||
->where('editor', '=', '')
|
||||
->where('markdown', '!=', '')
|
||||
->update(['editor' => 'markdown']);
|
||||
|
||||
// We set it to 'wysiwyg' where we have HTML but no markdown
|
||||
DB::table('pages')
|
||||
->where('editor', '=', '')
|
||||
->where('markdown', '=', '')
|
||||
->where('html', '!=', '')
|
||||
->update(['editor' => 'wysiwyg']);
|
||||
|
||||
// Otherwise, where still empty, set to the current default
|
||||
DB::table('pages')
|
||||
->where('editor', '=', '')
|
||||
->update(['editor' => $default]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// Can't reverse due to not knowing what would have been empty before
|
||||
}
|
||||
};
|
@ -14,6 +14,7 @@ const entryPoints = {
|
||||
code: path.join(__dirname, '../../resources/js/code/index.mjs'),
|
||||
'legacy-modes': path.join(__dirname, '../../resources/js/code/legacy-modes.mjs'),
|
||||
markdown: path.join(__dirname, '../../resources/js/markdown/index.mjs'),
|
||||
wysiwyg: path.join(__dirname, '../../resources/js/wysiwyg/index.ts'),
|
||||
};
|
||||
|
||||
// Locate our output directory
|
||||
@ -31,6 +32,15 @@ esbuild.build({
|
||||
format: 'esm',
|
||||
minify: isProd,
|
||||
logLevel: 'info',
|
||||
loader: {
|
||||
'.svg': 'text',
|
||||
},
|
||||
absWorkingDir: path.join(__dirname, '../..'),
|
||||
alias: {
|
||||
'@icons': './resources/icons',
|
||||
lexical: './resources/js/wysiwyg/lexical/core',
|
||||
'@lexical': './resources/js/wysiwyg/lexical',
|
||||
},
|
||||
banner: {
|
||||
js: '// See the "/licenses" URI for full package license details',
|
||||
css: '/* See the "/licenses" URI for full package license details */',
|
||||
|
@ -128,7 +128,7 @@ Link: https://github.com/fruitcake/php-cors
|
||||
graham-campbell/result-type
|
||||
License: MIT
|
||||
License File: vendor/graham-campbell/result-type/LICENSE
|
||||
Copyright: Copyright (c) 2020-2023 Graham Campbell <*****@**********.**.**>
|
||||
Copyright: Copyright (c) 2020-2024 Graham Campbell <*****@**********.**.**>
|
||||
Source: https://github.com/GrahamCampbell/Result-Type.git
|
||||
Link: https://github.com/GrahamCampbell/Result-Type.git
|
||||
-----------
|
||||
@ -676,13 +676,6 @@ Copyright: Copyright (c) 2015-present Fabien Potencier
|
||||
Source: https://github.com/symfony/polyfill-mbstring.git
|
||||
Link: https://symfony.com
|
||||
-----------
|
||||
symfony/polyfill-php72
|
||||
License: MIT
|
||||
License File: vendor/symfony/polyfill-php72/LICENSE
|
||||
Copyright: Copyright (c) 2015-present Fabien Potencier
|
||||
Source: https://github.com/symfony/polyfill-php72.git
|
||||
Link: https://symfony.com
|
||||
-----------
|
||||
symfony/polyfill-php80
|
||||
License: MIT
|
||||
License File: vendor/symfony/polyfill-php80/LICENSE
|
||||
|
209
jest.config.ts
Normal file
@ -0,0 +1,209 @@
|
||||
/**
|
||||
* For a detailed explanation regarding each configuration property, visit:
|
||||
* https://jestjs.io/docs/configuration
|
||||
*/
|
||||
|
||||
import type {Config} from 'jest';
|
||||
import {pathsToModuleNameMapper} from "ts-jest";
|
||||
import { compilerOptions } from './tsconfig.json';
|
||||
|
||||
const config: Config = {
|
||||
// All imported modules in your tests should be mocked automatically
|
||||
// automock: false,
|
||||
|
||||
// Stop running tests after `n` failures
|
||||
// bail: 0,
|
||||
|
||||
// The directory where Jest should store its cached dependency information
|
||||
// cacheDirectory: "/tmp/jest_rs",
|
||||
|
||||
// Automatically clear mock calls, instances, contexts and results before every test
|
||||
clearMocks: true,
|
||||
|
||||
// Indicates whether the coverage information should be collected while executing the test
|
||||
collectCoverage: false,
|
||||
|
||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||
// collectCoverageFrom: undefined,
|
||||
|
||||
// The directory where Jest should output its coverage files
|
||||
coverageDirectory: "coverage",
|
||||
|
||||
// An array of regexp pattern strings used to skip coverage collection
|
||||
// coveragePathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// Indicates which provider should be used to instrument code for coverage
|
||||
coverageProvider: "v8",
|
||||
|
||||
// A list of reporter names that Jest uses when writing coverage reports
|
||||
// coverageReporters: [
|
||||
// "json",
|
||||
// "text",
|
||||
// "lcov",
|
||||
// "clover"
|
||||
// ],
|
||||
|
||||
// An object that configures minimum threshold enforcement for coverage results
|
||||
// coverageThreshold: undefined,
|
||||
|
||||
// A path to a custom dependency extractor
|
||||
// dependencyExtractor: undefined,
|
||||
|
||||
// Make calling deprecated APIs throw helpful error messages
|
||||
// errorOnDeprecated: false,
|
||||
|
||||
// The default configuration for fake timers
|
||||
// fakeTimers: {
|
||||
// "enableGlobally": false
|
||||
// },
|
||||
|
||||
// Force coverage collection from ignored files using an array of glob patterns
|
||||
// forceCoverageMatch: [],
|
||||
|
||||
// A path to a module which exports an async function that is triggered once before all test suites
|
||||
// globalSetup: undefined,
|
||||
|
||||
// A path to a module which exports an async function that is triggered once after all test suites
|
||||
// globalTeardown: undefined,
|
||||
|
||||
// A set of global variables that need to be available in all test environments
|
||||
globals: {
|
||||
__DEV__: true,
|
||||
},
|
||||
|
||||
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
||||
// maxWorkers: "50%",
|
||||
|
||||
// An array of directory names to be searched recursively up from the requiring module's location
|
||||
// moduleDirectories: [
|
||||
// "node_modules"
|
||||
// ],
|
||||
|
||||
// An array of file extensions your modules use
|
||||
// moduleFileExtensions: [
|
||||
// "js",
|
||||
// "mjs",
|
||||
// "cjs",
|
||||
// "jsx",
|
||||
// "ts",
|
||||
// "tsx",
|
||||
// "json",
|
||||
// "node"
|
||||
// ],
|
||||
|
||||
modulePaths: ['./'],
|
||||
|
||||
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
||||
moduleNameMapper: {
|
||||
'lexical/shared/invariant': 'resources/js/wysiwyg/lexical/core/shared/__mocks__/invariant',
|
||||
...pathsToModuleNameMapper(compilerOptions.paths),
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||
// modulePathIgnorePatterns: [],
|
||||
|
||||
// Activates notifications for test results
|
||||
// notify: false,
|
||||
|
||||
// An enum that specifies notification mode. Requires { notify: true }
|
||||
// notifyMode: "failure-change",
|
||||
|
||||
// A preset that is used as a base for Jest's configuration
|
||||
// preset: undefined,
|
||||
|
||||
// Run tests from one or more projects
|
||||
// projects: undefined,
|
||||
|
||||
// Use this configuration option to add custom reporters to Jest
|
||||
// reporters: undefined,
|
||||
|
||||
// Automatically reset mock state before every test
|
||||
// resetMocks: false,
|
||||
|
||||
// Reset the module registry before running each individual test
|
||||
// resetModules: false,
|
||||
|
||||
// A path to a custom resolver
|
||||
// resolver: undefined,
|
||||
|
||||
// Automatically restore mock state and implementation before every test
|
||||
// restoreMocks: false,
|
||||
|
||||
// The root directory that Jest should scan for tests and modules within
|
||||
// rootDir: undefined,
|
||||
|
||||
// A list of paths to directories that Jest should use to search for files in
|
||||
roots: [
|
||||
"./resources/js"
|
||||
],
|
||||
|
||||
// Allows you to use a custom runner instead of Jest's default test runner
|
||||
// runner: "jest-runner",
|
||||
|
||||
// The paths to modules that run some code to configure or set up the testing environment before each test
|
||||
// setupFiles: [],
|
||||
|
||||
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||
// setupFilesAfterEnv: [],
|
||||
|
||||
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||
// slowTestThreshold: 5,
|
||||
|
||||
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
||||
// snapshotSerializers: [],
|
||||
|
||||
// The test environment that will be used for testing
|
||||
testEnvironment: "jsdom",
|
||||
|
||||
// Options that will be passed to the testEnvironment
|
||||
// testEnvironmentOptions: {},
|
||||
|
||||
// Adds a location field to test results
|
||||
// testLocationInResults: false,
|
||||
|
||||
// The glob patterns Jest uses to detect test files
|
||||
testMatch: [
|
||||
"**/__tests__/**/*.test.[jt]s",
|
||||
],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||
// testPathIgnorePatterns: [
|
||||
// "/node_modules/"
|
||||
// ],
|
||||
|
||||
// The regexp pattern or array of patterns that Jest uses to detect test files
|
||||
// testRegex: [],
|
||||
|
||||
// This option allows the use of a custom results processor
|
||||
// testResultsProcessor: undefined,
|
||||
|
||||
// This option allows use of a custom test runner
|
||||
// testRunner: "jest-circus/runner",
|
||||
|
||||
// A map from regular expressions to paths to transformers
|
||||
transform: {
|
||||
"^.+.tsx?$": ["ts-jest",{}],
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||
// transformIgnorePatterns: [
|
||||
// "/node_modules/",
|
||||
// "\\.pnp\\.[^\\/]+$"
|
||||
// ],
|
||||
|
||||
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||
// unmockedModulePathPatterns: undefined,
|
||||
|
||||
// Indicates whether each individual test should be reported during the run
|
||||
// verbose: undefined,
|
||||
|
||||
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
||||
// watchPathIgnorePatterns: [],
|
||||
|
||||
// Whether to use watchman for file crawling
|
||||
// watchman: true,
|
||||
};
|
||||
|
||||
export default config;
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'سياسة الخصوصية',
|
||||
'terms_of_service' => 'اتفاقية شروط الخدمة',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Политика за поверителност',
|
||||
'terms_of_service' => 'Условия на услугата',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Pravila o privatnosti',
|
||||
'terms_of_service' => 'Uslovi korištenja',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Política de privadesa',
|
||||
'terms_of_service' => 'Condicions del servei',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Zásady ochrany osobních údajů',
|
||||
'terms_of_service' => 'Podmínky služby',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Polisi Preifatrwydd',
|
||||
'terms_of_service' => 'Telerau Gwasanaeth',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -65,7 +65,7 @@ return [
|
||||
'auth_login' => 'loggede ind',
|
||||
'auth_register' => 'registered as new user',
|
||||
'auth_password_reset_request' => 'requested user password reset',
|
||||
'auth_password_reset_update' => 'reset user password',
|
||||
'auth_password_reset_update' => 'nulstil adgangskode',
|
||||
'mfa_setup_method' => 'configured MFA method',
|
||||
'mfa_setup_method_notification' => 'Multi-faktor metode konfigureret',
|
||||
'mfa_remove_method' => 'removed MFA method',
|
||||
@ -85,8 +85,8 @@ return [
|
||||
'webhook_delete_notification' => 'Webhooken blev slettet',
|
||||
|
||||
// Users
|
||||
'user_create' => 'created user',
|
||||
'user_create_notification' => 'User successfully created',
|
||||
'user_create' => 'opret bruger',
|
||||
'user_create_notification' => 'Bruger oprettet korrekt',
|
||||
'user_update' => 'updated user',
|
||||
'user_update_notification' => 'Brugeren blev opdateret',
|
||||
'user_delete' => 'deleted user',
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privatlivspolitik',
|
||||
'terms_of_service' => 'Tjenestevilkår',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Datenschutzbestimmungen',
|
||||
'terms_of_service' => 'Allgemeine Geschäftsbedingungen',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Datenschutzerklärung',
|
||||
'terms_of_service' => 'Allgemeine Geschäftsbedingungen',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Πολιτική Απορρήτου',
|
||||
'terms_of_service' => 'Όροι χρήσης',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privacy Policy',
|
||||
'terms_of_service' => 'Terms of Service',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -224,6 +224,8 @@ return [
|
||||
'pages_edit_switch_to_markdown_clean' => '(Clean Content)',
|
||||
'pages_edit_switch_to_markdown_stable' => '(Stable Content)',
|
||||
'pages_edit_switch_to_wysiwyg' => 'Switch to WYSIWYG Editor',
|
||||
'pages_edit_switch_to_new_wysiwyg' => 'Switch to new WYSIWYG',
|
||||
'pages_edit_switch_to_new_wysiwyg_desc' => '(In Alpha Testing)',
|
||||
'pages_edit_set_changelog' => 'Set Changelog',
|
||||
'pages_edit_enter_changelog_desc' => 'Enter a brief description of the changes you\'ve made',
|
||||
'pages_edit_enter_changelog' => 'Enter Changelog',
|
||||
|
@ -78,6 +78,7 @@ return [
|
||||
// Users
|
||||
'users_cannot_delete_only_admin' => 'You cannot delete the only admin',
|
||||
'users_cannot_delete_guest' => 'You cannot delete the guest user',
|
||||
'users_could_not_send_invite' => 'Could not create user since invite email failed to send',
|
||||
|
||||
// Roles
|
||||
'role_cannot_be_edited' => 'This role cannot be edited',
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Política de privacidad',
|
||||
'terms_of_service' => 'Términos de Servicio',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Buscar :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Política de privacidad',
|
||||
'terms_of_service' => 'Términos de Servicio',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privaatsus',
|
||||
'terms_of_service' => 'Kasutustingimused',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Pribatutasun politika',
|
||||
'terms_of_service' => 'Zerbitzu-baldintzak',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'سیاست حفظ حریم خصوصی',
|
||||
'terms_of_service' => 'شرایط خدمات',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Tietosuojaseloste',
|
||||
'terms_of_service' => 'Palvelun käyttöehdot',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Politique de confidentialité',
|
||||
'terms_of_service' => 'Conditions d\'utilisation',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'מדיניות הפרטיות',
|
||||
'terms_of_service' => 'תנאי שימוש',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Politika privatnosti',
|
||||
'terms_of_service' => 'Uvjeti korištenja',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Adatvédelmi irányelvek',
|
||||
'terms_of_service' => 'Felhasználási feltételek',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Kebijakan Privasi',
|
||||
'terms_of_service' => 'Ketentuan Layanan',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Norme sulla privacy',
|
||||
'terms_of_service' => 'Condizioni del Servizio',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'プライバシーポリシー',
|
||||
'terms_of_service' => '利用規約',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privacy Policy',
|
||||
'terms_of_service' => 'Terms of Service',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => '개인 정보 처리 방침',
|
||||
'terms_of_service' => '서비스 이용 약관',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privatumo politika',
|
||||
'terms_of_service' => 'Paslaugų teikimo paslaugos',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privātuma politika',
|
||||
'terms_of_service' => 'Pakalpojuma noteikumi',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Personvernregler',
|
||||
'terms_of_service' => 'Bruksvilkår',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privacybeleid',
|
||||
'terms_of_service' => 'Algemene voorwaarden',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Personvernreglar',
|
||||
'terms_of_service' => 'Bruksvilkår',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Polityka prywatności',
|
||||
'terms_of_service' => 'Warunki usługi',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Política de Privacidade',
|
||||
'terms_of_service' => 'Termos de Utilização',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Políticas de Privacidade',
|
||||
'terms_of_service' => 'Termos de Serviço',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Politică de confidențialitate',
|
||||
'terms_of_service' => 'Termeni și condiții',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Политика конфиденциальности',
|
||||
'terms_of_service' => 'Условия использования',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Zásady ochrany osobných údajov',
|
||||
'terms_of_service' => 'Podmienky používania',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Pravilnik o zasebnosti',
|
||||
'terms_of_service' => 'Pogoji uporabe',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Privacy Policy',
|
||||
'terms_of_service' => 'Terms of Service',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Правила о приватности',
|
||||
'terms_of_service' => 'Услови коришћења',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Integritetspolicy',
|
||||
'terms_of_service' => 'Användarvillkor',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Gizlilik Politikası',
|
||||
'terms_of_service' => 'Hizmet Şartları',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Політика приватності',
|
||||
'terms_of_service' => 'Умови використання',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Maxfiylik siyosati',
|
||||
'terms_of_service' => 'Xizmat ko‘rsatish shartlari',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => 'Chính Sách Quyền Riêng Tư',
|
||||
'terms_of_service' => 'Điều khoản Dịch vụ',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => '隐私政策',
|
||||
'terms_of_service' => '服务条款',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
@ -107,4 +107,7 @@ return [
|
||||
// Not directly used but available for convenience to users.
|
||||
'privacy_policy' => '隱私權政策',
|
||||
'terms_of_service' => '服務條款',
|
||||
|
||||
// OpenSearch
|
||||
'opensearch_description' => 'Search :appName',
|
||||
];
|
||||
|
4014
package-lock.json
generated
17
package.json
@ -5,7 +5,7 @@
|
||||
"build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources",
|
||||
"build:css:production": "sass ./resources/sass:./public/dist -s compressed",
|
||||
"build:js:dev": "node dev/build/esbuild.js",
|
||||
"build:js:watch": "chokidar --initial \"./resources/**/*.js\" \"./resources/**/*.mjs\" -c \"npm run build:js:dev\"",
|
||||
"build:js:watch": "chokidar --initial \"./resources/**/*.js\" \"./resources/**/*.mjs\" \"./resources/**/*.ts\" -c \"npm run build:js:dev\"",
|
||||
"build:js:production": "node dev/build/esbuild.js production",
|
||||
"build": "npm-run-all --parallel build:*:dev",
|
||||
"production": "npm-run-all --parallel build:*:production",
|
||||
@ -14,7 +14,9 @@
|
||||
"livereload": "livereload ./public/dist/",
|
||||
"permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads",
|
||||
"lint": "eslint \"resources/**/*.js\" \"resources/**/*.mjs\"",
|
||||
"fix": "eslint --fix \"resources/**/*.js\" \"resources/**/*.mjs\""
|
||||
"fix": "eslint --fix \"resources/**/*.js\" \"resources/**/*.mjs\"",
|
||||
"ts:lint": "tsc --noEmit",
|
||||
"test": "jest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lezer/generator": "^1.5.1",
|
||||
@ -23,9 +25,14 @@
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"livereload": "^0.9.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"sass": "^1.69.5"
|
||||
"sass": "^1.69.5",
|
||||
"ts-jest": "^29.2.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "5.6.*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "^6.3.2",
|
||||
@ -44,6 +51,7 @@
|
||||
"@lezer/highlight": "^1.2.0",
|
||||
"@ssddanbrown/codemirror-lang-smarty": "^1.0.0",
|
||||
"@ssddanbrown/codemirror-lang-twig": "^1.0.0",
|
||||
"@types/jest": "^29.5.13",
|
||||
"codemirror": "^6.0.1",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"markdown-it": "^14.1.0",
|
||||
@ -59,7 +67,8 @@
|
||||
},
|
||||
"extends": "airbnb-base",
|
||||
"ignorePatterns": [
|
||||
"resources/**/*-stub.js"
|
||||
"resources/**/*-stub.js",
|
||||
"resources/**/*.ts"
|
||||
],
|
||||
"overrides": [],
|
||||
"parserOptions": {
|
||||
|
@ -152,6 +152,7 @@ Note: This is not an exhaustive list of all libraries and projects that would be
|
||||
|
||||
* [Laravel](http://laravel.com/) - _[MIT](https://github.com/laravel/framework/blob/v8.82.0/LICENSE.md)_
|
||||
* [TinyMCE](https://www.tinymce.com/) - _[MIT](https://github.com/tinymce/tinymce/blob/develop/LICENSE.TXT)_
|
||||
* [Lexical](https://lexical.dev/) - _[MIT](https://github.com/facebook/lexical/blob/main/LICENSE)_
|
||||
* [CodeMirror](https://codemirror.net) - _[MIT](https://github.com/codemirror/CodeMirror/blob/master/LICENSE)_
|
||||
* [Sortable](https://github.com/SortableJS/Sortable) - _[MIT](https://github.com/SortableJS/Sortable/blob/master/LICENSE)_
|
||||
* [Google Material Icons](https://github.com/google/material-design-icons) - _[Apache-2.0](https://github.com/google/material-design-icons/blob/master/LICENSE)_
|
||||
|
1
resources/icons/caret-down-large.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m2 6.9159 10 10.168 10-10.168z" stroke-width="2.0168"/></svg>
|
After Width: | Height: | Size: 131 B |
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/><path fill="none" d="M0 0h24v24H0z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
|
Before Width: | Height: | Size: 216 B After Width: | Height: | Size: 179 B |
1
resources/icons/editor/align-center.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm160-160v-80h400v80H280ZM120-440v-80h720v80H120Zm160-160v-80h400v80H280ZM120-760v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 203 B |
1
resources/icons/editor/align-justify.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Zm0-160v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 195 B |
1
resources/icons/editor/align-left.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Zm0-160v-80h480v80H120Zm0-160v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 195 B |
1
resources/icons/editor/align-right.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-760v-80h720v80H120Zm240 160v-80h480v80H360ZM120-440v-80h720v80H120Zm240 160v-80h480v80H360ZM120-120v-80h720v80H120Z"/></svg>
|
After Width: | Height: | Size: 203 B |
1
resources/icons/editor/bold.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M272-200v-560h221q65 0 120 40t55 111q0 51-23 78.5T602-491q25 11 55.5 41t30.5 90q0 89-65 124.5T501-200H272Zm121-112h104q48 0 58.5-24.5T566-372q0-11-10.5-35.5T494-432H393v120Zm0-228h93q33 0 48-17t15-38q0-24-17-39t-44-15h-95v109Z"/></svg>
|
After Width: | Height: | Size: 309 B |
1
resources/icons/editor/code-block.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m384-336 56-57-87-87 87-87-56-57-144 144 144 144Zm192 0 144-144-144-144-56 57 87 87-87 87 56 57ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Zm0-560v560-560Z"/></svg>
|
After Width: | Height: | Size: 336 B |
1
resources/icons/editor/code.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>
|
After Width: | Height: | Size: 186 B |
1
resources/icons/editor/color-clear.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M800-436q0 36-8 69t-22 63l-62-60q6-17 9-34.5t3-37.5q0-47-17.5-89T650-600L480-768l-88 86-56-56 144-142 226 222q44 42 69 99.5T800-436Zm-8 380L668-180q-41 29-88 44.5T480-120q-133 0-226.5-92.5T160-436q0-51 16-98t48-90L56-792l56-56 736 736-56 56ZM480-200q36 0 68.5-10t61.5-28L280-566q-21 32-30.5 64t-9.5 66q0 98 70 167t170 69Zm-37-204Zm110-116Z"/></svg>
|
After Width: | Height: | Size: 422 B |
1
resources/icons/editor/details.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-480H200v480Zm80-280v-80h400v80H280Zm0 160v-80h240v80H280Z"/></svg>
|
After Width: | Height: | Size: 270 B |
1
resources/icons/editor/diagram.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M480-60q-63 0-106.5-43.5T330-210q0-52 31-91.5t79-53.5v-85H200v-160H100v-280h280v280H280v80h400v-85q-48-14-79-53.5T570-750q0-63 43.5-106.5T720-900q63 0 106.5 43.5T870-750q0 52-31 91.5T760-605v165H520v85q48 14 79 53.5t31 91.5q0 63-43.5 106.5T480-60Zm240-620q29 0 49.5-20.5T790-750q0-29-20.5-49.5T720-820q-29 0-49.5 20.5T650-750q0 29 20.5 49.5T720-680Zm-540 0h120v-120H180v120Zm300 540q29 0 49.5-20.5T550-210q0-29-20.5-49.5T480-280q-29 0-49.5 20.5T410-210q0 29 20.5 49.5T480-140ZM240-740Zm480-10ZM480-210Z"/></svg>
|
After Width: | Height: | Size: 585 B |
1
resources/icons/editor/direction-ltr.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M440-800v400q0 17-11.5 28.5T400-360q-17 0-28.5-11.5T360-400v-160q-66 0-113-47t-47-113q0-66 47-113t113-47h280q17 0 28.5 11.5T680-840q0 17-11.5 28.5T640-800h-40v400q0 17-11.5 28.5T560-360q-17 0-28.5-11.5T520-400v-400h-80Zm-80 160v-160q-33 0-56.5 23.5T280-720q0 33 23.5 56.5T360-640Zm0-80Zm328 520H160q-17 0-28.5-11.5T120-240q0-17 11.5-28.5T160-280h528l-36-36q-11-11-11-28t11-28q11-11 28-11t28 11l104 104q12 12 12 28t-12 28L708-108q-11 11-28 11t-28-11q-11-11-11-28t11-28l36-36Z"/></svg>
|
After Width: | Height: | Size: 557 B |
1
resources/icons/editor/direction-rtl.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M440-800v400q0 17-11.5 28.5T400-360q-17 0-28.5-11.5T360-400v-160q-66 0-113-47t-47-113q0-66 47-113t113-47h280q17 0 28.5 11.5T680-840q0 17-11.5 28.5T640-800h-40v400q0 17-11.5 28.5T560-360q-17 0-28.5-11.5T520-400v-400h-80ZM272-200l36 36q11 11 11 28t-11 28q-11 11-28 11t-28-11L148-212q-12-12-12-28t12-28l104-104q11-11 28-11t28 11q11 11 11 28t-11 28l-36 36h528q17 0 28.5 11.5T840-240q0 17-11.5 28.5T800-200H272Zm88-440v-160q-33 0-56.5 23.5T280-720q0 33 23.5 56.5T360-640Zm0-80Z"/></svg>
|
After Width: | Height: | Size: 555 B |
1
resources/icons/editor/format-clear.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="m528-546-93-93-121-121h486v120H568l-40 94ZM792-56 460-388l-80 188H249l119-280L56-792l56-56 736 736-56 56Z"/></svg>
|
After Width: | Height: | Size: 188 B |
1
resources/icons/editor/fullscreen.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-200h80v120h120v80H120Zm520 0v-80h120v-120h80v200H640ZM120-640v-200h200v80H200v120h-80Zm640 0v-120H640v-80h200v200h-80Z"/></svg>
|
After Width: | Height: | Size: 211 B |
1
resources/icons/editor/help.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>
|
After Width: | Height: | Size: 653 B |
1
resources/icons/editor/highlighter.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg version="1.1" viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"><path class="editor-icon-color-bar" d="m80-2e-6v-160h800v160z"/><path d="m584-480-104-104-160 160 103 104zm-47-160 103 103 160-159-104-104zm-84-29 216 216-189 190c-16 16-34.833 24-56.5 24s-40.5-8-56.5-24l-27 23h-200l126-125c-16-16-24.333-35.167-25-57.5s7-41.5 23-57.5zm0 0 187-187c16-16 34.833-24 56.5-24s40.5 8 56.5 24l104 103c16 16 24 34.833 24 56.5s-8 40.5-24 56.5l-188 187z"/></svg>
|
After Width: | Height: | Size: 465 B |
1
resources/icons/editor/horizontal-rule.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M160-440v-80h640v80H160Z"/></svg>
|
After Width: | Height: | Size: 107 B |
1
resources/icons/editor/image-search.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h200v80H200v560h560v-214l80 80v134q0 33-23.5 56.5T760-120H200Zm40-160 120-160 90 120 120-160 150 200H240Zm622-144L738-548q-21 14-45 21t-51 7q-74 0-126-52.5T464-700q0-75 52.5-127.5T644-880q75 0 127.5 52.5T824-700q0 27-8 52t-20 46l122 122-56 56ZM644-600q42 0 71-29t29-71q0-42-29-71t-71-29q-42 0-71 29t-29 71q0 42 29 71t71 29Z"/></svg>
|
After Width: | Height: | Size: 466 B |
1
resources/icons/editor/image.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h360v80H200v560h560v-360h80v360q0 33-23.5 56.5T760-120H200Zm480-480v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM240-280h480L570-480 450-320l-90-120-120 160Zm-40-480v560-560Z"/></svg>
|
After Width: | Height: | Size: 315 B |
1
resources/icons/editor/indent-decrease.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm160 440L120-480l160-160v320Z"/></svg>
|
After Width: | Height: | Size: 228 B |
1
resources/icons/editor/indent-increase.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M120-120v-80h720v80H120Zm320-160v-80h400v80H440Zm0-160v-80h400v80H440Zm0-160v-80h400v80H440ZM120-760v-80h720v80H120Zm0 440v-320l160 160-160 160Z"/></svg>
|
After Width: | Height: | Size: 227 B |
1
resources/icons/editor/italic.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M200-200v-100h160l120-360H320v-100h400v100H580L460-300h140v100H200Z"/></svg>
|
After Width: | Height: | Size: 150 B |
1
resources/icons/editor/link.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path d="M680-160v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM440-280H280q-83 0-141.5-58.5T80-480q0-83 58.5-141.5T280-680h160v80H280q-50 0-85 35t-35 85q0 50 35 85t85 35h160v80ZM320-440v-80h320v80H320Zm560-40h-80q0-50-35-85t-85-35H520v-80h160q83 0 141.5 58.5T880-480Z"/></svg>
|
After Width: | Height: | Size: 345 B |