- added own provider for drive methods
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m13s
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m13s
- renamed middleware Role and Can to role_middleware and can_middleware - added some typing for inertia vue3 components - npm updates
This commit is contained in:
parent
cb51a4136f
commit
296c8fd46e
|
@ -1,75 +0,0 @@
|
||||||
{
|
|
||||||
"typescript": true,
|
|
||||||
"commands": [
|
|
||||||
"./commands",
|
|
||||||
"@adonisjs/core/build/commands/index.js",
|
|
||||||
"@adonisjs/repl/build/commands",
|
|
||||||
"@eidellev/inertia-adonisjs/build/commands",
|
|
||||||
"@adonisjs/lucid/build/commands"
|
|
||||||
],
|
|
||||||
"exceptionHandlerNamespace": "App/Exceptions/Handler",
|
|
||||||
"aliases": {
|
|
||||||
"App": "app",
|
|
||||||
"Config": "config",
|
|
||||||
"Database": "database",
|
|
||||||
"Contracts": "contracts"
|
|
||||||
},
|
|
||||||
"preloads": [
|
|
||||||
"./start/routes",
|
|
||||||
"./start/kernel",
|
|
||||||
{
|
|
||||||
"file": "./start/inertia",
|
|
||||||
"environment": [
|
|
||||||
"web"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "./start/validator",
|
|
||||||
"environment": [
|
|
||||||
"web"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"providers": [
|
|
||||||
"./providers/AppProvider",
|
|
||||||
"@adonisjs/core",
|
|
||||||
"@adonisjs/session",
|
|
||||||
"@adonisjs/view",
|
|
||||||
"@adonisjs/shield",
|
|
||||||
"@eidellev/inertia-adonisjs",
|
|
||||||
"@adonisjs/lucid",
|
|
||||||
"@adonisjs/auth",
|
|
||||||
"@eidellev/adonis-stardust",
|
|
||||||
"./providers/QueryBuilderProvider",
|
|
||||||
"./providers/TokenWorkerProvider",
|
|
||||||
"@adonisjs/redis",
|
|
||||||
"./providers/DoiProvider"
|
|
||||||
],
|
|
||||||
"metaFiles": [
|
|
||||||
{
|
|
||||||
"pattern": "public/**",
|
|
||||||
"reloadServer": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pattern": "resources/views/**/*.edge",
|
|
||||||
"reloadServer": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"aceProviders": [
|
|
||||||
"@adonisjs/repl"
|
|
||||||
],
|
|
||||||
"tests": {
|
|
||||||
"suites": [
|
|
||||||
{
|
|
||||||
"name": "functional",
|
|
||||||
"files": [
|
|
||||||
"tests/functional/**/*.spec(.ts|.js)"
|
|
||||||
],
|
|
||||||
"timeout": 60000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"testProviders": [
|
|
||||||
"@japa/preset-adonis/TestsProvider"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@ root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 4
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
|
@ -57,6 +57,7 @@ export default defineConfig({
|
||||||
() => import('@adonisjs/shield/shield_provider'),
|
() => import('@adonisjs/shield/shield_provider'),
|
||||||
// () => import('@eidellev/inertia-adonisjs'),
|
// () => import('@eidellev/inertia-adonisjs'),
|
||||||
// () => import('@adonisjs/inertia/inertia_provider'),
|
// () => import('@adonisjs/inertia/inertia_provider'),
|
||||||
|
() => import('#providers/app_provider'),
|
||||||
() => import('#providers/inertia_provider'),
|
() => import('#providers/inertia_provider'),
|
||||||
() => import('@adonisjs/lucid/database_provider'),
|
() => import('@adonisjs/lucid/database_provider'),
|
||||||
() => import('@adonisjs/auth/auth_provider'),
|
() => import('@adonisjs/auth/auth_provider'),
|
||||||
|
@ -66,8 +67,9 @@ export default defineConfig({
|
||||||
() => import('@adonisjs/static/static_provider'),
|
() => import('@adonisjs/static/static_provider'),
|
||||||
() => import('#providers/stardust_provider'),
|
() => import('#providers/stardust_provider'),
|
||||||
() => import('#providers/query_builder_provider'),
|
() => import('#providers/query_builder_provider'),
|
||||||
() => import('#providers/TokenWorkerProvider'),
|
() => import('#providers/token_worker_provider'),
|
||||||
() => import('#providers/validator_provider'),
|
() => import('#providers/validator_provider'),
|
||||||
|
() => import('#providers/drive/provider/drive_provider')
|
||||||
],
|
],
|
||||||
metaFiles: [
|
metaFiles: [
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,8 @@ import UpdateUserValidator from '#app/Validators/UpdateUserValidator';
|
||||||
// import Hash from '@ioc:Adonis/Core/Hash';
|
// import Hash from '@ioc:Adonis/Core/Hash';
|
||||||
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
// import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
||||||
|
|
||||||
export default class AdminUserController {
|
export default class AdminuserController {
|
||||||
|
|
||||||
public async index({ auth, request, inertia }: HttpContext) {
|
public async index({ auth, request, inertia }: HttpContext) {
|
||||||
const page = request.input('page', 1);
|
const page = request.input('page', 1);
|
||||||
// const limit = 10
|
// const limit = 10
|
|
@ -1,7 +1,7 @@
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
import type { HttpContext } from '@adonisjs/core/http';
|
||||||
// import TotpSecret from 'App/Models/TotpSecret';
|
// import TotpSecret from 'App/Models/TotpSecret';
|
||||||
import User from '#app/Models/User';
|
import User from '#app/Models/User';
|
||||||
import TwoFactorAuthProvider from '#app/Services/TwoFactorAuthProvider';
|
import TwoFactorAuthProvider from '#app/services/TwoFactorAuthProvider';
|
||||||
import { StatusCodes } from 'http-status-codes';
|
import { StatusCodes } from 'http-status-codes';
|
||||||
import { InvalidArgumentException } from 'node-exceptions';
|
import { InvalidArgumentException } from 'node-exceptions';
|
||||||
import { TotpState } from '#contracts/enums';
|
import { TotpState } from '#contracts/enums';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import User from '#models/User';
|
||||||
// import InvalidCredentialException from 'App/Exceptions/InvalidCredentialException';
|
// import InvalidCredentialException from 'App/Exceptions/InvalidCredentialException';
|
||||||
import AuthValidator from '#app/Validators/AuthValidator';
|
import AuthValidator from '#app/Validators/AuthValidator';
|
||||||
|
|
||||||
import TwoFactorAuthProvider from '#app/Services/TwoFactorAuthProvider';
|
import TwoFactorAuthProvider from '#app/services/TwoFactorAuthProvider';
|
||||||
// import { Authenticator } from '@adonisjs/auth';
|
// import { Authenticator } from '@adonisjs/auth';
|
||||||
// import { LoginState } from 'Contracts/enums';
|
// import { LoginState } from 'Contracts/enums';
|
||||||
// import { StatusCodes } from 'http-status-codes';
|
// import { StatusCodes } from 'http-status-codes';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { HttpContext } from '@adonisjs/core/http';
|
import type { HttpContext } from '@adonisjs/core/http';
|
||||||
import User from '#app/Models/User';
|
import User from '#app/Models/User';
|
||||||
// import { RenderResponse } from '@ioc:EidelLev/Inertia';
|
// import { RenderResponse } from '@ioc:EidelLev/Inertia';
|
||||||
import TwoFactorAuthProvider from '#app/Services/TwoFactorAuthProvider';
|
import TwoFactorAuthProvider from '#app/services/TwoFactorAuthProvider';
|
||||||
import hash from '@adonisjs/core/services/hash';
|
import hash from '@adonisjs/core/services/hash';
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
import { schema, rules } from '@adonisjs/validator';
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ export default class UserController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async disableTwoFactorAuthentication({ auth, response, session }: HttpContext): Promise<void> {
|
public async disableTwoFactorAuthentication({ auth, response, session }: HttpContext): Promise<void> {
|
||||||
const user = auth?.user;
|
const user = auth.user;
|
||||||
|
|
||||||
user.twoFactorSecret = null;
|
user.twoFactorSecret = null;
|
||||||
user.twoFactorRecoveryCodes = null;
|
user.twoFactorRecoveryCodes = null;
|
||||||
|
|
|
@ -9,11 +9,11 @@ import Language from '#app/Models/Language';
|
||||||
import Coverage from '#app/Models/Coverage';
|
import Coverage from '#app/Models/Coverage';
|
||||||
import Collection from '#app/Models/Collection';
|
import Collection from '#app/Models/Collection';
|
||||||
import { schema, rules } from '@adonisjs/validator';
|
import { schema, rules } from '@adonisjs/validator';
|
||||||
import { CustomMessages } from "@adonisjs/validator/types";
|
import { CustomMessages } from '@adonisjs/validator/types';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import Person from '#app/Models/Person';
|
import Person from '#app/Models/Person';
|
||||||
import db from '@adonisjs/lucid/services/db';
|
import db from '@adonisjs/lucid/services/db';
|
||||||
import { TransactionClientContract } from "@adonisjs/lucid/types/database";
|
import { TransactionClientContract } from '@adonisjs/lucid/types/database';
|
||||||
import Subject from '#app/Models/Subject';
|
import Subject from '#app/Models/Subject';
|
||||||
import CreateDatasetValidator from '#app/Validators/CreateDatasetValidator';
|
import CreateDatasetValidator from '#app/Validators/CreateDatasetValidator';
|
||||||
import UpdateDatasetValidator from '#app/Validators/UpdateDatasetValidator';
|
import UpdateDatasetValidator from '#app/Validators/UpdateDatasetValidator';
|
||||||
|
@ -27,14 +27,15 @@ import {
|
||||||
DatasetTypes,
|
DatasetTypes,
|
||||||
SubjectTypes,
|
SubjectTypes,
|
||||||
} from '#contracts/enums';
|
} from '#contracts/enums';
|
||||||
import { ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
import { ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
||||||
import DatasetReference from '#app/Models/DatasetReference';
|
import DatasetReference from '#app/Models/DatasetReference';
|
||||||
import { cuid } from '@adonisjs/core/helpers';
|
import { cuid } from '@adonisjs/core/helpers';
|
||||||
import File from '#app/Models/File';
|
import File from '#app/Models/File';
|
||||||
import ClamScan from 'clamscan';
|
import ClamScan from 'clamscan';
|
||||||
import { ValidationException } from '@adonisjs/validator';
|
import { ValidationException } from '@adonisjs/validator';
|
||||||
// import Drive from '@ioc:Adonis/Core/Drive';
|
// import Drive from '@ioc:Adonis/Core/Drive';
|
||||||
import { Exception } from "@adonisjs/core/exceptions";
|
import drive from '#services/drive';
|
||||||
|
import { Exception } from '@adonisjs/core/exceptions';
|
||||||
import { MultipartFile } from '@adonisjs/core/types/bodyparser';
|
import { MultipartFile } from '@adonisjs/core/types/bodyparser';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import app from '@adonisjs/core/services/app';
|
import app from '@adonisjs/core/services/app';
|
||||||
|
@ -445,13 +446,10 @@ export default class DatasetController {
|
||||||
const mimeType = file.headers['content-type'] || 'application/octet-stream'; // Fallback to a default MIME type
|
const mimeType = file.headers['content-type'] || 'application/octet-stream'; // Fallback to a default MIME type
|
||||||
const datasetFolder = `files/${dataset.id}`;
|
const datasetFolder = `files/${dataset.id}`;
|
||||||
// const size = file.size;
|
// const size = file.size;
|
||||||
await file.move(
|
await file.move(app.makePath(datasetFolder), {
|
||||||
app.makePath( datasetFolder),
|
|
||||||
{
|
|
||||||
name: fileName,
|
name: fileName,
|
||||||
overwrite: true, // overwrite in case of conflict
|
overwrite: true, // overwrite in case of conflict
|
||||||
},
|
});
|
||||||
);
|
|
||||||
// save file metadata into db
|
// save file metadata into db
|
||||||
const newFile = new File();
|
const newFile = new File();
|
||||||
newFile.pathName = `${datasetFolder}/${fileName}`;
|
newFile.pathName = `${datasetFolder}/${fileName}`;
|
||||||
|
@ -468,7 +466,10 @@ export default class DatasetController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateRandomString(length: number): string {
|
private generateRandomString(length: number): string {
|
||||||
return crypto.randomBytes(Math.ceil(length / 2)).toString('hex').slice(0, length);
|
return crypto
|
||||||
|
.randomBytes(Math.ceil(length / 2))
|
||||||
|
.toString('hex')
|
||||||
|
.slice(0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateFilename(extension: string): string {
|
private generateFilename(extension: string): string {
|
||||||
|
@ -919,11 +920,7 @@ export default class DatasetController {
|
||||||
// move to disk:
|
// move to disk:
|
||||||
const fileName = `file-${cuid()}.${fileData.extname}`;
|
const fileName = `file-${cuid()}.${fileData.extname}`;
|
||||||
const datasetFolder = `files/${dataset.id}`;
|
const datasetFolder = `files/${dataset.id}`;
|
||||||
await fileData.moveToDisk(
|
await fileData.moveToDisk(datasetFolder, { name: fileName, overwrite: true }, 'local');
|
||||||
datasetFolder,
|
|
||||||
{ name: fileName, overwrite: true },
|
|
||||||
'local'
|
|
||||||
);
|
|
||||||
// let path = coverImage.filePath;
|
// let path = coverImage.filePath;
|
||||||
|
|
||||||
//save to db:
|
//save to db:
|
||||||
|
@ -1047,21 +1044,25 @@ export default class DatasetController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const datasetFolder = `files/${params.id}`;
|
const datasetFolder = `files/${params.id}`;
|
||||||
const folderExists = await Drive.exists(datasetFolder);
|
const folderExists = await drive.exists(datasetFolder);
|
||||||
if (folderExists) {
|
if (folderExists) {
|
||||||
const folderContents = await Drive.list(datasetFolder).toArray();
|
const dirListing = drive.list(datasetFolder);
|
||||||
|
const folderContents = await dirListing.toArray();
|
||||||
if (folderContents.length === 0) {
|
if (folderContents.length === 0) {
|
||||||
await Drive.delete(datasetFolder);
|
await drive.delete(datasetFolder);
|
||||||
}
|
}
|
||||||
// delete dataset wirh relation in db
|
// delete dataset wirh relation in db
|
||||||
await dataset.delete();
|
await dataset.delete();
|
||||||
session.flash({ message: 'You have deleted 1 dataset!' });
|
session.flash({ message: 'You have deleted 1 dataset!' });
|
||||||
return response.redirect().toRoute('dataset.list');
|
return response.redirect().toRoute('dataset.list');
|
||||||
} else {
|
} else {
|
||||||
session.flash({
|
// session.flash({
|
||||||
warning: `You cannot delete this dataset! Invalid server_state: "${dataset.server_state}"!`,
|
// warning: `You cannot delete this dataset! Invalid server_state: "${dataset.server_state}"!`,
|
||||||
});
|
// });
|
||||||
return response.status(400).redirect().back();
|
return response
|
||||||
|
.flash({ warning: `You cannot delete this dataset! Dataset folder "${datasetFolder}" doesn't exist!` })
|
||||||
|
.redirect()
|
||||||
|
.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -1070,10 +1071,7 @@ export default class DatasetController {
|
||||||
throw error;
|
throw error;
|
||||||
} else if (error instanceof Exception) {
|
} else if (error instanceof Exception) {
|
||||||
// General exception handling
|
// General exception handling
|
||||||
return response
|
return response.flash('errors', { error: error.message }).redirect().back();
|
||||||
.flash('errors', { error: error.message })
|
|
||||||
.redirect()
|
|
||||||
.back();
|
|
||||||
} else {
|
} else {
|
||||||
session.flash({ error: 'An error occurred while deleting the dataset.' });
|
session.flash({ error: 'An error occurred while deleting the dataset.' });
|
||||||
return response.redirect().back();
|
return response.redirect().back();
|
||||||
|
|
|
@ -29,28 +29,38 @@ export default class HttpExceptionHandler extends ExceptionHandler {
|
||||||
* codes. You might want to enable them in production only, but feel
|
* codes. You might want to enable them in production only, but feel
|
||||||
* free to enable them in development as well.
|
* free to enable them in development as well.
|
||||||
*/
|
*/
|
||||||
protected renderStatusPages = true;
|
protected renderStatusPages = true; //app.inProduction;
|
||||||
|
|
||||||
// protected statusPages = {
|
|
||||||
// '401,403': 'errors/unauthorized',
|
|
||||||
// '404': 'errors/not-found',
|
|
||||||
// '500..599': 'errors/server-error',
|
|
||||||
// };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status pages is a collection of error code range and a callback
|
* Status pages is a collection of error code range and a callback
|
||||||
* to return the HTML contents to send as a response.
|
* to return the HTML contents to send as a response.
|
||||||
*/
|
*/
|
||||||
|
// protected statusPages: Record<StatusPageRange, StatusPageRenderer> = {
|
||||||
|
// '401..403': (error, { view }) => {
|
||||||
|
// return view.render('./errors/unauthorized', { error });
|
||||||
|
// },
|
||||||
|
// '404': (error, { view }) => {
|
||||||
|
// return view.render('./errors/not-found', { error });
|
||||||
|
// },
|
||||||
|
// '500..599': (error, { view }) => {
|
||||||
|
// return view.render('./errors/server-error', { error });
|
||||||
|
// },
|
||||||
|
// };
|
||||||
protected statusPages: Record<StatusPageRange, StatusPageRenderer> = {
|
protected statusPages: Record<StatusPageRange, StatusPageRenderer> = {
|
||||||
'401..403': (error, { view }) => {
|
'404': (error, { inertia }) => {
|
||||||
return view.render('./errors/unauthorized', { error });
|
return inertia.render('Errors/ServerError', {
|
||||||
|
error: error.message,
|
||||||
|
code: error.status,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
'404': (error, { view }) => {
|
'401..403': async (error, { inertia }) => {
|
||||||
return view.render('./errors/not-found', { error });
|
// session.flash('errors', error.message);
|
||||||
},
|
return inertia.render('Errors/ServerError', {
|
||||||
'500..599': (error, { view }) => {
|
error: error.message,
|
||||||
return view.render('./errors/server-error', { error });
|
code: error.status,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
'500..599': (error, { inertia }) => inertia.render('Errors/ServerError', { error: error.message, code: error.status }),
|
||||||
};
|
};
|
||||||
|
|
||||||
// constructor() {
|
// constructor() {
|
||||||
|
@ -58,7 +68,7 @@ export default class HttpExceptionHandler extends ExceptionHandler {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public async handle(error: any, ctx: HttpContext) {
|
public async handle(error: any, ctx: HttpContext) {
|
||||||
const { response, request, session } = ctx;
|
// const { response, request, session, inertia } = ctx;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle failed authentication attempt
|
* Handle failed authentication attempt
|
||||||
|
@ -75,17 +85,26 @@ export default class HttpExceptionHandler extends ExceptionHandler {
|
||||||
// https://github.com/inertiajs/inertia-laravel/issues/56
|
// https://github.com/inertiajs/inertia-laravel/issues/56
|
||||||
// let test = response.getStatus(); //200
|
// let test = response.getStatus(); //200
|
||||||
// let header = request.header('X-Inertia'); // true
|
// let header = request.header('X-Inertia'); // true
|
||||||
if (request.header('X-Inertia') && [500, 503, 404, 403, 401, 200].includes(response.getStatus())) {
|
// if (request.header('X-Inertia') && [500, 503, 404, 403, 401, 200].includes(response.getStatus())) {
|
||||||
// session.flash('errors', error.messages.errors);
|
// // session.flash('errors', error.messages.errors);
|
||||||
session.flash('errors', error.messages);
|
// session.flash('errors', error.messages);
|
||||||
return response.redirect().back();
|
// return response.redirect().back();
|
||||||
// return inertia.render('Error', {
|
// // return inertia.render('errors/server_error', {
|
||||||
// status: response.getStatus(),
|
// // return inertia.render('errors/server_error', {
|
||||||
// message: error.message,
|
// // // status: response.getStatus(),
|
||||||
// });
|
// // error: error,
|
||||||
// ->toResponse($request)
|
// // });
|
||||||
// ->setStatusCode($response->status());
|
// // ->toResponse($request)
|
||||||
}
|
// // ->setStatusCode($response->status());
|
||||||
|
// }
|
||||||
|
// Dynamically change the error templates based on the absence of X-Inertia header
|
||||||
|
// if (!ctx.request.header('X-Inertia')) {
|
||||||
|
// this.statusPages = {
|
||||||
|
// '401..403': (error, { view }) => view.render('./errors/unauthorized', { error }),
|
||||||
|
// '404': (error, { view }) => view.render('./errors/not-found', { error }),
|
||||||
|
// '500..599': (error, { view }) => view.render('./errors/server-error', { error }),
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forward rest of the exceptions to the parent class
|
* Forward rest of the exceptions to the parent class
|
||||||
|
|
|
@ -7,7 +7,8 @@ import BaseModel from './BaseModel.js';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
// import Drive from '@ioc:Adonis/Core/Drive';
|
// import Drive from '@ioc:Adonis/Core/Drive';
|
||||||
import Drive from '@adonisjs/drive';
|
// import Drive from '@adonisjs/drive';
|
||||||
|
import drive from '#services/drive';
|
||||||
|
|
||||||
import type { HasMany } from "@adonisjs/lucid/types/relations";
|
import type { HasMany } from "@adonisjs/lucid/types/relations";
|
||||||
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
import type { BelongsTo } from "@adonisjs/lucid/types/relations";
|
||||||
|
@ -164,7 +165,7 @@ export default class File extends BaseModel {
|
||||||
public async delete() {
|
public async delete() {
|
||||||
if (this.pathName) {
|
if (this.pathName) {
|
||||||
// Delete file from additional storage
|
// Delete file from additional storage
|
||||||
await Drive.delete(this.pathName);
|
await drive.delete(this.pathName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the original delete method of the BaseModel to remove the record from the database
|
// Call the original delete method of the BaseModel to remove the record from the database
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { withAuthFinder } from '@adonisjs/auth';
|
import { withAuthFinder } from '@adonisjs/auth/mixins/lucid'
|
||||||
import { column, beforeSave, manyToMany, hasMany } from '@adonisjs/lucid/orm';
|
import { column, manyToMany, hasMany } from '@adonisjs/lucid/orm';
|
||||||
import hash from '@adonisjs/core/services/hash';
|
import hash from '@adonisjs/core/services/hash';
|
||||||
import Role from './Role.js';
|
import Role from './Role.js';
|
||||||
import db from '@adonisjs/lucid/services/db';
|
import db from '@adonisjs/lucid/services/db';
|
||||||
// import Config from '@ioc:Adonis/Core/Config';
|
|
||||||
import config from '@adonisjs/core/services/config';
|
import config from '@adonisjs/core/services/config';
|
||||||
import Dataset from './Dataset.js';
|
import Dataset from './Dataset.js';
|
||||||
import BaseModel from './BaseModel.js';
|
import BaseModel from './BaseModel.js';
|
||||||
|
@ -84,12 +83,12 @@ export default class User extends compose(BaseModel, AuthFinder) {
|
||||||
// })
|
// })
|
||||||
// public totp_secret: HasOne<typeof TotpSecret>;
|
// public totp_secret: HasOne<typeof TotpSecret>;
|
||||||
|
|
||||||
@beforeSave()
|
// @beforeSave()
|
||||||
public static async hashPassword(user: User) {
|
// public static async hashPassword(user: User) {
|
||||||
if (user.$dirty.password) {
|
// if (user.$dirty.password) {
|
||||||
user.password = await hash.use('laravel').make(user.password);
|
// user.password = await hash.use('laravel').make(user.password);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
public get isTwoFactorEnabled(): boolean {
|
public get isTwoFactorEnabled(): boolean {
|
||||||
return Boolean(this?.twoFactorSecret && this.state == TotpState.STATE_ENABLED);
|
return Boolean(this?.twoFactorSecret && this.state == TotpState.STATE_ENABLED);
|
||||||
|
|
13
app/services/drive.ts
Normal file
13
app/services/drive.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// import app from './app.js';
|
||||||
|
import DriveManager from "#providers/drive/src/drive_manager";
|
||||||
|
import app from "@adonisjs/core/services/app";
|
||||||
|
|
||||||
|
let drive: DriveManager;
|
||||||
|
/**
|
||||||
|
* Returns a singleton instance of the router class from
|
||||||
|
* the container
|
||||||
|
*/
|
||||||
|
await app.booted(async () => {
|
||||||
|
drive = await app.container.make(DriveManager);
|
||||||
|
});
|
||||||
|
export { drive as default };
|
|
@ -9,26 +9,33 @@ import { Client } from '@opensearch-project/opensearch';
|
||||||
import { getDomain } from '#app/Utils/utility-functions';
|
import { getDomain } from '#app/Utils/utility-functions';
|
||||||
import { BaseCommand, flags } from '@adonisjs/core/ace';
|
import { BaseCommand, flags } from '@adonisjs/core/ace';
|
||||||
import { CommandOptions } from '@adonisjs/core/types/ace';
|
import { CommandOptions } from '@adonisjs/core/types/ace';
|
||||||
|
import env from '#start/env';
|
||||||
|
// import db from '@adonisjs/lucid/services/db';
|
||||||
|
// import { default as Dataset } from '#app/Models/Dataset';
|
||||||
|
|
||||||
const opensearchNode = process.env.OPENSEARCH_HOST || 'localhost';
|
const opensearchNode = env.get('OPENSEARCH_HOST', 'localhost');
|
||||||
const client = new Client({ node: `http://${opensearchNode}` }); // replace with your OpenSearch endpoint
|
const client = new Client({ node: `http://${opensearchNode}` }); // replace with your OpenSearch endpoint
|
||||||
|
|
||||||
export default class IndexDatasets extends BaseCommand {
|
export default class IndexDatasets extends BaseCommand {
|
||||||
static commandName = 'index:datasets';
|
static commandName = 'index:datasets';
|
||||||
static description = 'Index datasets based on publish_id';
|
static description = 'Index datasets based on publish_id';
|
||||||
|
|
||||||
|
public static needsApplication = true;
|
||||||
|
|
||||||
@flags.number({ alias: 'p' })
|
@flags.number({ alias: 'p' })
|
||||||
public publish_id: number;
|
public publish_id: number;
|
||||||
|
|
||||||
static options: CommandOptions = {
|
public static options: CommandOptions = {
|
||||||
loadApp: true,
|
startApp: true,
|
||||||
staysAlive: false,
|
staysAlive: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
this.logger.info('Hello world!');
|
this.logger.info('Hello world!');
|
||||||
const { default: Dataset } = await import('#app/Models/Dataset');
|
// const { default: Dataset } = await import('#app/Models/Dataset');
|
||||||
const datasets = await Dataset.query().where('server_state', 'published').exec(); //this.getDatasets();
|
// const datasets = await Dataset.query().where('server_state', 'published').exec(); //this.getDatasets();
|
||||||
|
const datasets = await this.getDatasets();
|
||||||
const proc = readFileSync('public/assets2/solr.sef.json');
|
const proc = readFileSync('public/assets2/solr.sef.json');
|
||||||
const index_name = 'tethys-records';
|
const index_name = 'tethys-records';
|
||||||
|
|
||||||
|
@ -40,15 +47,19 @@ export default class IndexDatasets extends BaseCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private async getDatasets(): Promise<any[]> {
|
private async getDatasets(): Promise<any[]> {
|
||||||
// // const { default: Dataset } = await import('#app/Models/Dataset');
|
// const { default: Dataset } = await import('#app/Models/Dataset');
|
||||||
// // const Dataset = (await import('#app/Models/Dataset')).default
|
// const Dataset = (await import('#app/Models/Dataset')).default
|
||||||
// const query = Dataset.query().where('server_state', 'published');
|
// const Dataset = (
|
||||||
// if (this.publish_id) {
|
// await this.app.container.make('#app/Models/Dataset')
|
||||||
// query.where('publish_id', this.publish_id);
|
// ).default;
|
||||||
// }
|
// const query: ModelQueryBuilder<Dataset, any> = db.from(Dataset);
|
||||||
// return await query;
|
const query = Dataset.query().preload('xmlCache').where('server_state', 'published');
|
||||||
// }
|
if (this.publish_id) {
|
||||||
|
query.where('publish_id', this.publish_id);
|
||||||
|
}
|
||||||
|
return await query.exec();
|
||||||
|
}
|
||||||
|
|
||||||
private async indexDocument(dataset: Dataset, index_name: string, proc: Buffer): Promise<void> {
|
private async indexDocument(dataset: Dataset, index_name: string, proc: Buffer): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { BaseCommand } from '@adonisjs/core/ace'
|
import { BaseCommand } from '@adonisjs/core/ace';
|
||||||
import type { CommandOptions } from '@adonisjs/core/types/ace'
|
import type { CommandOptions } from '@adonisjs/core/types/ace';
|
||||||
|
|
||||||
export default class IndexTest extends BaseCommand {
|
export default class IndexTest extends BaseCommand {
|
||||||
static commandName = 'index:test'
|
static commandName = 'index:test';
|
||||||
static description = ''
|
static description = '';
|
||||||
|
|
||||||
static options: CommandOptions = {}
|
static options: CommandOptions = {};
|
||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
this.logger.info('Hello world from "IndexTest"')
|
this.logger.info('Hello world from "IndexTest"');
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,10 +4,10 @@
|
||||||
* Feel free to let us know via PR, if you find something broken in this config
|
* Feel free to let us know via PR, if you find something broken in this config
|
||||||
* file.
|
* file.
|
||||||
*/
|
*/
|
||||||
|
import { defineConfig } from '#providers/drive/src/types/define_config';
|
||||||
import env from '#start/env';
|
import env from '#start/env';
|
||||||
// import { driveConfig } from '@adonisjs/core/build/config';
|
// import { driveConfig } from '@adonisjs/core/build/config';
|
||||||
import { driveConfig } from "@adonisjs/drive/build/config.js";
|
// import { driveConfig } from "@adonisjs/drive/build/config.js";
|
||||||
// import Application from '@ioc:Adonis/Core/Application';
|
// import Application from '@ioc:Adonis/Core/Application';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -19,7 +19,7 @@ import { driveConfig } from "@adonisjs/drive/build/config.js";
|
||||||
| defined inside the `contracts` directory.
|
| defined inside the `contracts` directory.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
export default driveConfig({
|
export default defineConfig({
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Default disk
|
| Default disk
|
||||||
|
|
|
@ -11,22 +11,22 @@ export default defineConfig({
|
||||||
* Data that should be shared with all rendered pages
|
* Data that should be shared with all rendered pages
|
||||||
*/
|
*/
|
||||||
sharedData: {
|
sharedData: {
|
||||||
errors: (ctx) => ctx.session.flashMessages.get('errors'),
|
errors: (ctx) => ctx.session?.flashMessages.get('errors'),
|
||||||
|
|
||||||
user_id: (ctx) => {
|
user_id: (ctx) => {
|
||||||
return ctx.session.flashMessages.get('user_id');
|
return ctx.session?.flashMessages.get('user_id');
|
||||||
},
|
},
|
||||||
|
|
||||||
flash: (ctx) => {
|
flash: (ctx) => {
|
||||||
return {
|
return {
|
||||||
message: ctx.session.flashMessages.get('message'),
|
message: ctx.session?.flashMessages.get('message'),
|
||||||
warning: ctx.session.flashMessages.get('warning'),
|
warning: ctx.session?.flashMessages.get('warning'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
// params: ({ params }) => params,
|
// params: ({ params }) => params,
|
||||||
authUser: async ({ auth }: HttpContext) => {
|
authUser: async ({ auth }: HttpContext) => {
|
||||||
if (auth.user) {
|
if (auth?.user) {
|
||||||
await auth.user.load('roles');
|
await auth.user.load('roles');
|
||||||
return auth.user;
|
return auth.user;
|
||||||
// {
|
// {
|
||||||
|
@ -38,6 +38,14 @@ export default defineConfig({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for the server-side rendering
|
||||||
|
*/
|
||||||
|
ssr: {
|
||||||
|
enabled: false,
|
||||||
|
entrypoint: 'inertia/app/ssr.ts',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// import { InertiaConfig } from '@ioc:EidelLev/Inertia';
|
// import { InertiaConfig } from '@ioc:EidelLev/Inertia';
|
||||||
|
|
|
@ -7,8 +7,8 @@ interface OaiConfig {
|
||||||
}
|
}
|
||||||
const config: OaiConfig = {
|
const config: OaiConfig = {
|
||||||
max: {
|
max: {
|
||||||
listidentifiers: parseInt(env.get('OAI_LIST_SIZE', 100), 10),
|
listidentifiers: env.get('OAI_LIST_SIZE', 100),
|
||||||
listrecords: parseInt(env.get('OAI_LIST_SIZE', 100), 10),
|
listrecords: env.get('OAI_LIST_SIZE', 100),
|
||||||
},
|
},
|
||||||
workspacePath: 'workspace',
|
workspacePath: 'workspace',
|
||||||
redis: {
|
redis: {
|
||||||
|
|
2467
package-lock.json
generated
2467
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -58,7 +58,7 @@
|
||||||
"naive-ui": "^2.35.0",
|
"naive-ui": "^2.35.0",
|
||||||
"numeral": "^2.0.6",
|
"numeral": "^2.0.6",
|
||||||
"pinia": "^2.0.30",
|
"pinia": "^2.0.30",
|
||||||
"pino-pretty": "^10.3.1",
|
"pino-pretty": "^11.0.0",
|
||||||
"postcss-loader": "^7.3.0",
|
"postcss-loader": "^7.3.0",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"supertest": "^6.3.3",
|
"supertest": "^6.3.3",
|
||||||
|
@ -98,6 +98,7 @@
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"edge.js": "^6.0.1",
|
"edge.js": "^6.0.1",
|
||||||
"focus-trap": "^7.5.4",
|
"focus-trap": "^7.5.4",
|
||||||
|
"fs-extra": "^11.2.0",
|
||||||
"http-status-codes": "^2.2.0",
|
"http-status-codes": "^2.2.0",
|
||||||
"leaflet": "^1.9.3",
|
"leaflet": "^1.9.3",
|
||||||
"luxon": "^3.2.1",
|
"luxon": "^3.2.1",
|
||||||
|
@ -118,7 +119,7 @@
|
||||||
"#controllers/*": "./app/Controllers/*.js",
|
"#controllers/*": "./app/Controllers/*.js",
|
||||||
"#exceptions/*": "./app/Exceptions/*.js",
|
"#exceptions/*": "./app/Exceptions/*.js",
|
||||||
"#models/*": "./app/Models/*.js",
|
"#models/*": "./app/Models/*.js",
|
||||||
"#services/*": "./app/Services/*.js",
|
"#services/*": "./app/services/*.js",
|
||||||
"#listeners/*": "./app/listeners/*.js",
|
"#listeners/*": "./app/listeners/*.js",
|
||||||
"#events/*": "./app/events/*.js",
|
"#events/*": "./app/events/*.js",
|
||||||
"#middleware/*": "./app/Middleware/*.js",
|
"#middleware/*": "./app/Middleware/*.js",
|
||||||
|
|
|
@ -11,8 +11,7 @@ export type PbkdfConfig = {
|
||||||
rounds: number;
|
rounds: number;
|
||||||
saltSize?: number;
|
saltSize?: number;
|
||||||
version?: number;
|
version?: number;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
export class LaravelDriver implements HashDriverContract {
|
export class LaravelDriver implements HashDriverContract {
|
||||||
|
@ -25,7 +24,7 @@ export class LaravelDriver implements HashDriverContract {
|
||||||
rounds: 10,
|
rounds: 10,
|
||||||
saltSize: 16,
|
saltSize: 16,
|
||||||
version: 98,
|
version: 98,
|
||||||
...config
|
...config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,9 +134,8 @@ export class LaravelDriver implements HashDriverContract {
|
||||||
* Factory function to reference the driver
|
* Factory function to reference the driver
|
||||||
* inside the config file.
|
* inside the config file.
|
||||||
*/
|
*/
|
||||||
export function laravelDriver (config: PbkdfConfig): ManagerDriverFactory {
|
export function laravelDriver(config: PbkdfConfig): ManagerDriverFactory {
|
||||||
return () => {
|
return () => {
|
||||||
return new LaravelDriver(config)
|
return new LaravelDriver(config);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
133
providers/drive/drivers/local.ts
Normal file
133
providers/drive/drivers/local.ts
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
import fsExtra from 'fs-extra'
|
||||||
|
// import { RouterContract } from '@ioc:Adonis/Core/Route';
|
||||||
|
// import { Visibility, DriveFileStats, ContentHeaders, LocalDriverConfig, LocalDriverContract, DirectoryListingContract, LocalDriveListItem } from '@ioc:Adonis/Core/Drive';
|
||||||
|
|
||||||
|
import { CannotGetMetaDataException, CannotDeleteFileException, CannotListDirectoryException } from '../exceptions/index.js';
|
||||||
|
import PathPrefixer from '../path_prefixer/index.js';
|
||||||
|
import {
|
||||||
|
LocalDriverContract,
|
||||||
|
LocalDriverConfig,
|
||||||
|
DriverContract,
|
||||||
|
DriveListItem,
|
||||||
|
} from '../src/types/drive.js';
|
||||||
|
import { AsyncIterableArray } from '../src/iterable_array.js';
|
||||||
|
/**
|
||||||
|
* Local driver interacts with the local file system
|
||||||
|
*/
|
||||||
|
export class LocalDriver implements LocalDriverContract {
|
||||||
|
private diskName: string;
|
||||||
|
private config;
|
||||||
|
// private router;
|
||||||
|
// private routeName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to the underlying adapter. Which is
|
||||||
|
* fs-extra
|
||||||
|
*/
|
||||||
|
adapter: typeof fsExtra;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the driver
|
||||||
|
*/
|
||||||
|
name: 'local';
|
||||||
|
/**
|
||||||
|
* Path prefixer used for prefixing paths with disk root
|
||||||
|
*/
|
||||||
|
private prefixer;
|
||||||
|
|
||||||
|
// constructor(diskName: string, config: LocalDriverConfig, router: RouterContract);
|
||||||
|
constructor(diskName: string, config: LocalDriverConfig) {
|
||||||
|
this.diskName = diskName;
|
||||||
|
this.config = config;
|
||||||
|
// this.router = router;
|
||||||
|
// this.routeName = LocalFileServer_1.LocalFileServer.makeRouteName(this.diskName);
|
||||||
|
/**
|
||||||
|
* Reference to the underlying adapter. Which is
|
||||||
|
* fs-extra
|
||||||
|
*/
|
||||||
|
this.adapter = fsExtra;
|
||||||
|
/**
|
||||||
|
* Name of the driver
|
||||||
|
*/
|
||||||
|
this.name = 'local';
|
||||||
|
/**
|
||||||
|
* Path prefixer used for prefixing paths with disk root
|
||||||
|
*/
|
||||||
|
this.prefixer = PathPrefixer.fromPath(this.config.root); //root: '/storage/app/public',
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean to find if the location path exists or not
|
||||||
|
*/
|
||||||
|
exists(location: string): Promise<boolean>;
|
||||||
|
/**
|
||||||
|
* A boolean to find if the location path exists or not
|
||||||
|
*/
|
||||||
|
public async exists(location: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
return await this.adapter.pathExists(this.makePath(location));
|
||||||
|
} catch (error) {
|
||||||
|
throw CannotGetMetaDataException.invoke(location, 'exists', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make absolute path to a given location
|
||||||
|
*/
|
||||||
|
public makePath(location: string): string {
|
||||||
|
return this.prefixer.prefixPath(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a given location path
|
||||||
|
*/
|
||||||
|
// delete(location: string, ...args: any[]): Promise<void>;
|
||||||
|
public async delete(location: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this.adapter.remove(this.makePath(location));
|
||||||
|
} catch (error) {
|
||||||
|
throw CannotDeleteFileException.invoke(location, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a listing directory iterator for given location.
|
||||||
|
*/
|
||||||
|
public list(location: string): AsyncIterableArray<DriverContract, DriveListItem<any>> {
|
||||||
|
// public async list(location: string): Promise<DirectoryListing<DriverContract, DriveListItem<any>>> {
|
||||||
|
const fullPath = this.makePath(location); //'/storage/app/public/files/307'
|
||||||
|
|
||||||
|
// let dirListing: DirectoryListing<DriverContract, DriveListItem<any>> = new DirectoryListing(this, () => this.getListing(fullPath, location));
|
||||||
|
let dirListing: AsyncIterableArray<DriverContract, DriveListItem<any>> = new AsyncIterableArray(this, () => this.getListing(fullPath, location));
|
||||||
|
return dirListing;
|
||||||
|
// let listing: DriveListItem<fsExtra.Dirent>[] = await this.getListing(fullPath, location);
|
||||||
|
// let test = new DirectoryListing(this, listing);
|
||||||
|
// return test;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example usage
|
||||||
|
// private async *generateNumbers(): AsyncGenerator<number, void, unknown> {
|
||||||
|
// yield 1;
|
||||||
|
// yield 2;
|
||||||
|
// yield 3;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private async *getListing(fullPath: string, location: string): AsyncGenerator<DriveListItem<fsExtra.Dirent>, void, unknown> {
|
||||||
|
// private async getListing(fullPath: string, location: string): Promise<DriveListItem<fsExtra.Dirent>[]> {
|
||||||
|
try {
|
||||||
|
const dir = await this.adapter.opendir(fullPath);
|
||||||
|
const prefixer = this.prefixer.withStrippedPrefix(fullPath);
|
||||||
|
// const listing: DriveListItem<fsExtra.Dirent>[] = new Array();
|
||||||
|
for await (const dirent of dir) {
|
||||||
|
yield {
|
||||||
|
location: prefixer.prefixPath(dirent.name),
|
||||||
|
isFile: dirent.isFile(),
|
||||||
|
original: dirent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// return listing;
|
||||||
|
} catch (error) {
|
||||||
|
throw CannotListDirectoryException.invoke(location, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
73
providers/drive/exceptions/index.ts
Normal file
73
providers/drive/exceptions/index.ts
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// const utils_1 = require("@poppinss/utils");
|
||||||
|
// import * as utils_1 from "@poppinss/utils";
|
||||||
|
import { Exception } from '@poppinss/utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom exception for when a file cannot be deleted from a specified location
|
||||||
|
*/
|
||||||
|
export class CannotDeleteFileException extends Exception {
|
||||||
|
location: string;
|
||||||
|
original: any;
|
||||||
|
|
||||||
|
static invoke(location: string, original: any): CannotDeleteFileException {
|
||||||
|
const error = new this(`Cannot delete file at location "${location}"`, {
|
||||||
|
code: 'E_CANNOT_DELETE_FILE',
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
error.location = location;
|
||||||
|
error.original = original;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom exception for when file metadata cannot be retrieved
|
||||||
|
*/
|
||||||
|
export class CannotGetMetaDataException extends Exception {
|
||||||
|
location: string;
|
||||||
|
operation: string;
|
||||||
|
original: any;
|
||||||
|
|
||||||
|
static invoke(location: string, operation: string, original: any): CannotGetMetaDataException {
|
||||||
|
const error = new this(`Unable to retrieve the "${operation}" for file at location "${location}"`, {
|
||||||
|
code: 'E_CANNOT_GET_METADATA',
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
error.location = location;
|
||||||
|
error.operation = operation;
|
||||||
|
error.original = original;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given location is trying to traverse beyond the root path
|
||||||
|
*/
|
||||||
|
export class PathTraversalDetectedException extends Exception {
|
||||||
|
location: string;
|
||||||
|
static invoke(location: string) {
|
||||||
|
const error = new this(`Path traversal detected: "${location}"`, {
|
||||||
|
code: 'E_PATH_TRAVERSAL_DETECTED',
|
||||||
|
status: 500,
|
||||||
|
});
|
||||||
|
error.location = location;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unable to list directory contents of given location
|
||||||
|
*/
|
||||||
|
export class CannotListDirectoryException extends Exception {
|
||||||
|
location: string;
|
||||||
|
original: any;
|
||||||
|
static invoke(location: string, original: any): CannotListDirectoryException {
|
||||||
|
const error = new this(`Cannot list directory contents of location "${location}"`, {
|
||||||
|
status: 500,
|
||||||
|
code: 'E_CANNOT_LIST_DIRECTORY',
|
||||||
|
});
|
||||||
|
error.location = location;
|
||||||
|
error.original = original;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
96
providers/drive/path_prefixer/index.ts
Normal file
96
providers/drive/path_prefixer/index.ts
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import { slash } from '@poppinss/utils';
|
||||||
|
import { relative, normalize } from 'path';
|
||||||
|
import { PathTraversalDetectedException } from '../exceptions/index.js';
|
||||||
|
/**
|
||||||
|
* Path prefixer for resolving and prefixing paths for disk drivers
|
||||||
|
*/
|
||||||
|
export default class PathPrefixer {
|
||||||
|
/**
|
||||||
|
* Separator used for dividing path segments is always unix-style forward slash
|
||||||
|
*/
|
||||||
|
separator: '/';
|
||||||
|
/**
|
||||||
|
* Prefix used for path prefixing. Can be empty string for cloud drivers.
|
||||||
|
*/
|
||||||
|
prefix: string;
|
||||||
|
// constructor(prefix?: string);
|
||||||
|
|
||||||
|
constructor(prefix: string = '') {
|
||||||
|
/**
|
||||||
|
* Separator used for dividing path segments is always unix-style forward slash
|
||||||
|
*/
|
||||||
|
this.separator = '/';
|
||||||
|
// strip slashes from the end of the prefix
|
||||||
|
this.prefix = prefix.replace(/\/+$/g, '');
|
||||||
|
// always end prefix with separator if it is not empty
|
||||||
|
if (this.prefix !== '' || prefix === this.separator) {
|
||||||
|
this.prefix += this.separator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize given path to always use `/` as separator and resolve relative paths using `.` and `..`.
|
||||||
|
* It also guards against path traversal beyond the root.
|
||||||
|
*/
|
||||||
|
normalizePath(path: string): string {
|
||||||
|
// const converted = (0, utils_1.slash)(path);
|
||||||
|
const converted = slash(path);
|
||||||
|
const parts = [];
|
||||||
|
for (const part of converted.split(this.separator)) {
|
||||||
|
if (['', '.'].includes(part)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (part === '..') {
|
||||||
|
// if we are traversing beyond the root
|
||||||
|
if (parts.length === 0) {
|
||||||
|
throw PathTraversalDetectedException.invoke(converted);
|
||||||
|
}
|
||||||
|
parts.pop();
|
||||||
|
} else {
|
||||||
|
parts.push(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parts.join(this.separator);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Ruturns normalized and prefixed location path.
|
||||||
|
*/
|
||||||
|
prefixPath(location: string): string {
|
||||||
|
return this.prefix + this.normalizePath(location);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Ruturns normalized and prefixed location path for directory so always ending with slash.
|
||||||
|
* Useful for cloud drivers prefix when listitng files.
|
||||||
|
*/
|
||||||
|
prefixDirectoryPath(location: string): string {
|
||||||
|
return this.prefixPath(location) + this.separator;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns normalized path after stripping the current prefix from it.
|
||||||
|
* It is a reverse operation of `prefixPath`.
|
||||||
|
*/
|
||||||
|
stripPrefix(location: string): string {
|
||||||
|
// const path = (0, path_1.relative)(this.prefix, (0, utils_1.slash)(location));
|
||||||
|
const path = relative(this.prefix, slash(location));
|
||||||
|
return this.normalizePath(path);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a new instance of `PathPrefixer` which is using as prefix stripped prefix from path of current `PathPrefixer`.
|
||||||
|
*/
|
||||||
|
withStrippedPrefix(path: string): PathPrefixer {
|
||||||
|
return new PathPrefixer(this.stripPrefix(path));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a new instance of `PathPrefixer` which is using as prefix current prefix merged with provided prefix.
|
||||||
|
*/
|
||||||
|
withPrefix(prefix: string): PathPrefixer {
|
||||||
|
return new PathPrefixer(this.prefixPath(prefix));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns a new instance of `PathPrefixer` which is using as prefix provided normalized path.
|
||||||
|
*/
|
||||||
|
static fromPath(path: string): PathPrefixer {
|
||||||
|
// return new this((0, utils_1.slash)((0, path_1.normalize)(path)));
|
||||||
|
return new this(slash(normalize(path)));
|
||||||
|
}
|
||||||
|
}
|
62
providers/drive/provider/drive_provider.ts
Normal file
62
providers/drive/provider/drive_provider.ts
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import type { ApplicationService } from '@adonisjs/core/types';
|
||||||
|
import { RuntimeException } from '@poppinss/utils';
|
||||||
|
// import DriveManager from '../src/drive_manager.js';
|
||||||
|
import { DriveConfig } from '../src/types/drive.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class DriveProvider {
|
||||||
|
constructor(protected app: ApplicationService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register bindings to the container
|
||||||
|
*/
|
||||||
|
async register() {
|
||||||
|
const { default: DriveManager } = await import('../src/drive_manager.js');
|
||||||
|
this.app.container.singleton(DriveManager, async () => {
|
||||||
|
// 1. import the oai configuration
|
||||||
|
// const ttl: number = 86400;
|
||||||
|
const config: DriveConfig = this.app.config.get('drive');
|
||||||
|
// const config: DriveConfig | null = await configProvider.resolve(this.app, driveConfigProvider);
|
||||||
|
// const vite = await this.app.container.make("vite");
|
||||||
|
if (!config) {
|
||||||
|
throw new RuntimeException('Invalid "config/drive.ts" file. Make sure you are using the "defineConfig" method');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DriveManager(this.app, config);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register drive with the container
|
||||||
|
*/
|
||||||
|
// registerDrive() {
|
||||||
|
// this.app.container.singleton('Adonis/Core/Drive', () => {
|
||||||
|
// const { DriveManager } = require('../src/DriveManager');
|
||||||
|
// const Router = this.app.container.resolveBinding('Adonis/Core/Route');
|
||||||
|
// const Config = this.app.container.resolveBinding('Adonis/Core/Config');
|
||||||
|
// const Logger = this.app.container.resolveBinding('Adonis/Core/Logger');
|
||||||
|
// return new DriveManager(this.app, Router, Logger, Config.get('drive'));
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The container bindings have booted
|
||||||
|
*/
|
||||||
|
async boot() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application has been booted
|
||||||
|
*/
|
||||||
|
async start() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The process has been started
|
||||||
|
*/
|
||||||
|
async ready() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preparing to shutdown the app
|
||||||
|
*/
|
||||||
|
async shutdown() {}
|
||||||
|
}
|
154
providers/drive/src/drive_manager.ts
Normal file
154
providers/drive/src/drive_manager.ts
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
import type { ApplicationService } from '@adonisjs/core/types';
|
||||||
|
import { Manager } from '@poppinss/manager';
|
||||||
|
import { Exception } from '@poppinss/utils';
|
||||||
|
import { DriverContract, DriversList, DriveConfig, DriveListItem, DirectoryListingContract, LocalDriverConfig } from './types/drive.js';
|
||||||
|
// import { LocalDriver } from './drivers/local.js';
|
||||||
|
import { LocalDriver } from '../drivers/local.js';
|
||||||
|
|
||||||
|
type test = {
|
||||||
|
[P in keyof DriversList]: DriversList[P];
|
||||||
|
};
|
||||||
|
// type DriveMappings = {
|
||||||
|
// local: string
|
||||||
|
// fake: string
|
||||||
|
// }
|
||||||
|
|
||||||
|
// interface DriversList {
|
||||||
|
// local: {
|
||||||
|
// implementation: LocalDriverContract;
|
||||||
|
// config: LocalDriverConfig;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type DriverConfig = {
|
||||||
|
// disk: keyof DriversList
|
||||||
|
// disks: {
|
||||||
|
// [K in keyof DriversList]: any
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const mailerConfig: DriveConfig = {
|
||||||
|
// disk: 'local',
|
||||||
|
|
||||||
|
// disks: {
|
||||||
|
// local: {
|
||||||
|
// driver: 'local',
|
||||||
|
// root: '',
|
||||||
|
// visibility: '',
|
||||||
|
// serveFiles: false,
|
||||||
|
// basePath: '',
|
||||||
|
// },
|
||||||
|
|
||||||
|
// // 'fake': {
|
||||||
|
// // driver: 'fake',
|
||||||
|
// // root: '',
|
||||||
|
// // },
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
export default class DriveManager extends Manager<
|
||||||
|
ApplicationService,
|
||||||
|
DriverContract,
|
||||||
|
DriverContract,
|
||||||
|
{
|
||||||
|
[P in keyof DriversList]: DriversList[P]['implementation'];
|
||||||
|
}
|
||||||
|
> {
|
||||||
|
protected singleton = true;
|
||||||
|
private config;
|
||||||
|
/**
|
||||||
|
* Find if drive is ready to be used
|
||||||
|
*/
|
||||||
|
private isReady: boolean;
|
||||||
|
|
||||||
|
protected getDefaultMappingName() {
|
||||||
|
return this.config.disk; // "local"
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getMappingConfig(mappingName: string) {
|
||||||
|
return this.config.disks[mappingName];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getMappingDriver(mappingName: string) {
|
||||||
|
return this.config.disks[mappingName].driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make instance of the local driver
|
||||||
|
*/
|
||||||
|
protected createLocal(diskName: keyof DriversList, config: LocalDriverConfig) {
|
||||||
|
// const { LocalDriver } = await import('../drivers/local.js');
|
||||||
|
return new LocalDriver(diskName, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(application: ApplicationService, config: DriveConfig) {
|
||||||
|
super(application);
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find if drive is ready to be used
|
||||||
|
*/
|
||||||
|
this.isReady = false;
|
||||||
|
|
||||||
|
this.validateConfig();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Validate config
|
||||||
|
*/
|
||||||
|
private validateConfig() {
|
||||||
|
if (!this.config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// const validator = new utils_1.ManagerConfigValidator(this.config, 'drive', 'config/drive');
|
||||||
|
// validator.validateDefault('disk');
|
||||||
|
// validator.validateList('disks', 'disk');
|
||||||
|
this.isReady = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve instance for a disk
|
||||||
|
*/
|
||||||
|
use(disk?: keyof test): DriversList[keyof DriversList]['implementation'] {
|
||||||
|
if (!this.isReady) {
|
||||||
|
throw new Exception('Missing configuration for drive. Visit https://bit.ly/2WnR5j9 for setup instructions', {
|
||||||
|
status: 500,
|
||||||
|
code: 'E_MISSING_DRIVE_CONFIG',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
disk = disk || this.getDefaultMappingName();
|
||||||
|
// if (this.fakeDrive.isFaked(disk)) {
|
||||||
|
// return this.fakeDrive.use(disk);
|
||||||
|
// }
|
||||||
|
return super.use(disk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean to find if the location path exists or not
|
||||||
|
*/
|
||||||
|
exists(location: string): Promise<boolean> {
|
||||||
|
const driver = this.use();
|
||||||
|
return driver.exists(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a given location path
|
||||||
|
*/
|
||||||
|
delete(location: string): Promise<void> {
|
||||||
|
const driver = this.use();
|
||||||
|
return driver.delete(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a listing directory iterator for given location.
|
||||||
|
*/
|
||||||
|
list(location: string): DirectoryListingContract<DriverContract, DriveListItem> {
|
||||||
|
const driver = this.use();
|
||||||
|
if (typeof driver.list !== 'function') {
|
||||||
|
throw new Exception(`List is not supported by the "${driver.name}" driver.`, {
|
||||||
|
status: 500,
|
||||||
|
code: 'E_LIST_NOT_SUPPORTED',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return driver.list(location);
|
||||||
|
}
|
||||||
|
}
|
68
providers/drive/src/iterable_array.ts
Normal file
68
providers/drive/src/iterable_array.ts
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import { DriveListItem, DriverContract } from './types/drive.js';
|
||||||
|
// import * as fsExtra from 'fs-extra';
|
||||||
|
import { DirectoryListingContract } from './types/drive.js';
|
||||||
|
|
||||||
|
// class AsyncIterableArray<T> implements AsyncIterable<T> {
|
||||||
|
export class AsyncIterableArray<SpecificDriver extends DriverContract, T extends DriveListItem>
|
||||||
|
implements DirectoryListingContract<SpecificDriver, T>
|
||||||
|
{
|
||||||
|
public driver: SpecificDriver;
|
||||||
|
private generator: () => AsyncGenerator<T, void, unknown>;
|
||||||
|
// private generator: () => AsyncGenerator<T, void, unknown>;
|
||||||
|
private chain: any[];
|
||||||
|
|
||||||
|
constructor(driver: SpecificDriver, generator: () => AsyncGenerator<T, void, unknown>) {
|
||||||
|
// constructor(driver: SpecificDriver, listing: T) {
|
||||||
|
this.driver = driver;
|
||||||
|
this.generator = generator;
|
||||||
|
/**
|
||||||
|
* Functions chain to be executed for transforming generated listing iterable
|
||||||
|
*/
|
||||||
|
this.chain = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert directory listing to array.
|
||||||
|
*/
|
||||||
|
// public async toArray(): Promise<T[]> {
|
||||||
|
// const arr = [];
|
||||||
|
// for await (const item of this.toIterable()) {
|
||||||
|
// arr.push(item);
|
||||||
|
// }
|
||||||
|
// return arr;
|
||||||
|
// }
|
||||||
|
async toArray(): Promise<T[]> {
|
||||||
|
const arr: T[] = [];
|
||||||
|
for await (const item of this) {
|
||||||
|
arr.push(item);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method that returns the default async iterator for an object.
|
||||||
|
*/
|
||||||
|
public async *[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
||||||
|
// yield* this.toIterable();
|
||||||
|
for await (const item of this.generator.call(this.driver)) {
|
||||||
|
yield item;
|
||||||
|
}
|
||||||
|
// yield 1
|
||||||
|
// // await something()
|
||||||
|
// yield 2
|
||||||
|
// // await somethingElse()
|
||||||
|
// yield 3
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the final async iterable after passing directory listing through chain of piping functions modifying the output.
|
||||||
|
*/
|
||||||
|
public toIterable(): AsyncIterable<T> {
|
||||||
|
const generator = this.generator.call(this.driver);
|
||||||
|
const iterable = this.chain.reduce((prevIterable, currentIterable) => {
|
||||||
|
return currentIterable.call(this.driver, prevIterable);
|
||||||
|
}, generator);
|
||||||
|
|
||||||
|
return iterable;
|
||||||
|
}
|
||||||
|
}
|
5
providers/drive/src/types/define_config.ts
Normal file
5
providers/drive/src/types/define_config.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { DriveConfig } from "./drive.js";
|
||||||
|
|
||||||
|
export function defineConfig(config: DriveConfig): DriveConfig {
|
||||||
|
return config;
|
||||||
|
}
|
176
providers/drive/src/types/drive.ts
Normal file
176
providers/drive/src/types/drive.ts
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
import fsExtra from 'fs-extra';
|
||||||
|
import { LocalDriver } from '#providers/drive/drivers/local';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List item returned by the drive drivers
|
||||||
|
*/
|
||||||
|
export interface DriveListItem<T = any> {
|
||||||
|
/**
|
||||||
|
* Location of list item on disk which can be used in driver methods
|
||||||
|
*/
|
||||||
|
location: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag to know if item represents file or directory
|
||||||
|
*/
|
||||||
|
isFile: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Original list item returned from underlying driver
|
||||||
|
*/
|
||||||
|
original: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* List item returned from local disk driver
|
||||||
|
*/
|
||||||
|
export interface LocalDriveListItem extends DriveListItem<fsExtra.Dirent> {}
|
||||||
|
|
||||||
|
export interface DirectoryListingContract<Driver extends DriverContract, T> extends AsyncIterable<T> {
|
||||||
|
/**
|
||||||
|
* Reference to the driver for which the listing was created.
|
||||||
|
*/
|
||||||
|
driver: Driver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter generated items of listing with the given predicate function.
|
||||||
|
*/
|
||||||
|
// filter(predicate: (item: T, index: number, driver: Driver) => Promise<boolean> | boolean): DirectoryListingContract<Driver, T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform generated items of listing with the given mapper function.
|
||||||
|
*/
|
||||||
|
// map<M>(mapper: (item: T, index: number, driver: Driver) => Promise<M> | M): DirectoryListingContract<Driver, M>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do recursive listing of items. Without the next function it will do listing of leaf nodes only.
|
||||||
|
* For advanced usage you can pass the next function which will get as parameter current item and it should
|
||||||
|
* return the next location for list or null if the recursion should stop and yield the current item.
|
||||||
|
* For advanced usage you can also limit the depth of recursion using the second argument of next function.
|
||||||
|
*/
|
||||||
|
// recursive(
|
||||||
|
// next?: (current: T, depth: number, driver: Driver) => Promise<string | null> | string | null,
|
||||||
|
// ): DirectoryListingContract<Driver, T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a piping chain function which gets the current async iterable and returns
|
||||||
|
* new async iterable with modified directory listing output.
|
||||||
|
* Function this is bound to instance of driver for which the listing is generated.
|
||||||
|
* This allows using async generator functions and reference the driver methods easily.
|
||||||
|
* Piping will always return clone of the current instance and add the function
|
||||||
|
* to the chain of new cloned instance only to prevent side effects.
|
||||||
|
*/
|
||||||
|
// pipe<U>(fn: (this: Driver, source: AsyncIterable<T>) => AsyncIterable<U>): DirectoryListingContract<Driver, U>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the final async iterable after passing directory listing through chain of piping functions modifying the output.
|
||||||
|
*/
|
||||||
|
toIterable(): AsyncIterable<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert directory listing to array.
|
||||||
|
*/
|
||||||
|
toArray(): Promise<T[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shape of the generic driver
|
||||||
|
*/
|
||||||
|
export interface DriverContract {
|
||||||
|
/**
|
||||||
|
* Name of the driver
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean to find if the location path exists or not
|
||||||
|
*/
|
||||||
|
exists(location: string): Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a given location path
|
||||||
|
*/
|
||||||
|
delete(location: string): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a listing directory iterator for given location.
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
list?(location: string): DirectoryListingContract<DriverContract, DriveListItem>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shape of the local disk driver
|
||||||
|
*/
|
||||||
|
export interface LocalDriverContract extends DriverContract {
|
||||||
|
name: 'local';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to the underlying adapter. Which is fs-extra
|
||||||
|
*/
|
||||||
|
adapter: typeof fsExtra;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make path to a given file location
|
||||||
|
*/
|
||||||
|
makePath(location: string): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// interface LocalDriverContract {
|
||||||
|
// delete(): Promise<void>;
|
||||||
|
// }
|
||||||
|
export type LocalDriverConfig = {
|
||||||
|
driver: 'local';
|
||||||
|
// visibility: Visibility
|
||||||
|
root: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base path is always required when "serveFiles = true"
|
||||||
|
*/
|
||||||
|
serveFiles?: boolean;
|
||||||
|
basePath?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of registered drivers. Drivers shipped via other packages
|
||||||
|
* should merge drivers to this interface
|
||||||
|
*/
|
||||||
|
export interface DriversList {
|
||||||
|
// [key: string]: {implementation : DriverContract, config: {}};
|
||||||
|
local: {
|
||||||
|
implementation: LocalDriver;
|
||||||
|
config: {
|
||||||
|
driver: string;
|
||||||
|
visibility: string;
|
||||||
|
root: string;
|
||||||
|
serveFiles: boolean;
|
||||||
|
basePath: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// [key: string]: DriverContract;
|
||||||
|
// local: LocalDriver;
|
||||||
|
// fake: {
|
||||||
|
// implementation: LocalDriverContract;
|
||||||
|
// config: LocalDriverConfig;
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DriveConfig = {
|
||||||
|
disk: keyof DriversList;
|
||||||
|
// disks: {
|
||||||
|
// [name: string]: {
|
||||||
|
// driver: DriverContract;
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
disks: {
|
||||||
|
[name: string]: {
|
||||||
|
[K in keyof DriversList]: DriversList[K]['config'] & {
|
||||||
|
driver: K;
|
||||||
|
visibility: string;
|
||||||
|
root: string;
|
||||||
|
serveFiles: boolean;
|
||||||
|
basePath: string;
|
||||||
|
};
|
||||||
|
}[keyof DriversList];
|
||||||
|
};
|
||||||
|
};
|
|
@ -26,6 +26,8 @@
|
||||||
"assets/resources_js_Pages_Editor_Dataset_Publish_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Publish_vue.js",
|
"assets/resources_js_Pages_Editor_Dataset_Publish_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Publish_vue.js",
|
||||||
"assets/resources_js_Pages_Editor_Dataset_Receive_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Receive_vue.js",
|
"assets/resources_js_Pages_Editor_Dataset_Receive_vue.js": "http://localhost:8080/assets/resources_js_Pages_Editor_Dataset_Receive_vue.js",
|
||||||
"assets/resources_js_Pages_Error_vue.js": "http://localhost:8080/assets/resources_js_Pages_Error_vue.js",
|
"assets/resources_js_Pages_Error_vue.js": "http://localhost:8080/assets/resources_js_Pages_Error_vue.js",
|
||||||
|
"assets/resources_js_Pages_Errors_ServerError_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_ServerError_vue.js",
|
||||||
|
"assets/resources_js_Pages_Errors_not_found_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_not_found_vue.js",
|
||||||
"assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.css": "http://localhost:8080/assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.css",
|
"assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.css": "http://localhost:8080/assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.css",
|
||||||
"assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.js": "http://localhost:8080/assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.js",
|
"assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.js": "http://localhost:8080/assets/resources_js_Pages_Map_vue-resources_js_Components_Map_draw_component_vue-resources_js_Compon-b0925c.js",
|
||||||
"assets/resources_js_Pages_ProfileView_vue.js": "http://localhost:8080/assets/resources_js_Pages_ProfileView_vue.js",
|
"assets/resources_js_Pages_ProfileView_vue.js": "http://localhost:8080/assets/resources_js_Pages_ProfileView_vue.js",
|
||||||
|
@ -42,14 +44,15 @@
|
||||||
"assets/resources_js_Pages_Submitter_Dataset_Release_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Release_vue.js",
|
"assets/resources_js_Pages_Submitter_Dataset_Release_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Dataset_Release_vue.js",
|
||||||
"assets/resources_js_Pages_Submitter_Person_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Person_Index_vue.js",
|
"assets/resources_js_Pages_Submitter_Person_Index_vue.js": "http://localhost:8080/assets/resources_js_Pages_Submitter_Person_Index_vue.js",
|
||||||
"assets/resources_js_Pages_register-view_register-view-component_vue.js": "http://localhost:8080/assets/resources_js_Pages_register-view_register-view-component_vue.js",
|
"assets/resources_js_Pages_register-view_register-view-component_vue.js": "http://localhost:8080/assets/resources_js_Pages_register-view_register-view-component_vue.js",
|
||||||
"assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_j-02166b.js": "http://localhost:8080/assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_j-02166b.js",
|
"assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js": "http://localhost:8080/assets/vendors-node_modules_mdi_js_mdi_js-node_modules_vue-loader_dist_exportHelper_js.js",
|
||||||
|
"assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js": "http://localhost:8080/assets/vendors-node_modules_focus-trap_dist_focus-trap_esm_js-node_modules_notiwind_dist_index_esm_js.js",
|
||||||
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js",
|
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_utils_js.js",
|
||||||
"assets/vendors-node_modules_leaflet_src_control_Control_Attribution_js-node_modules_leaflet_src_laye-fbc1b4.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_src_control_Control_Attribution_js-node_modules_leaflet_src_laye-fbc1b4.js",
|
"assets/vendors-node_modules_leaflet_src_control_Control_Attribution_js-node_modules_leaflet_src_laye-fbc1b4.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_src_control_Control_Attribution_js-node_modules_leaflet_src_laye-fbc1b4.js",
|
||||||
"assets/vendors-node_modules_buffer_index_js-node_modules_leaflet_src_layer_tile_TileLayer_WMS_js-nod-e7bc71.js": "http://localhost:8080/assets/vendors-node_modules_buffer_index_js-node_modules_leaflet_src_layer_tile_TileLayer_WMS_js-nod-e7bc71.js",
|
"assets/vendors-node_modules_buffer_index_js-node_modules_leaflet_src_layer_tile_TileLayer_WMS_js-nod-e7bc71.js": "http://localhost:8080/assets/vendors-node_modules_buffer_index_js-node_modules_leaflet_src_layer_tile_TileLayer_WMS_js-nod-e7bc71.js",
|
||||||
"assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js": "http://localhost:8080/assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js",
|
"assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js": "http://localhost:8080/assets/vendors-node_modules_numeral_numeral_js-node_modules_chart_js_dist_chart_js.js",
|
||||||
"assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js",
|
"assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js": "http://localhost:8080/assets/vendors-node_modules_leaflet_dist_leaflet-src_js-node_modules_leaflet_src_layer_LayerGroup_js.js",
|
||||||
"assets/vendors-node_modules_toastify-js_src_toastify_js.js": "http://localhost:8080/assets/vendors-node_modules_toastify-js_src_toastify_js.js",
|
"assets/vendors-node_modules_toastify-js_src_toastify_js.js": "http://localhost:8080/assets/vendors-node_modules_toastify-js_src_toastify_js.js",
|
||||||
"assets/resources_js_Components_BaseButton_vue-resources_js_Components_BaseDivider_vue-resources_js_C-0c87b5.js": "http://localhost:8080/assets/resources_js_Components_BaseButton_vue-resources_js_Components_BaseDivider_vue-resources_js_C-0c87b5.js",
|
"assets/resources_js_Stores_main_ts-resources_js_Components_BaseButton_vue-resources_js_Components_Ba-dd870d.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseButton_vue-resources_js_Components_Ba-dd870d.js",
|
||||||
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css",
|
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.css",
|
||||||
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js",
|
"assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js": "http://localhost:8080/assets/resources_js_Components_SectionMain_vue-resources_js_Layouts_LayoutAuthenticated_vue.js",
|
||||||
"assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js",
|
"assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js": "http://localhost:8080/assets/resources_js_Components_BaseButtons_vue-resources_js_Components_FormControl_vue-resources_js_-d830d6.js",
|
||||||
|
@ -80,5 +83,10 @@
|
||||||
"assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png",
|
"assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png",
|
||||||
"assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png",
|
"assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png",
|
||||||
"assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png",
|
"assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png",
|
||||||
"assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg"
|
"assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg",
|
||||||
|
"assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js": "http://localhost:8080/assets/vendors-node_modules_vue-facing-decorator_dist_esm_index_js-node_modules_vue-facing-decorator-818045.js",
|
||||||
|
"assets/resources_js_Pages_Errors_App_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_App_vue.js",
|
||||||
|
"assets/resources_js_Pages_Errors_ServerError2_vue.js": "http://localhost:8080/assets/resources_js_Pages_Errors_ServerError2_vue.js",
|
||||||
|
"assets/resources_js_Components_BaseButton_vue.js": "http://localhost:8080/assets/resources_js_Components_BaseButton_vue.js",
|
||||||
|
"assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js": "http://localhost:8080/assets/resources_js_Stores_main_ts-resources_js_Components_BaseDivider_vue-resources_js_Components_C-b45805.js"
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
<script setup>
|
<script lang="ts" setup>
|
||||||
import { Link } from '@inertiajs/vue3';
|
import { Link } from '@inertiajs/vue3';
|
||||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -29,17 +28,15 @@ const props = defineProps({
|
||||||
// null
|
// null
|
||||||
// total:
|
// total:
|
||||||
// 19
|
// 19
|
||||||
const nextPageLink = computed(() => {
|
const calculateNextPageLink = computed(() => {
|
||||||
let url = new URL(document.location);
|
let url = new URL(document.location.href);
|
||||||
url.searchParams.set('page', props.data.currentPage + 1);
|
url.searchParams.set('page', String(props.data.currentPage + 1));
|
||||||
return url.href;
|
return url.href;
|
||||||
// return url + '&page=' + (Number(props.data.currentPage) + 1);
|
|
||||||
});
|
});
|
||||||
const prevPageLink = computed(() => {
|
const calculatePrevPageLink = computed(() => {
|
||||||
let url = new URL(document.location);
|
let url = new URL(document.location.href);
|
||||||
url.searchParams.set('page', props.data.currentPage - 1);
|
url.searchParams.set('page', String(props.data.currentPage - 1));
|
||||||
return url.href;
|
return url.href;
|
||||||
// return url + '&page=' + (props.data.currentPage - 1);
|
|
||||||
});
|
});
|
||||||
const toPage = computed(() => {
|
const toPage = computed(() => {
|
||||||
let currentPage = props.data.currentPage;
|
let currentPage = props.data.currentPage;
|
||||||
|
@ -58,54 +55,26 @@ const fromPage = computed(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- currentPage:
|
|
||||||
1
|
|
||||||
firstPage:
|
|
||||||
1
|
|
||||||
firstPageUrl:
|
|
||||||
'/?page=1'
|
|
||||||
lastPage:
|
|
||||||
3
|
|
||||||
lastPageUrl:
|
|
||||||
'/?page=3'
|
|
||||||
nextPageUrl:
|
|
||||||
'/?page=2'
|
|
||||||
perPage:
|
|
||||||
5
|
|
||||||
previousPageUrl:
|
|
||||||
null
|
|
||||||
total:
|
|
||||||
15 -->
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- <nav v-if="data.links.length > 3" -->
|
<!-- <nav v-if="data.links.length > 3" -->
|
||||||
<nav v-if="data.total > 3" role="navigation" aria-label="Pagination Navigation" class="flex items-center justify-between">
|
<nav v-if="data.total > 3" role="navigation" aria-label="Pagination Navigation"
|
||||||
|
class="flex items-center justify-between">
|
||||||
<div class="flex justify-between flex-1 sm:hidden">
|
<div class="flex justify-between flex-1 sm:hidden">
|
||||||
<span
|
<span v-if="data.currentPage <= 1"
|
||||||
v-if="data.currentPage <= 1"
|
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md">
|
||||||
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md"
|
|
||||||
>
|
|
||||||
Previous
|
Previous
|
||||||
</span>
|
</span>
|
||||||
<Link
|
<Link v-else :href="data.previousPageUrl"
|
||||||
v-else
|
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
|
||||||
:href="data.previousPageUrl"
|
|
||||||
class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
|
||||||
>
|
|
||||||
Previous
|
Previous
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link
|
<Link v-if="data.currentPage < data.lastPage" :href="data.nextPageUrl"
|
||||||
v-if="data.currentPage < data.lastPage"
|
class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
|
||||||
:href="data.nextPageUrl"
|
|
||||||
class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150"
|
|
||||||
>
|
|
||||||
Next
|
Next
|
||||||
</Link>
|
</Link>
|
||||||
<span
|
<span v-else
|
||||||
v-else
|
class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md">
|
||||||
class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md"
|
|
||||||
>
|
|
||||||
Next
|
Next
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -128,32 +97,23 @@ total:
|
||||||
<span v-if="props.data.currentPage <= 1" aria-disabled="true" aria-label="Previous">
|
<span v-if="props.data.currentPage <= 1" aria-disabled="true" aria-label="Previous">
|
||||||
<span
|
<span
|
||||||
class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-l-md leading-5"
|
class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-l-md leading-5"
|
||||||
aria-hidden="true"
|
aria-hidden="true">
|
||||||
>
|
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path
|
<path fill-rule="evenodd"
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
|
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
|
||||||
clip-rule="evenodd"
|
clip-rule="evenodd" />
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- <Link v-else :href="data.previousPageUrl" rel="prev" -->
|
<!-- <Link v-else :href="data.previousPageUrl" rel="prev" -->
|
||||||
<Link
|
<Link v-else :href="calculatePrevPageLink" rel="prev"
|
||||||
v-else
|
|
||||||
:href="prevPageLink"
|
|
||||||
rel="prev"
|
|
||||||
class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-l-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
|
class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-l-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
|
||||||
aria-label="Previous"
|
aria-label="Previous">
|
||||||
>
|
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path
|
<path fill-rule="evenodd"
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
|
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
|
||||||
clip-rule="evenodd"
|
clip-rule="evenodd" />
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
|
@ -169,35 +129,26 @@ total:
|
||||||
|
|
||||||
<Link v-else :key="`link-${key}`" :href="link.url" v-html="link.label" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150" aria-label="`Go to page ${link.label}`" />
|
<Link v-else :key="`link-${key}`" :href="link.url" v-html="link.label" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150" aria-label="`Go to page ${link.label}`" />
|
||||||
</template>
|
</template>
|
||||||
</template> -->
|
</template> -->
|
||||||
|
|
||||||
<Link
|
<Link v-if="props.data.currentPage < props.data.lastPage" :href="calculateNextPageLink" rel="next"
|
||||||
v-if="props.data.currentPage < props.data.lastPage"
|
|
||||||
:href="nextPageLink"
|
|
||||||
rel="next"
|
|
||||||
class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
|
class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:ring ring-gray-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150"
|
||||||
aria-label="Next"
|
aria-label="Next">
|
||||||
>
|
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path
|
<path fill-rule="evenodd"
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||||
clip-rule="evenodd"
|
clip-rule="evenodd" />
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
</Link>
|
</Link>
|
||||||
<!-- else disabled link -->
|
<!-- else disabled link -->
|
||||||
<span v-else aria-disabled="true" aria-label="Next">
|
<span v-else aria-disabled="true" aria-label="Next">
|
||||||
<span
|
<span
|
||||||
class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-r-md leading-5"
|
class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-r-md leading-5"
|
||||||
aria-hidden="true"
|
aria-hidden="true">
|
||||||
>
|
|
||||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
|
||||||
<path
|
<path fill-rule="evenodd"
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
||||||
clip-rule="evenodd"
|
clip-rule="evenodd" />
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, ComputedRef } from 'vue';
|
import { computed, ComputedRef } from 'vue';
|
||||||
import { Link, usePage } from '@inertiajs/vue3';
|
import { Link, usePage } from '@inertiajs/vue3';
|
||||||
// import { Link } from '@inertiajs/inertia-vue3';
|
// import { Link } from '@inertiajs/inertia-vue3';
|
||||||
|
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { mdiMinus, mdiPlus } from '@mdi/js';
|
import { mdiMinus, mdiPlus } from '@mdi/js';
|
||||||
import { getButtonColor } from '@/colors.js';
|
import { getButtonColor } from '@/colors.js';
|
||||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { stardust } from '@eidellev/adonis-stardust/client';
|
||||||
import { mdiLogout, mdiClose } from '@mdi/js';
|
import { mdiLogout, mdiClose } from '@mdi/js';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { LayoutService } from '@/Stores/layout';
|
import { LayoutService } from '@/Stores/layout';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import AsideMenuList from '@/Components/AsideMenuList.vue';
|
import AsideMenuList from '@/Components/AsideMenuList.vue';
|
||||||
import AsideMenuItem from '@/Components/AsideMenuItem.vue';
|
import AsideMenuItem from '@/Components/AsideMenuItem.vue';
|
||||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, defineProps } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { usePage } from '@inertiajs/vue3';
|
import { usePage } from '@inertiajs/vue3';
|
||||||
import NotificationBarInCard from '@/Components/NotificationBarInCard.vue';
|
import NotificationBarInCard from '@/Components/NotificationBarInCard.vue';
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-slate-100 py-3 px-6 flex justify-between items-center mb-6">
|
<div class="bg-slate-100 py-3 px-6 flex justify-between items-center mb-6">
|
||||||
<div class="flex items-center space-x-6">
|
<div class="flex items-center space-x-6">
|
||||||
<h3 class="font-bold">AdonisJS InertiaJS Example</h3>
|
<h3 class="font-bold">TethysCloud Errors</h3>
|
||||||
<nav class="flex items-center text-sm">
|
<nav class="flex items-center text-sm">
|
||||||
<Link href="/app">Home</Link>
|
<Link href="/apps/dashboard">Home</Link>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center space-x-6 text-sm">
|
<!-- <div class="flex items-center space-x-6 text-sm">
|
||||||
<Link href="/app/login">Login</Link>
|
<Link href="/app/login">Login</Link>
|
||||||
<Link href="/app/register">Register</Link>
|
<Link href="/app/register">Register</Link>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// import * as util from '../core/utilities';
|
// import * as util from '../core/utilities';
|
||||||
import { EventEmitter } from './EventEmitter.js';
|
import { EventEmitter } from './EventEmitter.js';
|
||||||
import type { Map } from 'leaflet/src/map/index';
|
import type { Map } from 'leaflet/src/map/index.js';
|
||||||
|
// import type { Map } from 'leaflet';
|
||||||
|
|
||||||
export abstract class Control<T> extends EventEmitter<T> {
|
export abstract class Control<T> extends EventEmitter<T> {
|
||||||
// @section
|
// @section
|
||||||
|
@ -8,7 +9,7 @@ export abstract class Control<T> extends EventEmitter<T> {
|
||||||
public options = {
|
public options = {
|
||||||
position: 'topright',
|
position: 'topright',
|
||||||
};
|
};
|
||||||
protected _map;
|
protected _map: Map;
|
||||||
protected _container;
|
protected _container;
|
||||||
|
|
||||||
// constructor(defaults?) {
|
// constructor(defaults?) {
|
||||||
|
@ -28,7 +29,7 @@ export abstract class Control<T> extends EventEmitter<T> {
|
||||||
return this._container;
|
return this._container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract onRemove(map): void;
|
public abstract onRemove(map: Map): void;
|
||||||
|
|
||||||
public abstract onAdd(map: any): HTMLElement;
|
public abstract onAdd(map: any): HTMLElement;
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ export abstract class Control<T> extends EventEmitter<T> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeFrom(map) {
|
public removeFrom(map: Map) {
|
||||||
let pos = this.getPosition();
|
let pos = this.getPosition();
|
||||||
let corner = map._controlCorners[pos];
|
let corner = map._controlCorners[pos];
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,7 @@ import { ComputedRef } from 'vue';
|
||||||
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { containerMaxW } from '@/config.js';
|
import { containerMaxW } from '@/config.js';
|
||||||
// import { MainService } from '@/Stores/main.js';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { StyleService } from '@/Stores/style';
|
|
||||||
import { LayoutService } from '@/Stores/layout';
|
import { LayoutService } from '@/Stores/layout';
|
||||||
import {
|
import {
|
||||||
mdiForwardburger,
|
mdiForwardburger,
|
||||||
|
@ -15,14 +14,12 @@ import {
|
||||||
mdiClose,
|
mdiClose,
|
||||||
mdiDotsVertical,
|
mdiDotsVertical,
|
||||||
mdiMenu,
|
mdiMenu,
|
||||||
// mdiClockOutline,
|
|
||||||
mdiCloudDownloadOutline,
|
mdiCloudDownloadOutline,
|
||||||
mdiCloud,
|
mdiCloud,
|
||||||
mdiCrop,
|
mdiCrop,
|
||||||
mdiAccountCog,
|
mdiAccountCog,
|
||||||
mdiFormatListGroup,
|
mdiFormatListGroup,
|
||||||
mdiFormatListNumbered,
|
mdiFormatListNumbered,
|
||||||
// mdiEmail,
|
|
||||||
mdiLogout,
|
mdiLogout,
|
||||||
mdiGithub,
|
mdiGithub,
|
||||||
mdiThemeLightDark,
|
mdiThemeLightDark,
|
||||||
|
@ -46,9 +43,6 @@ import FirstrunWizard from '@/Components/FirstrunWizard/FirstrunWizard.vue'
|
||||||
// import SwapHorizontal from 'vue-material-design-icons/SwapHorizontal.vue'
|
// import SwapHorizontal from 'vue-material-design-icons/SwapHorizontal.vue'
|
||||||
// import AccountGroup from 'vue-material-design-icons/AccountGroup.vue'
|
// import AccountGroup from 'vue-material-design-icons/AccountGroup.vue'
|
||||||
|
|
||||||
// const mainStore = MainService();
|
|
||||||
// const userName = computed(() =>mainStore.userName);
|
|
||||||
|
|
||||||
const styleService = StyleService();
|
const styleService = StyleService();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
showBurger: {
|
showBurger: {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
// import { Link } from '@inertiajs/vue3'
|
// import { Link } from '@inertiajs/vue3'
|
||||||
import { Link } from '@inertiajs/vue3';
|
import { Link } from '@inertiajs/vue3';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
|
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
|
||||||
import { mdiChevronUp, mdiChevronDown } from '@mdi/js';
|
import { mdiChevronUp, mdiChevronDown } from '@mdi/js';
|
||||||
import NavBarItem from '@/Components/NavBarItem.vue';
|
import NavBarItem from '@/Components/NavBarItem.vue';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
zIndex: {
|
zIndex: {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { gradientBgPurplePink, gradientBgDark, gradientBgPinkRed, gradientBgGreenBlue } from '@/colors';
|
import { gradientBgPurplePink, gradientBgDark, gradientBgPinkRed, gradientBgGreenBlue } from '@/colors';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
// import { MainService } from '@/Stores/main';
|
// import { MainService } from '@/Stores/main';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { mdiTrashCan } from '@mdi/js';
|
import { mdiTrashCan } from '@mdi/js';
|
||||||
// import CardBoxModal from '@/Components/CardBoxModal.vue';
|
// import CardBoxModal from '@/Components/CardBoxModal.vue';
|
||||||
// import TableCheckboxCell from '@/Components/TableCheckboxCell.vue';
|
// import TableCheckboxCell from '@/Components/TableCheckboxCell.vue';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
// import { MainService } from '@/Stores/main';
|
// import { MainService } from '@/Stores/main';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { mdiTrashCan } from '@mdi/js';
|
import { mdiTrashCan } from '@mdi/js';
|
||||||
import { mdiDragVariant } from '@mdi/js';
|
import { mdiDragVariant } from '@mdi/js';
|
||||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { MainService } from '@/Stores/main';
|
import { MainService } from '@/Stores/main';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { mdiEye, mdiTrashCan } from '@mdi/js';
|
import { mdiEye, mdiTrashCan } from '@mdi/js';
|
||||||
import CardBoxModal from '@/Components/CardBoxModal.vue';
|
import CardBoxModal from '@/Components/CardBoxModal.vue';
|
||||||
import TableCheckboxCell from '@/Components/TableCheckboxCell.vue';
|
import TableCheckboxCell from '@/Components/TableCheckboxCell.vue';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { LayoutService } from '@/Stores/layout';
|
import { LayoutService } from '@/Stores/layout';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import NavBar from '@/Components/NavBar.vue';
|
import NavBar from '@/Components/NavBar.vue';
|
||||||
import AsideMenu from '@/Components/AsideMenu.vue';
|
import AsideMenu from '@/Components/AsideMenu.vue';
|
||||||
import FooterBar from '@/Components/FooterBar.vue';
|
import FooterBar from '@/Components/FooterBar.vue';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
const styleService = StyleService();
|
const styleService = StyleService();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script lang="ts" setup>
|
||||||
import { Head, Link, useForm, router } from '@inertiajs/vue3';
|
import { Head, useForm } from '@inertiajs/vue3';
|
||||||
import { mdiAccountKey, mdiArrowLeftBoldOutline, mdiAccount, mdiNoteText, mdiFormTextarea } from '@mdi/js';
|
import { mdiAccountKey, mdiArrowLeftBoldOutline, mdiFormTextarea } from '@mdi/js';
|
||||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||||
import SectionMain from '@/Components/SectionMain.vue';
|
import SectionMain from '@/Components/SectionMain.vue';
|
||||||
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
mdiContrastCircle,
|
mdiContrastCircle,
|
||||||
|
|
60
resources/js/Pages/Errors/ServerError.vue
Normal file
60
resources/js/Pages/Errors/ServerError.vue
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<template>
|
||||||
|
<div class="min-h-screen flex items-center justify-center bg-gray-100">
|
||||||
|
<div class="max-w-md w-full p-6 bg-white rounded-md shadow-md">
|
||||||
|
<h1 class="text-2xl font-bold text-red-500 mb-4">Error!</h1>
|
||||||
|
<p class="text-gray-700 mb-4">{{ error }}</p>
|
||||||
|
|
||||||
|
<SectionTitleLineWithButton :icon="mdiLightbulbAlert" :title="code" :main="true">
|
||||||
|
<BaseButton @click.prevent="handleAction" :icon="mdiArrowLeftBoldOutline" label="Dashboard"
|
||||||
|
color="white" rounded-full small />
|
||||||
|
</SectionTitleLineWithButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Vue, Prop } from 'vue-facing-decorator';
|
||||||
|
import { Link, router } from '@inertiajs/vue3';
|
||||||
|
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||||
|
import BaseButton from '@/Components/BaseButton.vue';
|
||||||
|
import { mdiLightbulbAlert, mdiArrowLeftBoldOutline } from '@mdi/js';
|
||||||
|
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
// options: {
|
||||||
|
// layout: DefaultLayout,
|
||||||
|
// },
|
||||||
|
name: 'AppComponent',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
Link,
|
||||||
|
BaseButton,
|
||||||
|
SectionTitleLineWithButton,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
export default class AppComponent extends Vue {
|
||||||
|
// Component Property
|
||||||
|
@Prop({
|
||||||
|
type: String,
|
||||||
|
default: () => '',
|
||||||
|
})
|
||||||
|
error: string;
|
||||||
|
|
||||||
|
@Prop({
|
||||||
|
type: String,
|
||||||
|
default: () => '',
|
||||||
|
})
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
// class properties
|
||||||
|
mdiLightbulbAlert = mdiLightbulbAlert;
|
||||||
|
mdiArrowLeftBoldOutline = mdiArrowLeftBoldOutline;
|
||||||
|
|
||||||
|
public async handleAction() {
|
||||||
|
// Add your logic here for handling the button action (e.g., logout or go back)
|
||||||
|
await router.get(stardust.route('dashboard'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
7
resources/js/Pages/Errors/not_found.vue
Normal file
7
resources/js/Pages/Errors/not_found.vue
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<div class="title">Page not found</div>
|
||||||
|
|
||||||
|
<span>This page does not exist.</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -167,7 +167,7 @@ export const MainService = defineStore('main', {
|
||||||
this.totpState = state;
|
this.totpState = state;
|
||||||
},
|
},
|
||||||
|
|
||||||
async fetchChartData(year) {
|
async fetchChartData(year: string) {
|
||||||
// sampleDataKey= authors or datasets
|
// sampleDataKey= authors or datasets
|
||||||
axios
|
axios
|
||||||
.get(`/api/statistic/${year}`)
|
.get(`/api/statistic/${year}`)
|
||||||
|
|
|
@ -9,23 +9,23 @@ export const MapService = defineStore('map', {
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
// payload = authenticated user
|
// payload = authenticated user
|
||||||
setUser(payload) {
|
// setUser(payload: any) {
|
||||||
if (payload.name) {
|
// if (payload.name) {
|
||||||
this.userName = payload.name;
|
// this.userName = payload.name;
|
||||||
}
|
// }
|
||||||
if (payload.email) {
|
// if (payload.email) {
|
||||||
this.userEmail = payload.email;
|
// this.userEmail = payload.email;
|
||||||
}
|
// }
|
||||||
if (payload.avatar) {
|
// if (payload.avatar) {
|
||||||
this.userAvatar = payload.avatar;
|
// this.userAvatar = payload.avatar;
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
|
|
||||||
getMap(id: string) {
|
getMap(id: string) {
|
||||||
return this.mapService.get(id);
|
return this.mapService.get(id);
|
||||||
},
|
},
|
||||||
|
|
||||||
setMap(id: string, map) {
|
setMap(id: string, map: any) {
|
||||||
this.mapService.set(id, map);
|
this.mapService.set(id, map);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,27 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import * as styles from '@/styles';
|
import styles from '@/styles';
|
||||||
import { darkModeKey, styleKey } from '@/config';
|
import { darkModeKey, styleKey } from '@/config';
|
||||||
|
|
||||||
|
|
||||||
|
interface StyleState {
|
||||||
|
[key: string]: string | boolean;
|
||||||
|
asideStyle: string;
|
||||||
|
asideScrollbarsStyle: string;
|
||||||
|
asideBrandStyle: string;
|
||||||
|
asideMenuItemStyle: string;
|
||||||
|
asideMenuItemActiveStyle: string;
|
||||||
|
asideMenuDropdownStyle: string;
|
||||||
|
navBarItemLabelStyle: string;
|
||||||
|
navBarItemLabelHoverStyle: string;
|
||||||
|
navBarItemLabelActiveColorStyle: string;
|
||||||
|
overlayStyle: string;
|
||||||
|
darkMode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define StyleService store
|
||||||
export const StyleService = defineStore('style', {
|
export const StyleService = defineStore('style', {
|
||||||
state: () => ({
|
state: (): StyleState => ({
|
||||||
/* Styles */
|
// Styles
|
||||||
asideStyle: '',
|
asideStyle: '',
|
||||||
asideScrollbarsStyle: '',
|
asideScrollbarsStyle: '',
|
||||||
asideBrandStyle: '',
|
asideBrandStyle: '',
|
||||||
|
@ -15,39 +32,32 @@ export const StyleService = defineStore('style', {
|
||||||
navBarItemLabelHoverStyle: '',
|
navBarItemLabelHoverStyle: '',
|
||||||
navBarItemLabelActiveColorStyle: '',
|
navBarItemLabelActiveColorStyle: '',
|
||||||
overlayStyle: '',
|
overlayStyle: '',
|
||||||
|
// Dark mode default false
|
||||||
/* Dark mode default false */
|
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
// style payload = 'basic' or 'white' with blue font
|
// Set style based on payload value ('basic' or 'white')
|
||||||
setStyle(payload) {
|
setStyle(payload: 'basic' | 'white') {
|
||||||
if (!styles[payload]) {
|
if (!styles[payload]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
if (typeof localStorage !== 'undefined') {
|
||||||
localStorage.setItem(styleKey, payload);
|
localStorage.setItem(styleKey, payload);
|
||||||
}
|
}
|
||||||
|
const style = styles[payload] as Record<string, string>;
|
||||||
const style = styles[payload];
|
|
||||||
|
|
||||||
for (const key in style) {
|
for (const key in style) {
|
||||||
this[`${key}Style`] = style[key];
|
// let keyStyle: string = `${key}Style`;//key as keyof typeof style;
|
||||||
|
this[`${key}Style` as keyof StyleState] = style[key];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// toggle dark mode
|
// Toggle dark mode
|
||||||
setDarkMode(payload = null) {
|
setDarkMode(payload?: boolean) {
|
||||||
this.darkMode = payload !== null ? payload : !this.darkMode;
|
this.darkMode = payload !== undefined ? payload : !this.darkMode;
|
||||||
|
|
||||||
if (typeof localStorage !== 'undefined') {
|
if (typeof localStorage !== 'undefined') {
|
||||||
localStorage.setItem(darkModeKey, this.darkMode ? '1' : '0');
|
localStorage.setItem(darkModeKey, this.darkMode ? '1' : '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof document !== 'undefined') {
|
if (typeof document !== 'undefined') {
|
||||||
document.body.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars');
|
document.body.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars');
|
||||||
|
|
||||||
document.documentElement.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars-compat');
|
document.documentElement.classList[this.darkMode ? 'add' : 'remove']('dark-scrollbars-compat');
|
||||||
}
|
}
|
||||||
},
|
},
|
|
@ -1,21 +1,28 @@
|
||||||
import '../css/app.css';
|
import '../css/app.css';
|
||||||
import { createApp, h } from 'vue';
|
import { createApp, h, App, Plugin } from 'vue';
|
||||||
import { Inertia } from '@inertiajs/inertia';
|
import { Inertia } from '@inertiajs/inertia';
|
||||||
|
|
||||||
import { createInertiaApp, Link, usePage } from '@inertiajs/vue3';
|
import { createInertiaApp } from '@inertiajs/vue3';
|
||||||
// import DefaultLayout from '@/Layouts/Default.vue';
|
// import DefaultLayout from '@/Layouts/Default.vue';
|
||||||
|
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia';
|
||||||
import { StyleService } from '@/Stores/style';
|
import { StyleService } from '@/Stores/style.service';
|
||||||
import { LayoutService } from '@/Stores/layout';
|
import { LayoutService } from '@/Stores/layout';
|
||||||
import { MainService } from '@/Stores/main';
|
|
||||||
import { darkModeKey, styleKey } from '@/config';
|
import { darkModeKey, styleKey } from '@/config';
|
||||||
|
// import type { DefineComponent } from 'vue';
|
||||||
|
// import { resolvePageComponent } from '@adonisjs/inertia/helpers';
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
import { EmitterPlugin } from '@/EmitterDirective';
|
import { EmitterPlugin } from '@/EmitterDirective';
|
||||||
|
|
||||||
import { initRoutes } from '@eidellev/adonis-stardust/client/index.js';
|
import { initRoutes } from '@eidellev/adonis-stardust/client/index.js';
|
||||||
initRoutes();
|
initRoutes();
|
||||||
|
|
||||||
|
interface SetupOptions {
|
||||||
|
el: Element;
|
||||||
|
App: App;
|
||||||
|
props: Record<string, any>;
|
||||||
|
plugin: Plugin;
|
||||||
|
}
|
||||||
|
|
||||||
// import '@fontsource/archivo-black/index.css';
|
// import '@fontsource/archivo-black/index.css';
|
||||||
// import '@fontsource/inter/index.css';
|
// import '@fontsource/inter/index.css';
|
||||||
|
|
||||||
|
@ -35,7 +42,7 @@ createInertiaApp({
|
||||||
// // }
|
// // }
|
||||||
// return page;
|
// return page;
|
||||||
// },
|
// },
|
||||||
resolve: async (name) => {
|
resolve: async (name: string) => {
|
||||||
// Dynamically import the Vue component using import
|
// Dynamically import the Vue component using import
|
||||||
const { default: page } = await import(`./Pages/${name}.vue`);
|
const { default: page } = await import(`./Pages/${name}.vue`);
|
||||||
// const page = require(`./Pages/${name}.vue`).default;
|
// const page = require(`./Pages/${name}.vue`).default;
|
||||||
|
@ -44,12 +51,14 @@ createInertiaApp({
|
||||||
// }
|
// }
|
||||||
return page;
|
return page;
|
||||||
},
|
},
|
||||||
// resolve: async (name) => {
|
// resolve: (name) => {
|
||||||
// const firstPath = `@/Pages/${name}.vue`;
|
// return resolvePageComponent(
|
||||||
// const module = await import(firstPath);
|
// `./Pages/${name}.vue`,
|
||||||
// return module.default || null;
|
// import.meta.glob<DefineComponent>('./pages/**/*.vue'),
|
||||||
|
// )
|
||||||
// },
|
// },
|
||||||
setup({ el, App, props, plugin }) {
|
|
||||||
|
setup({ el, App, props, plugin} : SetupOptions) {
|
||||||
createApp({ render: () => h(App, props) })
|
createApp({ render: () => h(App, props) })
|
||||||
.use(plugin)
|
.use(plugin)
|
||||||
.use(pinia)
|
.use(pinia)
|
||||||
|
@ -72,8 +81,9 @@ if ((!localStorage[darkModeKey] && window.matchMedia('(prefers-color-scheme: dar
|
||||||
styleService.setDarkMode(true);
|
styleService.setDarkMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Collapse mobile aside menu on route change */
|
/* Collapse mobile aside menu on route change */
|
||||||
Inertia.on('navigate', (event) => {
|
Inertia.on('navigate', () => {
|
||||||
layoutService.isAsideMobileExpanded = false;
|
layoutService.isAsideMobileExpanded = false;
|
||||||
layoutService.isAsideLgActive = false;
|
layoutService.isAsideLgActive = false;
|
||||||
});
|
});
|
|
@ -1,4 +1,5 @@
|
||||||
export const basic = {
|
const styles = {
|
||||||
|
basic: {
|
||||||
aside: 'bg-gray-800',
|
aside: 'bg-gray-800',
|
||||||
asideScrollbars: 'aside-scrollbars-gray',
|
asideScrollbars: 'aside-scrollbars-gray',
|
||||||
asideBrand: 'bg-gray-900 text-white',
|
asideBrand: 'bg-gray-900 text-white',
|
||||||
|
@ -11,9 +12,9 @@ export const basic = {
|
||||||
// navBarItemLabelActiveColor: 'text-blue-600',
|
// navBarItemLabelActiveColor: 'text-blue-600',
|
||||||
navBarItemLabelActiveColor: 'text-lime-dark',
|
navBarItemLabelActiveColor: 'text-lime-dark',
|
||||||
overlay: 'from-gray-700 via-gray-900 to-gray-700',
|
overlay: 'from-gray-700 via-gray-900 to-gray-700',
|
||||||
};
|
},
|
||||||
|
|
||||||
export const white = {
|
white: {
|
||||||
aside: 'bg-white',
|
aside: 'bg-white',
|
||||||
asideScrollbars: 'aside-scrollbars-light',
|
asideScrollbars: 'aside-scrollbars-light',
|
||||||
asideBrand: '',
|
asideBrand: '',
|
||||||
|
@ -24,4 +25,6 @@ export const white = {
|
||||||
navBarItemLabelHover: 'hover:text-black',
|
navBarItemLabelHover: 'hover:text-black',
|
||||||
navBarItemLabelActiveColor: 'text-black',
|
navBarItemLabelActiveColor: 'text-black',
|
||||||
overlay: 'from-white via-gray-100 to-white',
|
overlay: 'from-white via-gray-100 to-white',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
export default styles;
|
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
// tsconfig.vue.json
|
// tsconfig.vue.json
|
||||||
"extends": "@vue/tsconfig/tsconfig.json",
|
"extends": "@vue/tsconfig/tsconfig.json",
|
||||||
"include": ["./resources/js/**/*"],
|
// "include": ["./resources/js/**/*"],
|
||||||
|
"include": ["env.d.ts", "./**/*.ts", "./**/*.vue"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// "module": "commonjs", //for tehys.api...alos nodenext
|
// "module": "commonjs", //for tehys.api...alos nodenext
|
||||||
// Process & infer types from .js files.
|
// Process & infer types from .js files.
|
||||||
|
@ -14,9 +14,13 @@
|
||||||
"experimentalDecorators": true, //neu
|
"experimentalDecorators": true, //neu
|
||||||
"strictPropertyInitialization": false //neu
|
"strictPropertyInitialization": false //neu
|
||||||
},
|
},
|
||||||
|
// "paths": {
|
||||||
|
// "App/*": ["./app/*"], // for App/modles/User
|
||||||
|
// "@/*": ["./resources/js/*"]
|
||||||
|
// },
|
||||||
"paths": {
|
"paths": {
|
||||||
"App/*": ["./app/*"], // for App/modles/User
|
"@/*": ["./*"],
|
||||||
"@/*": ["./resources/js/*"]
|
"~/*": ["../*"]
|
||||||
},
|
},
|
||||||
"files": ["./index.d.ts"]
|
// "files": ["./index.d.ts"]
|
||||||
}
|
}
|
|
@ -1,9 +1,4 @@
|
||||||
// import { ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
|
|
||||||
// import { LucidModel } from '@adonisjs/lucid/types/model';
|
|
||||||
import { Request, Response } from '@adonisjs/core/http';
|
import { Request, Response } from '@adonisjs/core/http';
|
||||||
// import BaseModel from '#app/Models/BaseModel';
|
|
||||||
// import { LucidModel } from '@adonisjs/lucid/types/model';
|
|
||||||
// import BaseModel from '#app/Models/BaseModel';
|
|
||||||
|
|
||||||
Request.macro('wantsJSON', function (this: Request) {
|
Request.macro('wantsJSON', function (this: Request) {
|
||||||
const firstType = this.types()[0];
|
const firstType = this.types()[0];
|
||||||
|
@ -22,11 +17,31 @@ declare module '@adonisjs/core/http' {
|
||||||
|
|
||||||
// By specifying this: Response in the function signature, you're explicitly stating
|
// By specifying this: Response in the function signature, you're explicitly stating
|
||||||
// that 'this' within the function should be of type 'Response', which resolves the TypeScript error.
|
// that 'this' within the function should be of type 'Response', which resolves the TypeScript error.
|
||||||
Response.macro('flash', function (this: Response, key: string, message: any) {
|
// Response.macro('flash', function (this: Response, message: any) {
|
||||||
|
// if (!this.ctx) {
|
||||||
|
// throw new Error('Context is not available');
|
||||||
|
// }
|
||||||
|
// this.ctx!.session.flash(message);
|
||||||
|
// return this;
|
||||||
|
// });
|
||||||
|
// Response.macro('flash', function (this: Response, key: string, message: any) {
|
||||||
|
// if (!this.ctx) {
|
||||||
|
// throw new Error('Context is not available');
|
||||||
|
// }
|
||||||
|
// this.ctx!.session.flash(key, message);
|
||||||
|
// return this;
|
||||||
|
// });
|
||||||
|
Response.macro('flash', function (this: Response, message: any, key?: string,) {
|
||||||
if (!this.ctx) {
|
if (!this.ctx) {
|
||||||
throw new Error('Context is not available');
|
throw new Error('Context is not available');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key !== undefined) {
|
||||||
this.ctx!.session.flash(key, message);
|
this.ctx!.session.flash(key, message);
|
||||||
|
} else {
|
||||||
|
this.ctx!.session.flash(message);
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
Response.macro('toRoute', function (this: Response, route: string) {
|
Response.macro('toRoute', function (this: Response, route: string) {
|
||||||
|
@ -35,6 +50,7 @@ Response.macro('toRoute', function (this: Response, route: string) {
|
||||||
});
|
});
|
||||||
declare module '@adonisjs/core/http' {
|
declare module '@adonisjs/core/http' {
|
||||||
interface Response {
|
interface Response {
|
||||||
|
flash(message: any): Response;
|
||||||
flash(key: string, message: any): Response;
|
flash(key: string, message: any): Response;
|
||||||
toRoute(route: string): Response;
|
toRoute(route: string): Response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export default await Env.create(new URL("../", import.meta.url), {
|
||||||
APP_KEY: Env.schema.string(),
|
APP_KEY: Env.schema.string(),
|
||||||
APP_NAME: Env.schema.string(),
|
APP_NAME: Env.schema.string(),
|
||||||
CACHE_VIEWS: Env.schema.boolean(),
|
CACHE_VIEWS: Env.schema.boolean(),
|
||||||
SESSION_DRIVER: Env.schema.string(),
|
SESSION_DRIVER: Env.schema.enum(["cookie" ,"memory"] as const),
|
||||||
|
|
||||||
DRIVE_DISK: Env.schema.enum(['local'] as const),
|
DRIVE_DISK: Env.schema.enum(['local'] as const),
|
||||||
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
|
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
|
||||||
|
@ -31,6 +31,9 @@ export default await Env.create(new URL("../", import.meta.url), {
|
||||||
PG_DB_NAME: Env.schema.string(),
|
PG_DB_NAME: Env.schema.string(),
|
||||||
|
|
||||||
REDIS_HOST: Env.schema.string({ format: 'host' }),
|
REDIS_HOST: Env.schema.string({ format: 'host' }),
|
||||||
REDIS_PORT: Env.schema.number()
|
REDIS_PORT: Env.schema.number(),
|
||||||
|
|
||||||
|
HASH_DRIVER: Env.schema.enum(["scrypt", "argon", "bcrypt", "laravel", undefined] as const),
|
||||||
|
OAI_LIST_SIZE: Env.schema.number()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ server.errorHandler(
|
||||||
server.use([
|
server.use([
|
||||||
() => import('#middleware/container_bindings_middleware'),
|
() => import('#middleware/container_bindings_middleware'),
|
||||||
() => import('@adonisjs/static/static_middleware'),
|
() => import('@adonisjs/static/static_middleware'),
|
||||||
|
// () => import('@adonisjs/cors/cors_middleware'),
|
||||||
() => import('@adonisjs/inertia/inertia_middleware'),
|
() => import('@adonisjs/inertia/inertia_middleware'),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -46,10 +47,8 @@ router.use([
|
||||||
* the routes or the routes group.
|
* the routes or the routes group.
|
||||||
*/
|
*/
|
||||||
export const middleware = router.named({
|
export const middleware = router.named({
|
||||||
// guest: () => import('#middleware/guest_middleware'),
|
guest: () => import('#middleware/guest_middleware'),
|
||||||
// stardust: () => import('#middleware/stardust_middleware'),
|
|
||||||
// guest: () => import('#middleware/guest_middleware'),
|
|
||||||
auth: () => import('#middleware/auth_middleware'),
|
auth: () => import('#middleware/auth_middleware'),
|
||||||
is: () => import('#middleware/Role'),
|
is: () => import('#middleware/role_middleware'),
|
||||||
can: () => import('#middleware/Can'),
|
can: () => import('#middleware/can_middleware'),
|
||||||
})
|
})
|
||||||
|
|
|
@ -29,7 +29,7 @@ import AuthValidator from '#app/Validators/AuthValidator';
|
||||||
import User from '#app/Models/User';
|
import User from '#app/Models/User';
|
||||||
import AuthController from '#controllers/Http/Auth/AuthController';
|
import AuthController from '#controllers/Http/Auth/AuthController';
|
||||||
import UserController from '#controllers/Http/Auth/UserController';
|
import UserController from '#controllers/Http/Auth/UserController';
|
||||||
import AdminUserController from '#controllers/Http/Admin/UsersController';
|
import AdminuserController from '#controllers/Http/Admin/AdminuserController';
|
||||||
import RoleController from '#controllers/Http/Admin/RoleController';
|
import RoleController from '#controllers/Http/Admin/RoleController';
|
||||||
|
|
||||||
import DatasetController from '#app/Controllers/Http/Submitter/DatasetController';
|
import DatasetController from '#app/Controllers/Http/Submitter/DatasetController';
|
||||||
|
@ -131,20 +131,20 @@ router.group(() => {
|
||||||
.as('overview');
|
.as('overview');
|
||||||
|
|
||||||
// user routes
|
// user routes
|
||||||
router.get('/user', [AdminUserController, 'index']).as('user.index').use(middleware.can(['user-list']));
|
router.get('/user', [AdminuserController, 'index']).as('user.index').use(middleware.can(['user-list']));
|
||||||
router.get('/user/create', [AdminUserController, 'create']).as('user.create').use(middleware.can(['user-create']));
|
router.get('/user/create', [AdminuserController, 'create']).as('user.create').use(middleware.can(['user-create']));
|
||||||
router.post('/user/store', [AdminUserController, 'store']).as('user.store').use(middleware.can(['user-create']));
|
router.post('/user/store', [AdminuserController, 'store']).as('user.store').use(middleware.can(['user-create']));
|
||||||
router.get('/user/:id', [AdminUserController, 'show']).as('user.show').where('id', router.matchers.number());
|
router.get('/user/:id', [AdminuserController, 'show']).as('user.show').where('id', router.matchers.number());
|
||||||
router.get('/user/:id/edit', [AdminUserController, 'edit']).as('user.edit').where('id', router.matchers.number()).use(middleware.can(['user-edit']));
|
router.get('/user/:id/edit', [AdminuserController, 'edit']).as('user.edit').where('id', router.matchers.number()).use(middleware.can(['user-edit']));
|
||||||
router.put('/user/:id/update', [AdminUserController, 'update'])
|
router.put('/user/:id/update', [AdminuserController, 'update'])
|
||||||
.as('user.update')
|
.as('user.update')
|
||||||
.where('id', router.matchers.number())
|
.where('id', router.matchers.number())
|
||||||
.use(middleware.can(['user-edit']));
|
.use(middleware.can(['user-edit']));
|
||||||
// // Route.delete('/user/:id', [AdminUserController, 'destroy'])
|
// // Route.delete('/user/:id', [AdminuserController, 'destroy'])
|
||||||
// // .as('user.destroy')
|
// // .as('user.destroy')
|
||||||
// // .where('id', Route.matchers.number())
|
// // .where('id', Route.matchers.number())
|
||||||
// // .use(middleware.can(['user-delete']));
|
// // .use(middleware.can(['user-delete']));
|
||||||
// // Route.resource('user', 'AdminUserController');
|
// // Route.resource('user', 'AdminuserController');
|
||||||
|
|
||||||
router.get('/role', [RoleController, 'index']).as('role.index').use(middleware.can(['user-list']));
|
router.get('/role', [RoleController, 'index']).as('role.index').use(middleware.can(['user-list']));
|
||||||
router.get('/role/create', [RoleController, 'create']).as('role.create').use(middleware.can(['user-create']));
|
router.get('/role/create', [RoleController, 'create']).as('role.create').use(middleware.can(['user-create']));
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
{
|
{
|
||||||
"extends": "@adonisjs/tsconfig/tsconfig.app.json",
|
"extends": "@adonisjs/tsconfig/tsconfig.app.json",
|
||||||
"include": [
|
"include": [
|
||||||
"**/*"
|
"**/*",
|
||||||
|
// "resources/**/*.ts",
|
||||||
|
// "resources/**/*.d.ts",
|
||||||
|
// "resources/**/*.vue"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"build",
|
"build",
|
||||||
"public",
|
"public",
|
||||||
"resources"
|
// "resources/js/**/*",
|
||||||
],
|
],
|
||||||
|
// "exclude": ["./inertia/**/*"]
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"outDir": "build",
|
"outDir": "build",
|
||||||
|
@ -21,8 +25,9 @@
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": ["./resources/js/*.js"],
|
||||||
"./resources/js/*"
|
"#resources/*": [
|
||||||
|
"./resources/js/*.js"
|
||||||
],
|
],
|
||||||
"#controllers/*": [
|
"#controllers/*": [
|
||||||
"./app/controllers/*.js"
|
"./app/controllers/*.js"
|
||||||
|
|
|
@ -96,7 +96,7 @@ Encore.setPublicPath('/assets');
|
||||||
| entrypoints.
|
| entrypoints.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
Encore.addEntry('app', './resources/js/app.js');
|
Encore.addEntry('app', './resources/js/app.ts');
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -305,7 +305,7 @@ Encore.addLoader({
|
||||||
Encore.addLoader(babelLoader)
|
Encore.addLoader(babelLoader)
|
||||||
// Encore.enableTypeScriptLoader(config => {
|
// Encore.enableTypeScriptLoader(config => {
|
||||||
// // Loader-specific options
|
// // Loader-specific options
|
||||||
// config.configFile = 'tsconfig.vue.json';
|
// config.configFile = 'resources/js/tsconfig.vue.json';
|
||||||
// config.appendTsSuffixTo = [/\.vue$/];
|
// config.appendTsSuffixTo = [/\.vue$/];
|
||||||
// config.transpileOnly = true;
|
// config.transpileOnly = true;
|
||||||
// config.happyPackMode = false;
|
// config.happyPackMode = false;
|
||||||
|
@ -317,11 +317,11 @@ Encore.addLoader(babelLoader)
|
||||||
.addAliases({
|
.addAliases({
|
||||||
'@': join(__dirname, 'resources/js'),
|
'@': join(__dirname, 'resources/js'),
|
||||||
'vue$': 'vue/dist/vue.runtime.esm-bundler.js',
|
'vue$': 'vue/dist/vue.runtime.esm-bundler.js',
|
||||||
|
})
|
||||||
|
.configureDefinePlugin((options) => {
|
||||||
|
options['__VUE_OPTIONS_API__'] = true;
|
||||||
|
options['__VUE_PROD_DEVTOOLS__'] = false;
|
||||||
});
|
});
|
||||||
// .configureDefinePlugin((options) => {
|
|
||||||
// options['__VUE_OPTIONS_API__'] = true;
|
|
||||||
// options['__VUE_PROD_DEVTOOLS__'] = false;
|
|
||||||
// });
|
|
||||||
|
|
||||||
// Encore.addAliases({
|
// Encore.addAliases({
|
||||||
// '@': resolve(__dirname, 'resources/js')
|
// '@': resolve(__dirname, 'resources/js')
|
||||||
|
|
|
@ -1,267 +0,0 @@
|
||||||
const { join } = require("path");
|
|
||||||
const Encore = require("@symfony/webpack-encore");
|
|
||||||
const { VueLoaderPlugin } = require('vue-loader');
|
|
||||||
const dotenv = require('dotenv-webpack');
|
|
||||||
|
|
||||||
// Load the environment variables from the.env file
|
|
||||||
Encore.addPlugin(
|
|
||||||
new dotenv({
|
|
||||||
path: ".env",
|
|
||||||
defaults: ".env",
|
|
||||||
systemvars: true,
|
|
||||||
allowEmptyValues: true,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Encore runtime environment
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
if (!Encore.isRuntimeEnvironmentConfigured()) {
|
|
||||||
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || "dev");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Output path
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The output path for writing the compiled files. It should always
|
|
||||||
| be inside the public directory, so that AdonisJS can serve it.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.setOutputPath("./public/assets");
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Public URI
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The public URI to access the static files. It should always be
|
|
||||||
| relative from the "public" directory.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.setPublicPath("/assets");
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Entrypoints
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Entrypoints are script files that boots your frontend application. Ideally
|
|
||||||
| a single entrypoint is used by majority of applications. However, feel
|
|
||||||
| free to add more (if required).
|
|
||||||
|
|
|
||||||
| Also, make sure to read the docs on "Assets bundler" to learn more about
|
|
||||||
| entrypoints.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.addEntry("app", "./resources/js/app.js");
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Copy assets
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Since the edge templates are not part of the Webpack compile lifecycle, any
|
|
||||||
| images referenced by it will not be processed by Webpack automatically. Hence
|
|
||||||
| we must copy them manually.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
// Encore.copyFiles({
|
|
||||||
// from: './resources/images',
|
|
||||||
// to: 'images/[path][name].[hash:8].[ext]',
|
|
||||||
// })
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Split shared code
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Instead of bundling duplicate code in all the bundles, generate a separate
|
|
||||||
| bundle for the shared code.
|
|
||||||
|
|
|
||||||
| https://symfony.com/doc/current/frontend/encore/split-chunks.html
|
|
||||||
| https://webpack.js.org/plugins/split-chunks-plugin/
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
// Encore.splitEntryChunks()
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Isolated entrypoints
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Treat each entry point and its dependencies as its own isolated module.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.disableSingleRuntimeChunk();
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Cleanup output folder
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| It is always nice to cleanup the build output before creating a build. It
|
|
||||||
| will ensure that all unused files from the previous build are removed.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.cleanupOutputBeforeBuild();
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Source maps
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Enable source maps in production
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.enableSourceMaps(!Encore.isProduction());
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Assets versioning
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Enable assets versioning to leverage lifetime browser and CDN cache
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.enableVersioning(Encore.isProduction());
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Configure dev server
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Here we configure the dev server to enable live reloading for edge templates.
|
|
||||||
| Remember edge templates are not processed by Webpack and hence we need
|
|
||||||
| to watch them explicitly and livereload the browser.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.configureDevServerOptions((options) => {
|
|
||||||
/**
|
|
||||||
* Normalize "options.static" property to an array
|
|
||||||
*/
|
|
||||||
if (!options.static) {
|
|
||||||
options.static = [];
|
|
||||||
} else if (!Array.isArray(options.static)) {
|
|
||||||
options.static = [options.static];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable live reload and add views directory
|
|
||||||
*/
|
|
||||||
options.liveReload = true;
|
|
||||||
options.static.push({
|
|
||||||
directory: join(__dirname, "./resources/views"),
|
|
||||||
watch: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| CSS precompilers support
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Uncomment one of the following lines of code to enable support for your
|
|
||||||
| favorite CSS precompiler
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
// Encore.enableSassLoader()
|
|
||||||
// Encore.enableLessLoader()
|
|
||||||
// Encore.enableStylusLoader()
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| CSS loaders
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Uncomment one of the following line of code to enable support for
|
|
||||||
| PostCSS or CSS.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
Encore.enablePostCssLoader()
|
|
||||||
// Encore.configureCssLoader(() => {})
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Enable Vue loader
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Uncomment the following lines of code to enable support for vue. Also make
|
|
||||||
| sure to install the required dependencies.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
// Encore.enableVueLoader(() => {}, {
|
|
||||||
// version: 3,
|
|
||||||
// runtimeCompilerBuild: false,
|
|
||||||
// useJsx: false
|
|
||||||
// });
|
|
||||||
|
|
||||||
Encore.addLoader({
|
|
||||||
test: /\.vue$/,
|
|
||||||
loader: 'vue-loader',
|
|
||||||
options: {
|
|
||||||
// loaders: {
|
|
||||||
// ts: 'ts-loader',
|
|
||||||
// },
|
|
||||||
cacheDirectory: 'C:\\Users\\kaiarn\\Documents\\Software\\tethys.viewer\\node_modules\\.cache\\vue-loader',
|
|
||||||
cacheIdentifier: 'f930df3e',
|
|
||||||
babelParserPlugins: ['jsx', 'classProperties', 'decorators-legacy'],
|
|
||||||
},
|
|
||||||
}).addPlugin(new VueLoaderPlugin());
|
|
||||||
|
|
||||||
|
|
||||||
Encore.enableTypeScriptLoader(config => {
|
|
||||||
// Loader-specific options
|
|
||||||
config.configFile = 'tsconfig.vue.json';
|
|
||||||
config.appendTsSuffixTo = [/\.vue$/];
|
|
||||||
config.transpileOnly = true;
|
|
||||||
config.happyPackMode = false;
|
|
||||||
}, {
|
|
||||||
// Directly change the exclude rule
|
|
||||||
exclude: /node_modules/,
|
|
||||||
|
|
||||||
})
|
|
||||||
.addAliases({
|
|
||||||
'@': join(__dirname, 'resources/js'),
|
|
||||||
'vue$': 'vue/dist/vue.runtime.esm-bundler.js',
|
|
||||||
})
|
|
||||||
.configureDefinePlugin((options) => {
|
|
||||||
options['__VUE_OPTIONS_API__'] = true;
|
|
||||||
options['__VUE_PROD_DEVTOOLS__'] = false;
|
|
||||||
})
|
|
||||||
.addAliases({
|
|
||||||
'@': join(__dirname, 'resources/js'),
|
|
||||||
'vue$': 'vue/dist/vue.runtime.esm-bundler.js',
|
|
||||||
})
|
|
||||||
.configureDefinePlugin((options) => {
|
|
||||||
options['__VUE_OPTIONS_API__'] = true;
|
|
||||||
options['__VUE_PROD_DEVTOOLS__'] = false;
|
|
||||||
});
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Configure logging
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| To keep the terminal clean from unnecessary info statements , we only
|
|
||||||
| log warnings and errors. If you want all the logs, you can change
|
|
||||||
| the level to "info".
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
const config = Encore.getWebpackConfig();
|
|
||||||
config.infrastructureLogging = {
|
|
||||||
level: "warn",
|
|
||||||
};
|
|
||||||
config.stats = "errors-warnings";
|
|
||||||
config.resolve.extensions = ['.tsx', '.ts', '.mjs', '.js', '.jsx', '.vue', '.json', '.wasm'];
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Export config
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Export config for webpack to do its job
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
module.exports = config;
|
|
Loading…
Reference in New Issue
Block a user