Compare commits
14
Commits
53bae19d3e
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
820450c48c
|
||
|
|
3a7c747ac4
|
||
|
|
02bcac7889
|
||
|
|
6831592661
|
||
|
|
d3a84bad04
|
||
|
|
756cafdbff
|
||
|
|
9356b06ef5
|
||
|
|
b5258f840e
|
||
|
|
b35f04d220
|
||
|
|
859187bafa
|
||
|
|
9e6e699db0
|
||
|
|
993350073c
|
||
|
|
9a6604a40b
|
||
|
|
85a4361d0c
|
+1
-1
@@ -1,4 +1,4 @@
|
||||
DOCKER_APP_PORT=8080
|
||||
DOCKER_WEB_PORT=8080
|
||||
DOCKER_CAPTCHA_PORT=8081
|
||||
DOCKER_CAPTCHA_WEBSOCKET_PORT=8082
|
||||
DOCKER_DB_PORT=3306
|
||||
|
||||
+11
-5
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\DocumentationCategories\CreateRequest;
|
||||
use App\Http\Requests\Admin\Projects\DocumentationCategories\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\DocumentationCategories\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationCategoryService;
|
||||
@@ -32,18 +33,23 @@ final class DocumentationCategoriesController extends Controller
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/index', $result->getData());
|
||||
return view('admin/projects/documentation-versions/documentation-categories/index', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, Request $request): View
|
||||
public function create(int $projectId, int $versionId, CreateRequest $request): View
|
||||
{
|
||||
$parentId = null;
|
||||
if ($request->has('category')) {
|
||||
$parentId = (int) $request->input('category');
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
$result = $this->documentationCategoryService->create($projectId, $versionId, $user);
|
||||
$result = $this->documentationCategoryService->create($projectId, $versionId, $user, $parentId);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/create', $result->getData());
|
||||
return view('admin/projects/documentation-versions/documentation-categories/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $versionId, int $id, Request $request): View
|
||||
@@ -54,7 +60,7 @@ final class DocumentationCategoriesController extends Controller
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentation-categories/edit', $result->getData());
|
||||
return view('admin/projects/documentation-versions/documentation-categories/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, int $versionId, StoreUpdateRequest $request): RedirectResponse
|
||||
|
||||
+2
-2
@@ -35,10 +35,10 @@ final class DocumentationVersionController extends Controller
|
||||
return view('admin/projects/documentation-versions/index', $result->getData());
|
||||
}
|
||||
|
||||
public function show(int $projectId, int $id, Request $request): View
|
||||
public function show(int $projectId, int $id, Request $request, ?int $category = null): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$result = $this->documentationVersionService->show($projectId, $id, $user);
|
||||
$result = $this->documentationVersionService->show($projectId, $id, $category, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin\Projects;
|
||||
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Http\Controllers\Admin\Controller;
|
||||
use App\Http\Requests\Admin\Projects\Documentations\CreateRequest;
|
||||
use App\Http\Requests\Admin\Projects\Documentations\IndexRequest;
|
||||
use App\Http\Requests\Admin\Projects\Documentations\StoreUpdateRequest;
|
||||
use App\Services\Admin\Project\DocumentationService;
|
||||
@@ -32,18 +33,23 @@ final class DocumentationsController extends Controller
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/index', $result->getData());
|
||||
return view('admin/projects/documentation-versions/documentations/index', $result->getData());
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, Request $request): View
|
||||
public function create(int $projectId, int $versionId, CreateRequest $request): View
|
||||
{
|
||||
$categoryId = null;
|
||||
if ($request->has('category')) {
|
||||
$categoryId = (int) $request->input('category');
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
$result = $this->documentationService->create($projectId, $versionId, $user);
|
||||
$result = $this->documentationService->create($projectId, $versionId, $user, $categoryId);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/create', $result->getData());
|
||||
return view('admin/projects/documentation-versions/documentations/create', $result->getData());
|
||||
}
|
||||
|
||||
public function edit(int $projectId, int $versionId, int $id, Request $request): View
|
||||
@@ -54,7 +60,7 @@ final class DocumentationsController extends Controller
|
||||
$this->errors($result);
|
||||
}
|
||||
|
||||
return view('admin/projects/documentations/edit', $result->getData());
|
||||
return view('admin/projects/documentation-versions/documentations/edit', $result->getData());
|
||||
}
|
||||
|
||||
public function store(int $projectId, int $versionId, StoreUpdateRequest $request): RedirectResponse
|
||||
|
||||
@@ -16,8 +16,8 @@ final class DocumentationController extends Controller
|
||||
|
||||
public function defaultVersion(Request $request): RedirectResponse | View
|
||||
{
|
||||
$project = $request->get('project');
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
$project = $request->attributes->get('project');
|
||||
$websiteTranslations = $request->attributes->get('websiteTranslations');
|
||||
|
||||
$result = $this->documentationService->defaultVersion($project, $request->user());
|
||||
if ($result->isError()) {
|
||||
@@ -40,9 +40,9 @@ final class DocumentationController extends Controller
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$documentation = new Documentation(
|
||||
project: $request->get('project'),
|
||||
version: $request->get('version'),
|
||||
websiteTranslations: $request->get('websiteTranslations'),
|
||||
project: $request->attributes->get('project'),
|
||||
version: $request->attributes->get('version'),
|
||||
websiteTranslations: $request->attributes->get('websiteTranslations'),
|
||||
user: $request->user(),
|
||||
);
|
||||
$result = $this->documentationService->index($documentation);
|
||||
@@ -57,9 +57,9 @@ final class DocumentationController extends Controller
|
||||
public function category(string $slug, Request $request): View
|
||||
{
|
||||
$documentation = new Documentation(
|
||||
project: $request->get('project'),
|
||||
version: $request->get('version'),
|
||||
websiteTranslations: $request->get('websiteTranslations'),
|
||||
project: $request->attributes->get('project'),
|
||||
version: $request->attributes->get('version'),
|
||||
websiteTranslations: $request->attributes->get('websiteTranslations'),
|
||||
user: $request->user(),
|
||||
);
|
||||
$result = $this->documentationService->category($slug, $documentation);
|
||||
@@ -77,9 +77,9 @@ final class DocumentationController extends Controller
|
||||
public function view(string $slug, Request $request): View
|
||||
{
|
||||
$documentation = new Documentation(
|
||||
project: $request->get('project'),
|
||||
version: $request->get('version'),
|
||||
websiteTranslations: $request->get('websiteTranslations'),
|
||||
project: $request->attributes->get('project'),
|
||||
version: $request->attributes->get('version'),
|
||||
websiteTranslations: $request->attributes->get('websiteTranslations'),
|
||||
user: $request->user(),
|
||||
);
|
||||
$result = $this->documentationService->view($slug, $documentation);
|
||||
|
||||
@@ -17,16 +17,16 @@ final class FeedbackController extends Controller
|
||||
public function index(Request $request): View
|
||||
{
|
||||
return view('site.feedback.index', [
|
||||
'project' => $request->get('project'),
|
||||
'websiteTranslations' => $request->get('websiteTranslations'),
|
||||
'project' => $request->attributes->get('project'),
|
||||
'websiteTranslations' => $request->attributes->get('websiteTranslations'),
|
||||
'captcha' => config('app.captcha', false),
|
||||
]);
|
||||
}
|
||||
|
||||
public function send(SendRequest $request): RedirectResponse
|
||||
{
|
||||
$project = $request->get('project');
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
$project = $request->attributes->get('project');
|
||||
$websiteTranslations = $request->attributes->get('websiteTranslations');
|
||||
$user = $request->user();
|
||||
$data = $request->getDto();
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ final class ProjectsController extends Controller
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$user = $request->user();
|
||||
$project = $request->get('project');
|
||||
$project = $request->attributes->get('project');
|
||||
|
||||
if (\is_null($project)) {
|
||||
$with = ['storage'];
|
||||
@@ -27,7 +27,7 @@ final class ProjectsController extends Controller
|
||||
return \view('site.projects.index', $result->getData());
|
||||
}
|
||||
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
$websiteTranslations = $request->attributes->get('websiteTranslations');
|
||||
$result = $this->projectService->getAboutByProject($project, $websiteTranslations, $user);
|
||||
if ($result->isError()) {
|
||||
$this->errors($result);
|
||||
|
||||
@@ -10,7 +10,7 @@ final readonly class DocumentationVersion
|
||||
{
|
||||
public function handle(Request $request, \Closure $next): Response
|
||||
{
|
||||
$project = $request->get('project');
|
||||
$project = $request->attributes->get('project');
|
||||
$versionSlug = $request->route()?->parameter('version');
|
||||
if ($versionSlug === null || $project === null) {
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
|
||||
@@ -10,7 +10,7 @@ final class IsProject
|
||||
{
|
||||
public function handle(Request $request, \Closure $next): Response
|
||||
{
|
||||
$project = $request->get('project');
|
||||
$project = $request->attributes->get('project');
|
||||
if (\is_null($project)) {
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ final class IsWebsiteTranslations
|
||||
{
|
||||
public function handle(Request $request, \Closure $next): Response
|
||||
{
|
||||
$websiteTranslations = $request->get('websiteTranslations');
|
||||
$websiteTranslations = $request->attributes->get('websiteTranslations');
|
||||
if (\is_null($websiteTranslations)) {
|
||||
\abort(Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ final class StoreUpdateRequest extends FormRequest implements FormRequestDto
|
||||
{
|
||||
return new StoreUpdate(
|
||||
title: $this->input('title'),
|
||||
description: $this->input('description'),
|
||||
description: (string) $this->input('description', ''),
|
||||
storages: $this->storages(),
|
||||
isTranslateAutomatically: (bool) $this->input('translate-automatically', false),
|
||||
);
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\DocumentationCategories;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class CreateRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'category' => ['nullable', 'integer', 'min:1'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\Admin\Projects\Documentations;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
final class CreateRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'category' => ['nullable', 'integer', 'min:1'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ final class DocumentationCategoryService extends Service
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, User $user): ServiceResultError | ServiceResultArray
|
||||
public function create(int $projectId, int $versionId, User $user, ?int $parentId = null): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
||||
$project = $version?->project;
|
||||
@@ -88,10 +88,15 @@ final class DocumentationCategoryService extends Service
|
||||
}
|
||||
|
||||
$defaultLanguage = $project->languages->where('is_default', 1)->first();
|
||||
$category = new DocumentationCategory();
|
||||
if ($parentId !== null) {
|
||||
$category->parent_id = $parentId;
|
||||
}
|
||||
|
||||
return $this->result([
|
||||
'version' => $version,
|
||||
'project' => $project,
|
||||
'category' => new DocumentationCategory(),
|
||||
'category' => $category,
|
||||
'categories' => $this->documentationCategoryRepository->getForSelect($version, $defaultLanguage),
|
||||
'serviceTranslationEnable' => config('translation_service.enable', false),
|
||||
]);
|
||||
|
||||
@@ -75,7 +75,7 @@ final class DocumentationService extends Service
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(int $projectId, int $versionId, User $user): ServiceResultError | ServiceResultArray
|
||||
public function create(int $projectId, int $versionId, User $user, ?int $categoryId = null): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$version = $this->documentationVersionRepository->getVersionById($versionId);
|
||||
$project = $version?->project;
|
||||
@@ -87,11 +87,16 @@ final class DocumentationService extends Service
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$documentation = new Documentation();
|
||||
if ($categoryId !== null) {
|
||||
$documentation->category_id = $categoryId;
|
||||
}
|
||||
|
||||
$defaultLanguage = $project->languages->where('is_default', 1)->first();
|
||||
return $this->result([
|
||||
'version' => $version,
|
||||
'project' => $project,
|
||||
'documentation' => new Documentation(),
|
||||
'documentation' => $documentation,
|
||||
'categories' => $this->documentationCategoryRepository->getForSelect($version, $defaultLanguage),
|
||||
'serviceTranslationEnable' => config('translation_service.enable', false),
|
||||
]);
|
||||
|
||||
@@ -2,12 +2,17 @@
|
||||
|
||||
namespace App\Services\Admin\Project;
|
||||
|
||||
use App\Dto\Builder\Documentation as DocumentationBuilderDto;
|
||||
use App\Dto\Builder\DocumentationCategory as DocumentationCategoryBuilderDto;
|
||||
use App\Dto\QuerySettingsDto;
|
||||
use App\Dto\Builder\DocumentationVersion as DocumentationVersionBuilderDto;
|
||||
use App\Dto\Service\Admin\Project\DocumentationVersion\StoreUpdate;
|
||||
use App\Enums\DocumentationVersionStatus;
|
||||
use App\Models\DocumentationVersion;
|
||||
use App\Models\ProjectLanguage;
|
||||
use App\Models\User;
|
||||
use App\Repositories\DocumentationCategoryRepository;
|
||||
use App\Repositories\DocumentationRepository;
|
||||
use App\Repositories\DocumentationVersionRepository;
|
||||
use App\Repositories\ProjectRepository;
|
||||
use App\ServiceResults\ServiceResultArray;
|
||||
@@ -17,6 +22,8 @@ use App\ServiceResults\StoreUpdateResult;
|
||||
use App\Services\ClearCacheCommandHandler;
|
||||
use App\Services\DocumentationVersion\DocumentationVersionCommandHandler;
|
||||
use App\Services\Service;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
final class DocumentationVersionService extends Service
|
||||
@@ -26,6 +33,9 @@ final class DocumentationVersionService extends Service
|
||||
private readonly DocumentationVersionRepository $documentationVersionRepository,
|
||||
private readonly DocumentationVersionCommandHandler $documentationVersionCommandHandler,
|
||||
private readonly ClearCacheCommandHandler $clearCacheCommandHandler,
|
||||
|
||||
private readonly DocumentationCategoryRepository $documentationCategoryRepository,
|
||||
private readonly DocumentationRepository $documentationRepository
|
||||
) { }
|
||||
|
||||
public function index(int $projectId, DocumentationVersionBuilderDto $documentationVersionBuilderDto, QuerySettingsDto $querySettingsDto, User $user): ServiceResultError | ServiceResultArray
|
||||
@@ -54,7 +64,7 @@ final class DocumentationVersionService extends Service
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(int $projectId, int $versionId, User $user): ServiceResultError | ServiceResultArray
|
||||
public function show(int $projectId, int $versionId, ?int $categoryId, User $user): ServiceResultError | ServiceResultArray
|
||||
{
|
||||
$project = $this->projectRepository->getProjectById($projectId);
|
||||
if (\is_null($project)) {
|
||||
@@ -70,9 +80,48 @@ final class DocumentationVersionService extends Service
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
|
||||
$category = null;
|
||||
if (!\is_null($categoryId)) {
|
||||
$category = $this->documentationCategoryRepository->getCategoryById($categoryId);
|
||||
if (\is_null($category) || $category->version_id !== $version->id) {
|
||||
return $this->errNotFound(__('Not Found'));
|
||||
}
|
||||
if ($user->cannot('view', $category)) {
|
||||
return $this->errFobidden(__('Access is denied'));
|
||||
}
|
||||
}
|
||||
|
||||
$defaultLanguage = $project->languages()->where('is_default', 1)->first();
|
||||
$with = [
|
||||
'content' => function (HasOne $hasOne) use ($defaultLanguage) {
|
||||
/** @var ?ProjectLanguage $defaultLanguage */
|
||||
$hasOne->when($defaultLanguage, function (Builder $query, ProjectLanguage $defaultLanguage) {
|
||||
$query->where('language_id', $defaultLanguage->id);
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
$categoryDto = new DocumentationCategoryBuilderDto\Category($category->id ?? null);
|
||||
$categories = $this->documentationCategoryRepository
|
||||
->getCategories(
|
||||
$version->id,
|
||||
new DocumentationCategoryBuilderDto(parentId: $categoryDto),
|
||||
$with
|
||||
)->all();
|
||||
$documents = $this->documentationRepository
|
||||
->getDocumentations(
|
||||
$version->id,
|
||||
new DocumentationBuilderDto(categoryId: $categoryDto),
|
||||
$with
|
||||
)->all();
|
||||
|
||||
return $this->result([
|
||||
'version' => $version,
|
||||
'project' => $project,
|
||||
|
||||
'category' => $category,
|
||||
'categories' => $categories,
|
||||
'documentations' => $documents,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ final readonly class ResizeCommandHandler
|
||||
{
|
||||
public function resize(Storage $storage, int $width, int $height): Storage
|
||||
{
|
||||
$image = InterventionImage::read($storage->path);
|
||||
$image = InterventionImage::decodePath($storage->path);
|
||||
if ($image->width() < $width && $image->height() < $height) {
|
||||
return $storage;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ final readonly class ResizeCommandHandler
|
||||
|
||||
public function width(Storage $storage, int $width): Storage
|
||||
{
|
||||
$image = InterventionImage::read($storage->path);
|
||||
$image = InterventionImage::decodePath($storage->path);
|
||||
if ($image->width() < $width) {
|
||||
return $storage;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ final readonly class ResizeCommandHandler
|
||||
|
||||
public function height(Storage $storage, int $height): Storage
|
||||
{
|
||||
$image = InterventionImage::read($storage->path);
|
||||
$image = InterventionImage::decodePath($storage->path);
|
||||
if ($image->height() < $height) {
|
||||
return $storage;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"$schema": "https://getcomposer.org/schema.json",
|
||||
"name": "laravel/laravel",
|
||||
"type": "project",
|
||||
"description": "The skeleton application for the Laravel framework.",
|
||||
@@ -6,23 +7,22 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"intervention/image-laravel": "^1.2",
|
||||
"intervention/image-laravel": "^4.0",
|
||||
"kor-elf/captcha-rule-for-laravel": "^1.0",
|
||||
"kor-elf/translate-laravel": "1.3.0",
|
||||
"laravel/framework": "^11.0",
|
||||
"laravel/tinker": "^2.9",
|
||||
"staudenmeir/laravel-adjacency-list": "^1.0"
|
||||
"kor-elf/translate-laravel": "^2.0",
|
||||
"laravel/framework": "^13.8",
|
||||
"laravel/tinker": "^3.0",
|
||||
"staudenmeir/laravel-adjacency-list": "^1.26"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.13",
|
||||
"barryvdh/laravel-debugbar": "^4.3",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"laravel-lang/common": "^6.2",
|
||||
"laravel/pint": "^1.13",
|
||||
"laravel/sail": "^1.26",
|
||||
"laravel/pail": "^1.2.5",
|
||||
"laravel/pao": "^1.0.6",
|
||||
"laravel/pint": "^1.27",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.0",
|
||||
"phpunit/phpunit": "^10.5",
|
||||
"spatie/laravel-ignition": "^2.4"
|
||||
"nunomaduro/collision": "^8.6",
|
||||
"phpunit/phpunit": "^12.5.12"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -37,6 +37,22 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"setup": [
|
||||
"composer install",
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
|
||||
"@php artisan key:generate",
|
||||
"@php artisan migrate --force",
|
||||
"npm install --ignore-scripts",
|
||||
"npm run build"
|
||||
],
|
||||
"dev": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --timeout=0\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
|
||||
],
|
||||
"test": [
|
||||
"@php artisan config:clear --ansi @no_additional_args",
|
||||
"@php artisan test"
|
||||
],
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
@@ -51,6 +67,9 @@
|
||||
"@php artisan key:generate --ansi",
|
||||
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
|
||||
"@php artisan migrate --graceful --ansi"
|
||||
],
|
||||
"pre-package-uninstall": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::prePackageUninstall"
|
||||
]
|
||||
},
|
||||
"extra": {
|
||||
|
||||
Generated
+2252
-3946
File diff suppressed because it is too large
Load Diff
@@ -38,6 +38,9 @@
|
||||
"Connection Timed Out": "Connection Timed Out",
|
||||
"Continue": "Continue",
|
||||
"Create": "Create",
|
||||
"Create documentation": "Create documentation",
|
||||
"Create category": "Create category",
|
||||
"Create version documentation": "Create a version of the documentation",
|
||||
"Create :name": "Create :name",
|
||||
"Created": "Created",
|
||||
"Delete": "Delete",
|
||||
|
||||
@@ -17,4 +17,6 @@ return [
|
||||
'Documentation' => 'Documentation',
|
||||
'Categories' => 'Categories',
|
||||
'Setting up automatic translation' => 'Setting up automatic translation',
|
||||
'Documentation not found' => 'Documentation not found',
|
||||
'No categories found' => 'No categories found',
|
||||
];
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'Do not translate' => 'Do not translate',
|
||||
'Mark as not to translate' => 'Mark as not to translate',
|
||||
];
|
||||
@@ -38,6 +38,9 @@
|
||||
"Connection Timed Out": "Соединение не отвечает",
|
||||
"Continue": "Продолжай",
|
||||
"Create": "Создать",
|
||||
"Create documentation": "Создать документацию",
|
||||
"Create category": "Создать категорию",
|
||||
"Create version documentation": "Создать версию документации",
|
||||
"Create :name": "Создать :name",
|
||||
"Created": "Создано",
|
||||
"Delete": "Удалить",
|
||||
|
||||
@@ -17,4 +17,6 @@ return [
|
||||
'Documentation' => 'Документация',
|
||||
'Categories' => 'Категории',
|
||||
'Setting up automatic translation' => 'Настройка автоматического перевода',
|
||||
'Documentation not found' => 'Документация не найдена',
|
||||
'No categories found' => 'Категории не найдены',
|
||||
];
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'Do not translate' => 'Не переводить',
|
||||
'Mark as not to translate' => 'Пометить как не переводить',
|
||||
];
|
||||
+23
-7
@@ -1,18 +1,34 @@
|
||||
|
||||
<div class="mb-4">
|
||||
<div class="mb-2">
|
||||
@can('create', \App\Models\DocumentationVersion::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.create', ['project' => $project->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.create', ['project' => $project->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
||||
{{ __('Create') }}
|
||||
{{ __('Create version documentation') }}
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\DocumentationVersion::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.index', ['project' => $project->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.index', ['project' => $project->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
{{ __('List') }}
|
||||
{{ __('admin-sections.Documentation version') }}
|
||||
</a>
|
||||
@endcan
|
||||
@if(!empty($version) && $version->id)
|
||||
@can('viewAny', \App\Models\Documentation::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
{{ __('admin-sections.Documentation') }}
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\DocumentationCategory::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
{{ __('admin-sections.Categories') }}
|
||||
</a>
|
||||
@endcan
|
||||
@endif
|
||||
</div>
|
||||
|
||||
|
||||
+12
-4
@@ -1,12 +1,12 @@
|
||||
<div class="mb-4">
|
||||
<div class="mb-2">
|
||||
@can('create', \App\Models\DocumentationCategory::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.create', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.create', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
||||
{{ __('Create') }}
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\DocumentationCategory::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
@@ -14,12 +14,20 @@
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\Documentation::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
{{ __('admin-sections.Documentation') }}
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\DocumentationVersion::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.index', ['project' => $project->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
{{ __('admin-sections.Documentation version') }}
|
||||
</a>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -3,14 +3,14 @@
|
||||
{{ __('admin-sections.Project') . ': ' . $project->name . ' (' . $version->title . ')' }}
|
||||
@endsection
|
||||
<x-admin.layout>
|
||||
@include('admin.projects.documentation-categories._top')
|
||||
@include('admin.projects.documentation-versions.documentation-categories._top')
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<div class="card border-0 shadow components-section">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.Categories') }}</h3>
|
||||
<form method="post" action="{{ route('admin.projects.documentation-versions.categories.store', ['project' => $project->id, 'version' => $version->id]) }}">
|
||||
@include('admin.projects.documentation-categories._from')
|
||||
@include('admin.projects.documentation-versions.documentation-categories._from')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+4
-3
@@ -3,15 +3,16 @@
|
||||
{{ __('admin-sections.Project') . ': ' . $project->name . ' (' . $version->title . ')' }}
|
||||
@endsection
|
||||
<x-admin.layout>
|
||||
@include('admin.projects.documentation-categories._top')
|
||||
@include('admin.projects.documentation-versions.documentation-categories._top')
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<div class="card border-0 shadow components-section">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.Categories') }}</h3>
|
||||
<form method="post" action="{{ route('admin.projects.documentation-versions.categories.update', ['project' => $project->id, 'version' => $version->id, 'category' => $category->id]) }}">
|
||||
<form method="post"
|
||||
action="{{ route('admin.projects.documentation-versions.categories.update', ['project' => $project->id, 'version' => $version->id, 'category' => $category->id]) }}">
|
||||
@method('PUT')
|
||||
@include('admin.projects.documentation-categories._from')
|
||||
@include('admin.projects.documentation-versions.documentation-categories._from')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
{{ __('admin-sections.Project') . ': ' . $project->name . ' (' . $version->title . ')' }}
|
||||
@endsection
|
||||
<x-admin.layout>
|
||||
@include('admin.projects.documentation-categories._top')
|
||||
@include('admin.projects.documentation-versions.documentation-categories._top')
|
||||
<div class="card border-0 shadow mb-4">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.Categories') }}</h3>
|
||||
+12
-4
@@ -1,12 +1,12 @@
|
||||
<div class="mb-4">
|
||||
<div class="mb-2">
|
||||
@can('create', \App\Models\Documentation::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.create', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.create', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
||||
{{ __('Create') }}
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\Documentation::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
@@ -14,12 +14,20 @@
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\DocumentationCategory::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2">
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.index', ['project' => $project->id, 'version' => $version->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
{{ __('admin-sections.Categories') }}
|
||||
</a>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\DocumentationVersion::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.index', ['project' => $project->id]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 0 1-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75c0 .621-.504 1.125-1.125 1.125m1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125m0 3.75h-7.5A1.125 1.125 0 0 1 12 18.375m9.75-12.75c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125m19.5 0v1.5c0 .621-.504 1.125-1.125 1.125M2.25 5.625v1.5c0 .621.504 1.125 1.125 1.125m0 0h17.25m-17.25 0h7.5c.621 0 1.125.504 1.125 1.125M3.375 8.25c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125m17.25-3.75h-7.5c-.621 0-1.125.504-1.125 1.125m8.625-1.125c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125M12 10.875v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 10.875c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125M13.125 12h7.5m-7.5 0c-.621 0-1.125.504-1.125 1.125M20.625 12c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125m-17.25 0h7.5M12 14.625v-1.5m0 1.5c0 .621-.504 1.125-1.125 1.125M12 14.625c0 .621.504 1.125 1.125 1.125m-2.25 0c.621 0 1.125.504 1.125 1.125m0 1.5v-1.5m0 0c0-.621.504-1.125 1.125-1.125m0 0h7.5"></path>
|
||||
</svg>
|
||||
{{ __('admin-sections.Documentation version') }}
|
||||
</a>
|
||||
@endcan
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -3,14 +3,14 @@
|
||||
{{ __('admin-sections.Project') . ': ' . $project->name . ' (' . $version->title . ')' }}
|
||||
@endsection
|
||||
<x-admin.layout>
|
||||
@include('admin.projects.documentations._top')
|
||||
@include('admin.projects.documentation-versions.documentations._top')
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<div class="card border-0 shadow components-section">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.Documentation') }}</h3>
|
||||
<form method="post" action="{{ route('admin.projects.documentation-versions.documentations.store', ['project' => $project->id, 'version' => $version->id]) }}">
|
||||
@include('admin.projects.documentations._from')
|
||||
@include('admin.projects.documentation-versions.documentations._from')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
{{ __('admin-sections.Project') . ': ' . $project->name . ' (' . $version->title . ')' }}
|
||||
@endsection
|
||||
<x-admin.layout>
|
||||
@include('admin.projects.documentations._top')
|
||||
@include('admin.projects.documentation-versions.documentations._top')
|
||||
<div class="row">
|
||||
<div class="col-12 mb-4">
|
||||
<div class="card border-0 shadow components-section">
|
||||
@@ -11,7 +11,7 @@
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.Documentation') }}</h3>
|
||||
<form method="post" action="{{ route('admin.projects.documentation-versions.documentations.update', ['project' => $project->id, 'version' => $version->id, 'documentation' => $documentation->id]) }}">
|
||||
@method('PUT')
|
||||
@include('admin.projects.documentations._from')
|
||||
@include('admin.projects.documentation-versions.documentations._from')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
{{ __('admin-sections.Project') . ': ' . $project->name . ' (' . $version->title . ')' }}
|
||||
@endsection
|
||||
<x-admin.layout>
|
||||
@include('admin.projects.documentations._top')
|
||||
@include('admin.projects.documentation-versions.documentations._top')
|
||||
<div class="card border-0 shadow mb-4">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.Documentation') }}</h3>
|
||||
+140
-23
@@ -1,45 +1,162 @@
|
||||
@section('meta_title', __('admin-sections.Documentation version'))
|
||||
@section('h1', __('admin-sections.Project') . ': ' . $project->name)
|
||||
@php
|
||||
$categoryId = null;
|
||||
if (!empty($category) && $category->id) {
|
||||
$categoryId = $category->id;
|
||||
}
|
||||
@endphp
|
||||
<x-admin.layout>
|
||||
@include('admin.projects.documentation-versions._top')
|
||||
<div class="card border-0 shadow mb-4">
|
||||
<div class="card-body">
|
||||
<h3 id="category" class="mb-4">{{ __('admin-sections.Documentation version') }}: {{ $version->title }}</h3>
|
||||
<h3 id="category" class="mb-4">
|
||||
{{ __('admin-sections.Documentation version') }}: {{ $version->title }}
|
||||
</h3>
|
||||
@if(!empty($category))
|
||||
<h3 class="mb-4">
|
||||
{{ __('admin-sections.Categories') }}: {{ $category->content?->title }}
|
||||
</h3>
|
||||
@endif
|
||||
@can('create', \App\Models\Documentation::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.create', ['project' => $project->id, 'version' => $version->id, 'category' => $categoryId]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
||||
{{ __('Create documentation') }}
|
||||
</a>
|
||||
@endcan
|
||||
@can('create', \App\Models\DocumentationCategory::class)
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.create', ['project' => $project->id, 'version' => $version->id, 'category' => $categoryId]) }}" class="btn btn-secondary d-inline-flex align-items-center me-2 mb-3">
|
||||
<svg class="icon icon-xs me-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
||||
{{ __('Create category') }}
|
||||
</a>
|
||||
@endcan
|
||||
<div class="table-responsive">
|
||||
<table class="table table-centered table-nowrap mb-0 rounded">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th class="border-0">{{ __('admin-sections.Sections') }}</th>
|
||||
<td><h5>{{ __('admin-sections.Categories') }}</h5></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="border-0">{{ __('validation.attributes.title') }}</th>
|
||||
<th class="border-0">{{ __('validation.attributes.slug') }}</th>
|
||||
<th class="border-0">{{ __('validation.attributes.is_public') }}</th>
|
||||
<th class="border-0 rounded-end" style="width: 150px"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@can('viewAny', \App\Models\Documentation::class)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.index', ['project' => $project->id, 'version' => $version->id]) }}" class="fw-bold">
|
||||
<svg width="16" height="16" class="align-text-top" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z"></path>
|
||||
</svg>
|
||||
{{ __('admin-sections.Documentation') }}
|
||||
@forelse($categories as $category)
|
||||
<tr>
|
||||
<td>
|
||||
@can('view', $category)
|
||||
<a href="{{ route('admin.projects.documentation-versions.category.show', ['project' => $project->id, 'version' => $version->id, 'category' => $category->id]) }}" class="text-decoration-none text-dark">
|
||||
{{ $category->content?->title }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endcan
|
||||
@can('viewAny', \App\Models\DocumentationCategory::class)
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.index', ['project' => $project->id, 'version' => $version->id]) }}" class="fw-bold">
|
||||
<svg width="16" height="16" class="align-text-top" data-slot="icon" fill="none" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 12.75V12A2.25 2.25 0 0 1 4.5 9.75h15A2.25 2.25 0 0 1 21.75 12v.75m-8.69-6.44-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z"></path>
|
||||
@else
|
||||
{{ $category->content?->title }}
|
||||
@endcan
|
||||
</td>
|
||||
<td>
|
||||
{{ $category->slug }}
|
||||
</td>
|
||||
<td>
|
||||
@if($category->is_public)
|
||||
{{ __('Yes') }}
|
||||
@else
|
||||
{{ __('No') }}
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@can('update', $category)
|
||||
<a href="{{ route('admin.projects.documentation-versions.categories.edit', ['project' => $project->id, 'version' => $version->id, 'category' => $category->id]) }}" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Edit') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
{{ __('admin-sections.Categories') }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endcan
|
||||
@endcan
|
||||
@can('delete', $category)
|
||||
<form method="post" class="d-inline-block" action="{{ route('admin.projects.documentation-versions.categories.destroy', ['project' => $project->id, 'version' => $version->id, 'category' => $category->id]) }}">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-danger click-confirm" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Delete') }}">
|
||||
<svg data-slot="icon" fill="currentColor" width="20" height="20" class="align-text-center" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
@endcan
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="text-center">
|
||||
{{ __('admin-sections.No categories found') }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><h5>{{ __('admin-sections.Documentation') }}</h5></td>
|
||||
</tr>
|
||||
<tr class="thead-light">
|
||||
<th class="border-0">{{ __('validation.attributes.title') }}</th>
|
||||
<th class="border-0">{{ __('validation.attributes.slug') }}</th>
|
||||
<th class="border-0">{{ __('validation.attributes.is_public') }}</th>
|
||||
<th class="border-0 rounded-end" style="width: 150px"></th>
|
||||
</tr>
|
||||
@forelse($documentations as $documentation)
|
||||
<tr>
|
||||
<td>
|
||||
{{ $documentation->content?->title }}
|
||||
</td>
|
||||
<td>
|
||||
{{ $documentation->slug }}
|
||||
</td>
|
||||
<td>
|
||||
@if($documentation->is_public)
|
||||
{{ __('Yes') }}
|
||||
@else
|
||||
{{ __('No') }}
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@can('update', $documentation)
|
||||
<a href="{{ route('admin.projects.documentation-versions.documentations.edit', ['project' => $project->id, 'version' => $version->id, 'documentation' => $documentation->id]) }}" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Edit') }}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="align-text-top" viewBox="0 0 16 16">
|
||||
<path d="M12.854.146a.5.5 0 0 0-.707 0L10.5 1.793 14.207 5.5l1.647-1.646a.5.5 0 0 0 0-.708l-3-3zm.646 6.061L9.793 2.5 3.293 9H3.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.207l6.5-6.5zm-7.468 7.468A.5.5 0 0 1 6 13.5V13h-.5a.5.5 0 0 1-.5-.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.5-.5V10h-.5a.499.499 0 0 1-.175-.032l-.179.178a.5.5 0 0 0-.11.168l-2 5a.5.5 0 0 0 .65.65l5-2a.5.5 0 0 0 .168-.11l.178-.178z"/>
|
||||
</svg>
|
||||
</a>
|
||||
@endcan
|
||||
@can('delete', $documentation)
|
||||
<form method="post" class="d-inline-block" action="{{ route('admin.projects.documentation-versions.documentations.destroy', ['project' => $project->id, 'version' => $version->id, 'documentation' => $documentation->id]) }}">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-danger click-confirm" data-bs-toggle="tooltip" data-bs-placement="top" title="{{ __('Delete') }}">
|
||||
<svg data-slot="icon" fill="currentColor" width="20" height="20" class="align-text-center" stroke-width="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
@endcan
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="text-center">
|
||||
{{ __('admin-sections.Documentation not found') }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@push('scripts')
|
||||
@include('admin._scripts._click-confirm', ['alert' => __('Do you want to delete?')])
|
||||
@endpush
|
||||
</x-admin.layout>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
@endphp
|
||||
<div class="mb-3">
|
||||
<label for="{{ $tinyId }}">{{ $title }}</label>
|
||||
<textarea class="form-control {{ $attributes->get('class') }} textarea-tinymce @error($requestName) is-invalid @enderror" name="{{ $name }}" id="{{ $tinyId }}" rows="3">{{ $value }}</textarea>
|
||||
<textarea class="form-control {{ $attributes->get('class') }} textarea-tinymce @error($requestName) is-invalid @enderror" name="{{ $name }}" id="{{ $tinyId }}" style="height: 600px;">{{ $value }}</textarea>
|
||||
@foreach($images as $image)
|
||||
@continue( empty($image['file']) )
|
||||
<input type="hidden" value="{{ $image['file'] }}" name="{{ $storageUpload->getInputName() }}[content_images][][file]';">
|
||||
@@ -95,14 +95,96 @@
|
||||
xhr.send(formData);
|
||||
});
|
||||
@endif
|
||||
|
||||
tinymce.PluginManager.add('translateNo', (editor) => {
|
||||
const ATTR = 'translate';
|
||||
const VALUE = 'no';
|
||||
|
||||
const isTranslateNo = (node) =>
|
||||
node && node.nodeType === 1 && node.getAttribute(ATTR) === VALUE;
|
||||
|
||||
const toggleTranslateNo = () => {
|
||||
const selectedNode = editor.selection.getNode();
|
||||
|
||||
if (isTranslateNo(selectedNode)) {
|
||||
// Remove translate="no", expand span
|
||||
if (selectedNode.tagName === 'SPAN') {
|
||||
editor.dom.remove(selectedNode, true); // true = сохранить детей
|
||||
} else {
|
||||
editor.dom.setAttrib(selectedNode, ATTR, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If inside translate="no", remove the mark
|
||||
const wrapper = editor.dom.getParent(selectedNode, `[${ATTR}="${VALUE}"]`);
|
||||
if (wrapper) {
|
||||
if (wrapper.tagName === 'SPAN') {
|
||||
editor.dom.remove(wrapper, true);
|
||||
} else {
|
||||
editor.dom.setAttrib(wrapper, ATTR, null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, wrap the selection
|
||||
editor.formatter.register('translateNo', {
|
||||
inline: 'span',
|
||||
attributes: { [ATTR]: VALUE },
|
||||
remove: 'all'
|
||||
});
|
||||
editor.formatter.apply('translateNo');
|
||||
};
|
||||
|
||||
editor.ui.registry.addToggleButton('translateNo', {
|
||||
icon: 'translate',
|
||||
tooltip: '{{ __('editor.Do not translate') }}',
|
||||
onAction: toggleTranslateNo,
|
||||
onSetup: (api) => {
|
||||
const setActive = () => {
|
||||
const node = editor.selection.getNode();
|
||||
api.setActive(
|
||||
isTranslateNo(node) ||
|
||||
!!editor.dom.getParent(node, `[${ATTR}="${VALUE}"]`)
|
||||
);
|
||||
};
|
||||
editor.on('NodeChange', setActive);
|
||||
return () => editor.off('NodeChange', setActive);
|
||||
}
|
||||
});
|
||||
|
||||
editor.ui.registry.addMenuItem('translateNo', {
|
||||
text: '{{ __('editor.Mark as not to translate') }}',
|
||||
icon: 'translate',
|
||||
onAction: toggleTranslateNo
|
||||
});
|
||||
});
|
||||
|
||||
tinymce.init({
|
||||
content_style: `
|
||||
span[translate="no"] {
|
||||
background: rgba(255, 215, 0, 0.35);
|
||||
outline: 1px dashed #e0a800;
|
||||
position: relative;
|
||||
}
|
||||
span[translate="no"]:hover::before {
|
||||
position: absolute;
|
||||
content: "{{ __('editor.Do not translate') }}";
|
||||
left: 0;
|
||||
bottom: 100%;
|
||||
background: #e0a800;
|
||||
white-space: nowrap;
|
||||
padding: 0.25rem;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
`,
|
||||
selector: '#{{ $tinyId }}',
|
||||
@if(in_array(app()->getLocale(), ['ru'], true))
|
||||
language: '{{ app()->getLocale() }}',
|
||||
@endif
|
||||
license_key: '{{ $tinymceLicenseKey }}',
|
||||
plugins: 'advlist code emoticons link lists table codesample media my-image',
|
||||
toolbar: 'bold italic | bullist numlist | link image emoticons media codesample',
|
||||
plugins: 'advlist code emoticons link lists table codesample media my-image translateNo',
|
||||
toolbar: 'bold italic | bullist numlist | link image emoticons media codesample translateNo',
|
||||
referrer_policy: 'origin',
|
||||
@if($storageUpload !== null)
|
||||
images_upload_handler: imageUpload,
|
||||
|
||||
@@ -38,6 +38,7 @@ Route::middleware(['auth', 'verified', \App\Http\Middleware\UserLocale::class])-
|
||||
|
||||
Route::resource('documentation-versions', \App\Http\Controllers\Admin\Projects\DocumentationVersionController::class)->where(['documentation_version' => '[0-9]+']);
|
||||
Route::prefix('documentation-versions/{version}')->as('documentation-versions.')->group(function () {
|
||||
Route::get('category/{category}', [\App\Http\Controllers\Admin\Projects\DocumentationVersionController::class, 'show'])->where(['category' => '[0-9]+'])->name('category.show');
|
||||
Route::resource('documentations', \App\Http\Controllers\Admin\Projects\DocumentationsController::class)->except(['show'])->where(['documentation' => '[0-9]+']);
|
||||
Route::resource('categories', \App\Http\Controllers\Admin\Projects\DocumentationCategoriesController::class)->except(['show'])->where(['category' => '[0-9]+']);
|
||||
})->where(['version' => '[0-9]+']);
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WAITLOOPS=5
|
||||
SLEEPSEC=1
|
||||
unitd="unitd"
|
||||
role=${CONTAINER_ROLE:-app}
|
||||
|
||||
curl_put()
|
||||
{
|
||||
RET=$(/usr/bin/curl -s -w '%{http_code}' -X PUT --data-binary @$1 --unix-socket /var/run/control.unit.sock http://localhost/$2)
|
||||
RET_BODY=$(echo $RET | /bin/sed '$ s/...$//')
|
||||
RET_STATUS=$(echo $RET | /usr/bin/tail -c 4)
|
||||
if [ "$RET_STATUS" -ne "200" ]; then
|
||||
echo "$0: Error: HTTP response status code is '$RET_STATUS'"
|
||||
echo "$RET_BODY"
|
||||
return 1
|
||||
else
|
||||
echo "$0: OK: HTTP response status code is '$RET_STATUS'"
|
||||
echo "$RET_BODY"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
if [ "$role" = "app" ]; then
|
||||
echo "$0: Launching Unit daemon to perform initial configuration..."
|
||||
/usr/sbin/$unitd --control unix:/var/run/control.unit.sock
|
||||
for i in $(/usr/bin/seq $WAITLOOPS); do
|
||||
if [ ! -S /var/run/control.unit.sock ]; then
|
||||
echo "$0: Waiting for control socket to be created..."
|
||||
/bin/sleep $SLEEPSEC
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# even when the control socket exists, it does not mean unit has finished initialisation
|
||||
# this curl call will get a reply once unit is fully launched
|
||||
/usr/bin/curl -s -X GET --unix-socket /var/run/control.unit.sock http://localhost/
|
||||
|
||||
if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -print -quit 2>/dev/null | /bin/grep -q .; then
|
||||
echo "$0: /docker-entrypoint.d/ is not empty, applying initial configuration..."
|
||||
|
||||
if [[ -n "${UNIT_SOURCE:-}" ]]; then
|
||||
config="/docker-entrypoint.d/config.json"
|
||||
tmp="$(mktemp)"
|
||||
jq --arg src "${UNIT_SOURCE}" '
|
||||
.listeners["*:9000"].forwarded.source =
|
||||
( $src
|
||||
| split(",")
|
||||
| map( gsub("^\\s+|\\s+$"; "") ) # trim пробелы
|
||||
| map( select(. != "") ) # убрать пустые
|
||||
)
|
||||
' "$config" > "$tmp"
|
||||
mv "$tmp" "$config"
|
||||
fi
|
||||
|
||||
echo "$0: Looking for certificate bundles in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.pem"); do
|
||||
echo "$0: Uploading certificates bundle: $f"
|
||||
curl_put $f "certificates/$(basename $f .pem)"
|
||||
done
|
||||
|
||||
echo "$0: Looking for JavaScript modules in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.js"); do
|
||||
echo "$0: Uploading JavaScript module: $f"
|
||||
curl_put $f "js_modules/$(basename $f .js)"
|
||||
done
|
||||
|
||||
echo "$0: Looking for configuration snippets in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.json"); do
|
||||
echo "$0: Applying configuration $f";
|
||||
curl_put $f "config"
|
||||
done
|
||||
|
||||
echo "$0: Looking for shell scripts in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.sh"); do
|
||||
echo "$0: Launching $f";
|
||||
"$f"
|
||||
done
|
||||
|
||||
# warn on filetypes we don't know what to do with
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -not -name "*.sh" -not -name "*.json" -not -name "*.pem" -not -name "*.js"); do
|
||||
echo "$0: Ignoring $f";
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$0: Stopping Unit daemon after initial configuration..."
|
||||
kill -TERM $(/bin/cat /var/run/unit.pid)
|
||||
|
||||
for i in $(/usr/bin/seq $WAITLOOPS); do
|
||||
if [ -S /var/run/control.unit.sock ]; then
|
||||
echo "$0: Waiting for control socket to be removed..."
|
||||
/bin/sleep $SLEEPSEC
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -S /var/run/control.unit.sock ]; then
|
||||
kill -KILL $(/bin/cat /var/run/unit.pid)
|
||||
rm -f /var/run/control.unit.sock
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "$0: Unit initial configuration complete; ready for start up..."
|
||||
echo
|
||||
fi
|
||||
|
||||
chmod -R 777 /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
|
||||
exec "$@"
|
||||
@@ -1,122 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
WAITLOOPS=5
|
||||
SLEEPSEC=1
|
||||
unitd="unitd"
|
||||
role=${CONTAINER_ROLE:-app}
|
||||
|
||||
curl_put()
|
||||
{
|
||||
RET=$(/usr/bin/curl -s -w '%{http_code}' -X PUT --data-binary @$1 --unix-socket /var/run/control.unit.sock http://localhost/$2)
|
||||
RET_BODY=$(echo $RET | /bin/sed '$ s/...$//')
|
||||
RET_STATUS=$(echo $RET | /usr/bin/tail -c 4)
|
||||
if [ "$RET_STATUS" -ne "200" ]; then
|
||||
echo "$0: Error: HTTP response status code is '$RET_STATUS'"
|
||||
echo "$RET_BODY"
|
||||
return 1
|
||||
else
|
||||
echo "$0: OK: HTTP response status code is '$RET_STATUS'"
|
||||
echo "$RET_BODY"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
if [ "$role" = "app" ]; then
|
||||
echo "$0: Launching Unit daemon to perform initial configuration..."
|
||||
/usr/sbin/$unitd --control unix:/var/run/control.unit.sock
|
||||
for i in $(/usr/bin/seq $WAITLOOPS); do
|
||||
if [ ! -S /var/run/control.unit.sock ]; then
|
||||
echo "$0: Waiting for control socket to be created..."
|
||||
/bin/sleep $SLEEPSEC
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# even when the control socket exists, it does not mean unit has finished initialisation
|
||||
# this curl call will get a reply once unit is fully launched
|
||||
/usr/bin/curl -s -X GET --unix-socket /var/run/control.unit.sock http://localhost/
|
||||
|
||||
if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -print -quit 2>/dev/null | /bin/grep -q .; then
|
||||
echo "$0: /docker-entrypoint.d/ is not empty, applying initial configuration..."
|
||||
|
||||
if [[ -n "${UNIT_SOURCE:-}" ]]; then
|
||||
config="/docker-entrypoint.d/config.json"
|
||||
tmp="$(mktemp)"
|
||||
jq --arg src "${UNIT_SOURCE}" '
|
||||
.listeners["*:9000"].forwarded.source =
|
||||
( $src
|
||||
| split(",")
|
||||
| map( gsub("^\\s+|\\s+$"; "") ) # trim пробелы
|
||||
| map( select(. != "") ) # убрать пустые
|
||||
)
|
||||
' "$config" > "$tmp"
|
||||
mv "$tmp" "$config"
|
||||
fi
|
||||
|
||||
echo "$0: Looking for certificate bundles in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.pem"); do
|
||||
echo "$0: Uploading certificates bundle: $f"
|
||||
curl_put $f "certificates/$(basename $f .pem)"
|
||||
done
|
||||
|
||||
echo "$0: Looking for JavaScript modules in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.js"); do
|
||||
echo "$0: Uploading JavaScript module: $f"
|
||||
curl_put $f "js_modules/$(basename $f .js)"
|
||||
done
|
||||
|
||||
echo "$0: Looking for configuration snippets in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.json"); do
|
||||
echo "$0: Applying configuration $f";
|
||||
curl_put $f "config"
|
||||
done
|
||||
|
||||
echo "$0: Looking for shell scripts in /docker-entrypoint.d/..."
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -name "*.sh"); do
|
||||
echo "$0: Launching $f";
|
||||
"$f"
|
||||
done
|
||||
|
||||
# warn on filetypes we don't know what to do with
|
||||
for f in $(/usr/bin/find /docker-entrypoint.d/ -type f -not -name "*.sh" -not -name "*.json" -not -name "*.pem" -not -name "*.js"); do
|
||||
echo "$0: Ignoring $f";
|
||||
done
|
||||
fi
|
||||
|
||||
echo "$0: Stopping Unit daemon after initial configuration..."
|
||||
kill -TERM $(/bin/cat /var/run/unit.pid)
|
||||
|
||||
for i in $(/usr/bin/seq $WAITLOOPS); do
|
||||
if [ -S /var/run/control.unit.sock ]; then
|
||||
echo "$0: Waiting for control socket to be removed..."
|
||||
/bin/sleep $SLEEPSEC
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -S /var/run/control.unit.sock ]; then
|
||||
kill -KILL $(/bin/cat /var/run/unit.pid)
|
||||
rm -f /var/run/control.unit.sock
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "$0: Unit initial configuration complete; ready for start up..."
|
||||
echo
|
||||
fi
|
||||
|
||||
php artisan config:cache
|
||||
php artisan event:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
php artisan storage:link
|
||||
if [ "$role" = "app" ]; then
|
||||
php artisan migrate --force
|
||||
fi
|
||||
chown -R unit:unit /var/www/html
|
||||
chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
chmod -R 777 /var/www/html/storage /var/www/html/bootstrap/cache
|
||||
|
||||
exec "$@"
|
||||
@@ -1,23 +1,4 @@
|
||||
FROM docker.io/php:8.3-zts-alpine3.18 AS unit_builder
|
||||
|
||||
ARG UNIT_VERSION=1.31.1
|
||||
|
||||
RUN apk --no-cache add pcre2-dev gcc git musl-dev make && \
|
||||
mkdir -p /usr/lib/unit/modules && \
|
||||
git clone https://github.com/nginx/unit.git && \
|
||||
cd unit && \
|
||||
git checkout $UNIT_VERSION && \
|
||||
./configure --prefix=/var --statedir=/var/lib/unit --runstatedir=/var/run --control=unix:/run/unit/control.unit.sock --log=/var/log/unit.log --user=www-data --group=www-data --tmpdir=/tmp --modulesdir=/var/lib/unit/modules && \
|
||||
./configure php && \
|
||||
make && \
|
||||
make install
|
||||
|
||||
FROM docker.io/php:8.3-zts-alpine3.18 AS build
|
||||
|
||||
COPY --from=unit_builder /var/sbin/unitd /usr/sbin/unitd
|
||||
COPY --from=unit_builder /var/lib/unit/ /var/lib/unit/
|
||||
|
||||
COPY docker/unit-config.json /docker-entrypoint.d/config.json
|
||||
FROM docker.io/php:8.5-fpm-alpine3.23 AS build
|
||||
|
||||
RUN apk --no-cache add pcre2 libbz2 libpng libwebp libjpeg-turbo icu-libs freetype oniguruma libzip jq \
|
||||
&& apk add --no-cache --virtual .phpize-deps icu-dev libpng-dev bzip2-dev libwebp-dev libjpeg-turbo-dev freetype-dev oniguruma-dev libzip-dev pcre2-dev ${PHPIZE_DEPS} \
|
||||
@@ -30,7 +11,7 @@ RUN apk --no-cache add pcre2 libbz2 libpng libwebp libjpeg-turbo icu-libs freety
|
||||
mysqli pdo_mysql \
|
||||
intl mbstring \
|
||||
zip pcntl \
|
||||
exif opcache bz2 \
|
||||
exif bz2 \
|
||||
calendar \
|
||||
&& pear update-channels && pecl update-channels \
|
||||
&& pecl install redis && docker-php-ext-enable redis \
|
||||
@@ -44,36 +25,35 @@ RUN apk --no-cache add pcre2 libbz2 libpng libwebp libjpeg-turbo icu-libs freety
|
||||
&& mkdir -p /tmp/php/upload \
|
||||
&& mkdir -p /tmp/php/sys \
|
||||
&& mkdir -p /tmp/php/session \
|
||||
&& chown -R www-data:www-data /tmp/php \
|
||||
&& ln -sf /dev/stdout /var/log/unit.log \
|
||||
&& addgroup -S unit && adduser -S unit -G unit
|
||||
&& chown -R www-data:www-data /tmp/php
|
||||
|
||||
COPY docker/php/conf/app-fpm.conf /usr/local/etc/php-fpm.d/app-fpm.conf
|
||||
|
||||
FROM build AS app_build_for_production
|
||||
WORKDIR /home/app
|
||||
|
||||
COPY application /home/app
|
||||
|
||||
RUN apk --no-cache add git nodejs npm \
|
||||
RUN apk --no-cache add git \
|
||||
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
|
||||
&& composer install --optimize-autoloader --no-dev \
|
||||
&& npm install && npm run build \
|
||||
&& rm -rf /home/app/node_modules /home/app/.env
|
||||
&& rm -rf /home/app/.env
|
||||
|
||||
|
||||
FROM build AS production
|
||||
|
||||
COPY --from=app_build_for_production /home/app /var/www/html
|
||||
COPY docker/docker-entrypoint_prod.sh /home/unit/docker-entrypoint.sh
|
||||
COPY docker/start.sh /usr/local/bin/start
|
||||
COPY docker/php/start.sh /usr/local/bin/start
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
RUN chmod 755 /home/unit/docker-entrypoint.sh \
|
||||
RUN chown -R www-data:www-data /var/www/html \
|
||||
&& chmod 755 /usr/local/bin/start
|
||||
|
||||
STOPSIGNAL SIGTERM
|
||||
|
||||
ENTRYPOINT ["/home/unit/docker-entrypoint.sh"]
|
||||
USER www-data
|
||||
|
||||
EXPOSE 9000
|
||||
CMD ["/usr/local/bin/start"]
|
||||
|
||||
@@ -82,17 +62,15 @@ FROM build AS develop
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
COPY docker/docker-entrypoint_dev.sh /home/unit/docker-entrypoint.sh
|
||||
COPY docker/start.sh /usr/local/bin/start
|
||||
COPY docker/php/start.sh /usr/local/bin/start
|
||||
|
||||
STOPSIGNAL SIGTERM
|
||||
|
||||
RUN chmod 755 /home/unit/docker-entrypoint.sh \
|
||||
&& chmod 755 /usr/local/bin/start \
|
||||
RUN chmod 755 /usr/local/bin/start \
|
||||
&& apk --no-cache add git nodejs npm \
|
||||
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
ENTRYPOINT ["/home/unit/docker-entrypoint.sh"]
|
||||
USER www-data
|
||||
|
||||
EXPOSE 9000
|
||||
CMD ["/usr/local/bin/start"]
|
||||
@@ -0,0 +1,26 @@
|
||||
[www]
|
||||
php_admin_value[upload_tmp_dir] = "/tmp/php/upload"
|
||||
php_admin_value[sys_temp_dir] = "/tmp/php/sys"
|
||||
php_admin_value[session.save_path] = "/tmp/php/session"
|
||||
php_admin_value[open_basedir] = "/var/www/html:/tmp/php:."
|
||||
php_admin_value[expose_php] = 0
|
||||
php_admin_value[memory_limit] = ${PHP_FPM_MEMORY_LIMIT}
|
||||
php_admin_value[upload_max_filesize] = ${PHP_FPM_UPLOAD_MAX_FILESIZE}
|
||||
php_admin_value[post_max_size] = ${PHP_FPM_POST_MAX_SIZE}
|
||||
php_admin_value[display_errors] = ${PHP_FPM_DISPLAY_ERRORS}
|
||||
php_admin_value[opcache.enable] = ${PHP_FPM_OPCACHE_ENABLE}
|
||||
php_admin_value[opcache.validate_timestamps] = ${PHP_FPM_OPCACHE_VALIDATE_TIMESTAMPS}
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = ${PHP_FPM_PM_MAX_CHILDREN}
|
||||
pm.start_servers = ${PHP_FPM_PM_START_SERVERS}
|
||||
pm.min_spare_servers = ${PHP_FPM_PM_MIN_SPARE_SERVERS}
|
||||
pm.max_spare_servers = ${PHP_FPM_PM_MAX_SPARE_SERVERS}
|
||||
pm.max_requests = ${PHP_FPM_PM_MAX_REQUESTS}
|
||||
|
||||
|
||||
listen = 127.0.0.1:9000
|
||||
listen.mode = 0660
|
||||
listen.owner = www-data
|
||||
listen.group = www-data
|
||||
security.limit_extensions = .php
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
role=${CONTAINER_ROLE:-app}
|
||||
|
||||
if [ "$APP_ENV" = "production" ]; then
|
||||
php artisan config:cache
|
||||
php artisan event:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
php artisan storage:link
|
||||
fi
|
||||
|
||||
if [ "$role" = "app" ]; then
|
||||
|
||||
export PHP_FPM_MEMORY_LIMIT="${PHP_FPM_MEMORY_LIMIT:-256m}"
|
||||
export PHP_FPM_UPLOAD_MAX_FILESIZE="${PHP_FPM_UPLOAD_MAX_FILESIZE:-20m}"
|
||||
export PHP_FPM_POST_MAX_SIZE="${PHP_FPM_POST_MAX_SIZE:-20m}"
|
||||
|
||||
export PHP_FPM_PM_MAX_CHILDREN="${PHP_FPM_PM_MAX_CHILDREN:-10}"
|
||||
export PHP_FPM_PM_START_SERVERS="${PHP_FPM_PM_START_SERVERS:-5}"
|
||||
export PHP_FPM_PM_MIN_SPARE_SERVERS="${PHP_FPM_PM_MIN_SPARE_SERVERS:-2}"
|
||||
export PHP_FPM_PM_MAX_SPARE_SERVERS="${PHP_FPM_PM_MAX_SPARE_SERVERS:-5}"
|
||||
export PHP_FPM_PM_MAX_REQUESTS="${PHP_FPM_PM_MAX_REQUESTS:-500}"
|
||||
|
||||
if [ "$APP_ENV" = "production" ]; then
|
||||
export PHP_FPM_DISPLAY_ERRORS="${PHP_FPM_DISPLAY_ERRORS:-0}"
|
||||
export PHP_FPM_OPCACHE_ENABLE="${PHP_FPM_OPCACHE_ENABLE:-1}"
|
||||
export PHP_FPM_OPCACHE_VALIDATE_TIMESTAMPS="${PHP_FPM_OPCACHE_VALIDATE_TIMESTAMPS:-0}"
|
||||
|
||||
php artisan migrate --force
|
||||
else
|
||||
export PHP_FPM_DISPLAY_ERRORS="${PHP_FPM_DISPLAY_ERRORS:-1}"
|
||||
export PHP_FPM_OPCACHE_ENABLE="${PHP_FPM_OPCACHE_ENABLE:-0}"
|
||||
export PHP_FPM_OPCACHE_VALIDATE_TIMESTAMPS="${PHP_FPM_OPCACHE_VALIDATE_TIMESTAMPS:-1}"
|
||||
fi
|
||||
|
||||
if [ ! -w /var/www/html/storage ]; then
|
||||
echo "ERROR: /var/www/html/storage must be writable."
|
||||
echo "Fix permissions on host/volume for the www-data user."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec php-fpm
|
||||
elif [ "$role" = "queue" ]; then
|
||||
echo "Running the queue..."
|
||||
while [ true ]
|
||||
do
|
||||
php /var/www/html/artisan queue:work --verbose --sleep=5 --tries=100 --backoff=10 --max-time=3600 --queue=high,normal,low,default
|
||||
done
|
||||
elif [ "$role" = "scheduler" ]; then
|
||||
while [ true ]
|
||||
do
|
||||
php /var/www/html/artisan schedule:run --verbose --no-interaction &
|
||||
sleep 60
|
||||
done
|
||||
else
|
||||
echo "Could not match the container role \"$role\""
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
set -e
|
||||
role=${CONTAINER_ROLE:-app}
|
||||
if [ "$role" = "app" ]; then
|
||||
exec unitd --no-daemon --control unix:/var/run/control.unit.sock --user unit --group unit
|
||||
elif [ "$role" = "queue" ]; then
|
||||
echo "Running the queue..."
|
||||
while [ true ]
|
||||
do
|
||||
php /var/www/html/artisan queue:work --verbose --sleep=5 --tries=100 --backoff=10 --max-time=3600 --queue=high,normal,low,default
|
||||
done
|
||||
elif [ "$role" = "scheduler" ]; then
|
||||
while [ true ]
|
||||
do
|
||||
php /var/www/html/artisan schedule:run --verbose --no-interaction &
|
||||
sleep 60
|
||||
done
|
||||
else
|
||||
echo "Could not match the container role \"$role\""
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,69 +0,0 @@
|
||||
{
|
||||
"listeners": {
|
||||
"*:9000": {
|
||||
"pass": "routes",
|
||||
"forwarded": {
|
||||
"client_ip": "X-Forwarded-For",
|
||||
"recursive": false,
|
||||
"source": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"routes": [
|
||||
{
|
||||
"match": {
|
||||
"uri": [
|
||||
"/index.php/",
|
||||
"~^/index\\.php/.*",
|
||||
"~\\.php$"
|
||||
]
|
||||
},
|
||||
"action": {
|
||||
"return": 404
|
||||
}
|
||||
},
|
||||
{
|
||||
"action": {
|
||||
"share": "/var/www/html/public$uri",
|
||||
"fallback": {
|
||||
"pass": "applications/laravel"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
"applications": {
|
||||
"laravel": {
|
||||
"type": "php",
|
||||
"root": "/var/www/html/public",
|
||||
"working_directory": "/var/www/html",
|
||||
"user": "www-data",
|
||||
"group": "www-data",
|
||||
"script": "index.php",
|
||||
"processes": {
|
||||
"max": 10,
|
||||
"spare": 5,
|
||||
"idle_timeout": 20
|
||||
},
|
||||
"options": {
|
||||
"file": "/usr/local/etc/php/php.ini",
|
||||
"admin": {
|
||||
"upload_tmp_dir": "/tmp/php/upload",
|
||||
"sys_temp_dir": "/tmp/php/sys",
|
||||
"session.save_path": "/tmp/php/session",
|
||||
"open_basedir": "/var/www/html:/tmp/php:.",
|
||||
"memory_limit": "256M",
|
||||
"upload_max_filesize": "20M",
|
||||
"post_max_size": "20M",
|
||||
"expose_php": "0"
|
||||
},
|
||||
"user": {
|
||||
"display_errors": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
FROM docker.io/nginx:1.31-alpine AS build
|
||||
|
||||
COPY docker/web/conf/default.conf.template /etc/nginx/templates/default.conf.template
|
||||
COPY docker/web/conf/fastcgi_params /etc/nginx/fastcgi_params
|
||||
COPY docker/web/start.sh /usr/local/bin/start
|
||||
|
||||
RUN chmod 755 /usr/local/bin/start
|
||||
|
||||
FROM build AS app_build_for_production
|
||||
|
||||
WORKDIR /home/app
|
||||
COPY application /home/app
|
||||
|
||||
RUN apk --no-cache add git nodejs npm \
|
||||
&& npm install && npm run build \
|
||||
&& rm -rf /home/app/node_modules
|
||||
|
||||
FROM build AS production
|
||||
|
||||
COPY --from=app_build_for_production /home/app/public /usr/share/nginx/html
|
||||
|
||||
WORKDIR /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["/usr/local/bin/start"]
|
||||
|
||||
FROM build AS develop
|
||||
WORKDIR /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
CMD ["/usr/local/bin/start"]
|
||||
@@ -0,0 +1,3 @@
|
||||
application/public/*.php
|
||||
application/public/**/*.php
|
||||
application/public/.htaccess
|
||||
@@ -0,0 +1,44 @@
|
||||
map $FRONTEND_PORT $host_with_port {
|
||||
"" $host;
|
||||
default "$host:$FRONTEND_PORT";
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
client_max_body_size ${NGINX_CLIENT_MAX_BODY_SIZE};
|
||||
|
||||
disable_symlinks if_not_owner from=/usr/share/nginx/html;
|
||||
|
||||
index index.html;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
${GZIP_BLOCK}
|
||||
${REAL_IP_BLOCK}
|
||||
|
||||
location / {
|
||||
location / {
|
||||
try_files $uri @fallback;
|
||||
}
|
||||
location ~ \.php$ {
|
||||
return 404;
|
||||
}
|
||||
location ~ /\. {
|
||||
return 404;
|
||||
}
|
||||
location ~ /\.(ht|svn|git) {
|
||||
return 404;
|
||||
}
|
||||
}
|
||||
|
||||
location @fallback {
|
||||
fastcgi_pass ${BACKEND_HOST}:${BACKEND_PORT};
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param REDIRECT_STATUS 200;
|
||||
fastcgi_param SCRIPT_FILENAME /var/www/html/public/index.php;
|
||||
fastcgi_param SCRIPT_NAME /index.php;
|
||||
fastcgi_param HTTP_HOST $host_with_port;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
fastcgi_param QUERY_STRING $query_string;
|
||||
fastcgi_param REQUEST_METHOD $request_method;
|
||||
fastcgi_param CONTENT_TYPE $content_type;
|
||||
fastcgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
fastcgi_param REQUEST_URI $request_uri;
|
||||
fastcgi_param DOCUMENT_URI $document_uri;
|
||||
fastcgi_param DOCUMENT_ROOT $document_root;
|
||||
fastcgi_param SERVER_PROTOCOL $server_protocol;
|
||||
fastcgi_param HTTPS $https if_not_empty;
|
||||
|
||||
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
|
||||
fastcgi_param SERVER_SOFTWARE nginx;
|
||||
|
||||
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||
fastcgi_param REMOTE_PORT $remote_port;
|
||||
fastcgi_param SERVER_ADDR $server_addr;
|
||||
fastcgi_param SERVER_PORT $server_port;
|
||||
fastcgi_param SERVER_NAME $server_name;
|
||||
|
||||
fastcgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
|
||||
fastcgi_param HTTP_X_REAL_IP $remote_addr;
|
||||
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
if [ "$IS_GZIP" = "1" ]; then
|
||||
GZIP_BLOCK='gzip on;
|
||||
gzip_vary on;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
gzip_min_length 1024;'
|
||||
else
|
||||
GZIP_BLOCK=''
|
||||
fi
|
||||
export GZIP_BLOCK
|
||||
|
||||
if [ -n "$TRUSTED_PROXY_CIDR" ]; then
|
||||
REAL_IP_BLOCK="set_real_ip_from $TRUSTED_PROXY_CIDR;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;"
|
||||
else
|
||||
REAL_IP_BLOCK=""
|
||||
fi
|
||||
export REAL_IP_BLOCK
|
||||
|
||||
export BACKEND_HOST="${BACKEND_HOST:-app}"
|
||||
export BACKEND_PORT="${BACKEND_PORT:-9000}"
|
||||
export FRONTEND_PORT="${FRONTEND_PORT:-''}"
|
||||
export NGINX_CLIENT_MAX_BODY_SIZE="${NGINX_CLIENT_MAX_BODY_SIZE:-'20m'}"
|
||||
|
||||
envsubst '$BACKEND_HOST $BACKEND_PORT $GZIP_BLOCK $REAL_IP_BLOCK $FRONTEND_PORT $NGINX_CLIENT_MAX_BODY_SIZE' \
|
||||
< /etc/nginx/templates/default.conf.template \
|
||||
> /etc/nginx/conf.d/default.conf
|
||||
|
||||
exec nginx -g 'daemon off;'
|
||||
+27
-6
@@ -1,30 +1,47 @@
|
||||
#version: '3.7'
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/web/Dockerfile
|
||||
target: DEVELOP
|
||||
depends_on:
|
||||
- app
|
||||
ports:
|
||||
- ${DOCKER_WEB_PORT}:80
|
||||
environment:
|
||||
IS_GZIP: 1
|
||||
# FRONTEND_PORT: ${DOCKER_WEB_PORT}
|
||||
BACKEND_HOST: app
|
||||
BACKEND_PORT: 9000
|
||||
TRUSTED_PROXY_CIDR: 172.16.0.0/12
|
||||
volumes:
|
||||
- ./app/application/public:/usr/share/nginx/html
|
||||
- ./app/application/storage/app/public:/usr/share/nginx/html/storage
|
||||
app:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: PRODUCTION
|
||||
# restart: always
|
||||
depends_on:
|
||||
- db
|
||||
- app-redis
|
||||
- captcha-app
|
||||
ports:
|
||||
- ${DOCKER_APP_PORT}:9000
|
||||
volumes:
|
||||
- ./app/application:/var/www/html
|
||||
environment:
|
||||
CONTAINER_ROLE: app
|
||||
UNIT_SOURCE: "172.16.0.0/12"
|
||||
APP_ENV: production
|
||||
|
||||
queue:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: PRODUCTION
|
||||
# restart: always
|
||||
depends_on:
|
||||
- app
|
||||
- db
|
||||
- app-redis
|
||||
environment:
|
||||
@@ -35,10 +52,11 @@ services:
|
||||
scheduler:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: PRODUCTION
|
||||
# restart: always
|
||||
depends_on:
|
||||
- app
|
||||
- db
|
||||
- app-redis
|
||||
environment:
|
||||
@@ -75,6 +93,7 @@ services:
|
||||
image: korelf/service-captcha:0.8.2
|
||||
# restart: always
|
||||
depends_on:
|
||||
- captcha-app
|
||||
- db
|
||||
- captcha-redis
|
||||
environment:
|
||||
@@ -84,6 +103,7 @@ services:
|
||||
image: korelf/service-captcha:0.8.2
|
||||
# restart: always
|
||||
depends_on:
|
||||
- captcha-app
|
||||
- db
|
||||
- captcha-redis
|
||||
environment:
|
||||
@@ -95,6 +115,7 @@ services:
|
||||
image: korelf/service-captcha:0.8.2
|
||||
# restart: always
|
||||
depends_on:
|
||||
- captcha-app
|
||||
- db
|
||||
- captcha-redis
|
||||
environment:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#version: '3.7'
|
||||
services:
|
||||
app:
|
||||
# image: korelf/my-projects-website:0.5.0 # docker hub
|
||||
image: docker.mdhub.kor-elf.net/kor-elf/my-projects-website:0.5.0 # MDHub
|
||||
# image: korelf/my-projects-website:0.6.0 # docker hub
|
||||
image: docker.mdhub.kor-elf.net/kor-elf/my-projects-website:0.6.0 # MDHub
|
||||
# restart: always
|
||||
depends_on:
|
||||
- db
|
||||
@@ -20,8 +20,8 @@ services:
|
||||
# - ./app/translate/authorized_key.json:/var/www/html/storage/translation_service/authorized_key.json
|
||||
|
||||
queue:
|
||||
# image: korelf/my-projects-website:0.5.0 # docker hub
|
||||
image: docker.mdhub.kor-elf.net/kor-elf/my-projects-website:0.5.0 # MDHub
|
||||
# image: korelf/my-projects-website:0.6.0 # docker hub
|
||||
image: docker.mdhub.kor-elf.net/kor-elf/my-projects-website:0.6.0 # MDHub
|
||||
# restart: always
|
||||
depends_on:
|
||||
- db
|
||||
@@ -35,8 +35,8 @@ services:
|
||||
# - ./app/translate/authorized_key.json:/var/www/html/storage/translation_service/authorized_key.json
|
||||
|
||||
scheduler:
|
||||
# image: korelf/my-projects-website:0.5.0 # docker hub
|
||||
image: docker.mdhub.kor-elf.net/kor-elf/my-projects-website:0.5.0 # MDHub
|
||||
# image: korelf/my-projects-website:0.6.0 # docker hub
|
||||
image: docker.mdhub.kor-elf.net/kor-elf/my-projects-website:0.6.0 # MDHub
|
||||
# restart: always
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
+30
-8
@@ -1,28 +1,46 @@
|
||||
#version: '3.7'
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/web/Dockerfile
|
||||
target: DEVELOP
|
||||
depends_on:
|
||||
- app
|
||||
ports:
|
||||
- ${DOCKER_WEB_PORT}:80
|
||||
environment:
|
||||
IS_GZIP: 0
|
||||
FRONTEND_PORT: ${DOCKER_WEB_PORT}
|
||||
BACKEND_HOST: app
|
||||
BACKEND_PORT: 9000
|
||||
# TRUSTED_PROXY_CIDR: 172.16.0.0/12
|
||||
volumes:
|
||||
- ./app/application/public:/usr/share/nginx/html
|
||||
- ./app/application/storage/app/public:/usr/share/nginx/html/storage
|
||||
app:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: DEVELOP
|
||||
depends_on:
|
||||
- db
|
||||
- app-redis
|
||||
- captcha-app
|
||||
ports:
|
||||
- ${DOCKER_APP_PORT}:9000
|
||||
volumes:
|
||||
- ./app/application:/var/www/html
|
||||
environment:
|
||||
CONTAINER_ROLE: app
|
||||
APP_ENV: local
|
||||
|
||||
queue:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: DEVELOP
|
||||
depends_on:
|
||||
- db
|
||||
- app
|
||||
- app-redis
|
||||
environment:
|
||||
CONTAINER_ROLE: queue
|
||||
@@ -32,10 +50,11 @@ services:
|
||||
scheduler:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: DEVELOP
|
||||
depends_on:
|
||||
- db
|
||||
- app
|
||||
- app-redis
|
||||
environment:
|
||||
CONTAINER_ROLE: scheduler
|
||||
@@ -69,6 +88,7 @@ services:
|
||||
image: korelf/service-captcha:0.8.2
|
||||
# restart: always
|
||||
depends_on:
|
||||
- captcha-app
|
||||
- db
|
||||
- captcha-redis
|
||||
environment:
|
||||
@@ -81,6 +101,7 @@ services:
|
||||
image: korelf/service-captcha:0.8.2
|
||||
# restart: always
|
||||
depends_on:
|
||||
- captcha-app
|
||||
- db
|
||||
- captcha-redis
|
||||
environment:
|
||||
@@ -95,6 +116,7 @@ services:
|
||||
image: korelf/service-captcha:0.8.2
|
||||
# restart: always
|
||||
depends_on:
|
||||
- captcha-app
|
||||
- db
|
||||
- captcha-redis
|
||||
environment:
|
||||
@@ -124,7 +146,7 @@ services:
|
||||
artisan:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: ARTISAN
|
||||
user: "${UID}:${GID}"
|
||||
volumes:
|
||||
@@ -133,7 +155,7 @@ services:
|
||||
composer:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: COMPOSER
|
||||
user: "${UID}:${GID}"
|
||||
volumes:
|
||||
@@ -142,7 +164,7 @@ services:
|
||||
npm:
|
||||
build:
|
||||
context: app
|
||||
dockerfile: docker/Dockerfile
|
||||
dockerfile: docker/php/Dockerfile
|
||||
target: NPM
|
||||
user: "${UID}:${GID}"
|
||||
volumes:
|
||||
|
||||
Reference in New Issue
Block a user