🔀 Merge remote-tracking branch 'origin/main' into release/v1.0.5
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
version: "3.4"
|
||||
|
||||
services:
|
||||
mongo:
|
||||
container_name: mongo
|
||||
|
||||
@@ -70,12 +70,17 @@
|
||||
}
|
||||
},
|
||||
"storage": {
|
||||
"strategy": "STORAGE_STRATEGY",
|
||||
"secret": "STORAGE_SECRET",
|
||||
"iv": "STORAGE_SECRET_BASE_IV",
|
||||
"type": "STORAGE_DRIVER",
|
||||
"local": {
|
||||
"path": "STORAGE_LOCAL_PATH"
|
||||
},
|
||||
"oneof": {
|
||||
"__name": "STORAGE_ONEOF",
|
||||
"__format": "json"
|
||||
},
|
||||
"S3": {
|
||||
"homeDirectory": "STORAGE_S3_HOME_DIRECTORY",
|
||||
"bucket": "STORAGE_S3_BUCKET",
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
"storage": {
|
||||
"secret": "0ea28a329df23220fa814e005bfb671c",
|
||||
"iv": "1234abcd00000000",
|
||||
"strategy": "local",
|
||||
"type": "local",
|
||||
"S3": {
|
||||
"endPoint": "play.min.io",
|
||||
|
||||
Generated
+52
-757
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,7 @@
|
||||
"test:unit:watch": "npm run test:unit -- --watchAll --verbose false | pino-pretty",
|
||||
"test:merge:json": "npx istanbul report --dir coverage/merged --include 'coverage/**/coverage-final.json' json-summary",
|
||||
"test:merge:text": "npx istanbul report --dir coverage/merged --include 'coverage/**/coverage-final.json' text > coverage/merged/coverage-report.txt",
|
||||
"test:all": "jest test --forceExit --coverage --detectOpenHandles --testTimeout=600000 --verbose false --runInBand",
|
||||
"test:all": "jest test --forceExit --coverage --detectOpenHandles --testTimeout=600000 --verbose false",
|
||||
"kill": "kill $(lsof -t -i:3000) | exit 0"
|
||||
},
|
||||
"jest": {
|
||||
@@ -77,6 +77,7 @@
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/pdf-image": "^2.0.1",
|
||||
"@types/pg-pool": "^2.0.6",
|
||||
"@types/pino": "^7.0.5",
|
||||
"@types/pump": "^1.1.1",
|
||||
"@types/random-useragent": "^0.3.1",
|
||||
"@types/socket.io-client": "^1.4.36",
|
||||
@@ -166,8 +167,7 @@
|
||||
"pdf2pic": "^2.1.4",
|
||||
"pg": "^8.11.3",
|
||||
"pg-pool": "^3.6.1",
|
||||
"pino": "^6.8.0",
|
||||
"pino-std-serializers": "^6.1.0",
|
||||
"pino": "^9.5.0",
|
||||
"probe-image-size": "^7.2.3",
|
||||
"pump": "^3.0.0",
|
||||
"random-useragent": "^0.5.0",
|
||||
@@ -182,7 +182,6 @@
|
||||
"unzipper": "^0.11.6",
|
||||
"uuid": "^8.3.2",
|
||||
"uuid-time": "^1.0.0",
|
||||
"v8-profiler-next": "^1.10.0",
|
||||
"yargs": "^16.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,12 @@ export const logger = pino({
|
||||
mixin() {
|
||||
return executionStorage.getStore() ? executionStorage.getStore() : {};
|
||||
},
|
||||
formatters: {
|
||||
level(label: string) {
|
||||
return { level: label.toUpperCase() };
|
||||
},
|
||||
},
|
||||
serializers: pino.stdSerializers,
|
||||
});
|
||||
|
||||
export const getLogger = (name?: string): TdriveLogger =>
|
||||
|
||||
@@ -28,7 +28,7 @@ export async function buildDependenciesTree(
|
||||
`The component dependency ${dependencyName} has not been found for component ${name}`,
|
||||
);
|
||||
} else {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`(warning) The component dependency ${dependencyName} has not been found for component ${name} it will be imported asynchronously`,
|
||||
);
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ export default class MongoSearch extends SearchAdapter implements SearchAdapterI
|
||||
const { query, sort, project } = buildSearchQuery<EntityType>(entityType, filters, options);
|
||||
|
||||
logger.info(`Search query: ${JSON.stringify(query)}`);
|
||||
console.log(query);
|
||||
logger.info(query);
|
||||
|
||||
const sortMapped: any = sort
|
||||
? Object.fromEntries(
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
import { buildSelectQuery } from "../../../database/services/orm/connectors/mongodb/query-builder";
|
||||
import { EntityTarget, FindFilter, FindOptions, getEntityDefinition } from "../../api";
|
||||
import { asciiFold } from "../utils";
|
||||
import { logger } from "../../../../framework";
|
||||
|
||||
export function buildSearchQuery<Entity>(
|
||||
entityType: EntityTarget<Entity>,
|
||||
@@ -15,7 +16,7 @@ export function buildSearchQuery<Entity>(
|
||||
try {
|
||||
query = buildSelectQuery(entityType, filters, options);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
logger.info(e);
|
||||
}
|
||||
let sort: any = {};
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@ import * as Minio from "minio";
|
||||
import { logger } from "../../../../../../core/platform/framework";
|
||||
import { Readable } from "stream";
|
||||
import { StorageConnectorAPI, WriteMetadata } from "../../provider";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
export type S3Configuration = {
|
||||
id: string;
|
||||
bucket: string;
|
||||
region: string;
|
||||
endPoint: string;
|
||||
@@ -17,10 +19,20 @@ export type S3Configuration = {
|
||||
export default class S3ConnectorService implements StorageConnectorAPI {
|
||||
client: Minio.Client;
|
||||
minioConfiguration: S3Configuration;
|
||||
id: string;
|
||||
|
||||
constructor(S3Configuration: S3Configuration) {
|
||||
this.client = new Minio.Client(S3Configuration);
|
||||
this.minioConfiguration = S3Configuration;
|
||||
this.id = this.minioConfiguration.id;
|
||||
if (!this.id) {
|
||||
this.id = randomUUID();
|
||||
logger.info(`Identifier for S3 storage haven't been set, initializing to '${this.id}'`);
|
||||
}
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
write(path: string, stream: Readable): Promise<WriteMetadata> {
|
||||
@@ -101,7 +113,7 @@ export default class S3ConnectorService implements StorageConnectorAPI {
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error("Error getting information from S3", e);
|
||||
logger.error(e, `Error getting information from S3 for path: ${path}`);
|
||||
}
|
||||
|
||||
if (i === tries) {
|
||||
|
||||
@@ -5,16 +5,28 @@ import { rm } from "fs/promises"; // Do not change the import, this is not the s
|
||||
import { StorageConnectorAPI, WriteMetadata } from "../../provider";
|
||||
import fs from "fs";
|
||||
import { logger } from "../../../../framework/logger";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
export type LocalConfiguration = {
|
||||
id: string;
|
||||
path: string;
|
||||
};
|
||||
|
||||
export default class LocalConnectorService implements StorageConnectorAPI {
|
||||
id: string;
|
||||
configuration: LocalConfiguration;
|
||||
|
||||
constructor(localConfiguration: LocalConfiguration) {
|
||||
this.configuration = localConfiguration;
|
||||
this.id = this.configuration.id;
|
||||
if (!this.id) {
|
||||
this.id = randomUUID();
|
||||
logger.info(`Identifier for local storage haven't been set, initializing to '${this.id}'`);
|
||||
}
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
write(relativePath: string, stream: Readable): Promise<WriteMetadata> {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Readable, Stream } from "stream";
|
||||
import { ExecutionContext } from "../../framework/api/crud-service";
|
||||
import {
|
||||
DeleteOptions,
|
||||
ReadOptions,
|
||||
StorageConnectorAPI,
|
||||
WriteMetadata,
|
||||
WriteOptions,
|
||||
} from "../storage/provider";
|
||||
|
||||
export class DefaultStorageStrategy implements StorageConnectorAPI {
|
||||
private connector: StorageConnectorAPI;
|
||||
|
||||
constructor(connector: StorageConnectorAPI) {
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.connector.getId();
|
||||
}
|
||||
|
||||
write = (
|
||||
path: string,
|
||||
stream: Stream,
|
||||
options?: WriteOptions,
|
||||
context?: ExecutionContext,
|
||||
): Promise<WriteMetadata> => {
|
||||
return this.connector.write(path, stream, options, context);
|
||||
};
|
||||
|
||||
read = (path: string, options?: ReadOptions, context?: ExecutionContext): Promise<Readable> => {
|
||||
return this.connector.read(path, options, context);
|
||||
};
|
||||
|
||||
exists = (path: string, options?: ReadOptions, context?: ExecutionContext): Promise<boolean> => {
|
||||
return this.connector.exists(path, options, context);
|
||||
};
|
||||
|
||||
remove = (
|
||||
path: string,
|
||||
options?: DeleteOptions,
|
||||
context?: ExecutionContext,
|
||||
): Promise<boolean> => {
|
||||
return this.connector.remove(path, options, context);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export class FileNotFountException extends Error {}
|
||||
export class WriteFileException extends Error {}
|
||||
@@ -0,0 +1,163 @@
|
||||
import { Readable, Stream, PassThrough } from "stream";
|
||||
import {
|
||||
DeleteOptions,
|
||||
ReadOptions,
|
||||
StorageConnectorAPI,
|
||||
WriteMetadata,
|
||||
WriteOptions,
|
||||
} from "../storage/provider";
|
||||
import { logger } from "../../../platform/framework";
|
||||
import { FileNotFountException, WriteFileException } from "./exceptions";
|
||||
|
||||
/**
|
||||
* OneOfStorageStrategy is responsible for managing multiple storage backends.
|
||||
* It writes to, reads from, removes, and checks for the existence of files
|
||||
* across multiple storage systems.
|
||||
*
|
||||
* WARNING: Be careful using this strategy. There is a very big probability that
|
||||
* all storages won't be synchronized. You need to use external synchronization
|
||||
* tools like rclone to keep them in sync.
|
||||
* As far as all the objects in a storage are immutable you won't have inconsistent
|
||||
* state of the object except it could've been deleted, and it's still exists in one
|
||||
* of the storages. So you will need to have external procedures to clean up storages
|
||||
* and make "garbage" collection.
|
||||
*/
|
||||
export class OneOfStorageStrategy implements StorageConnectorAPI {
|
||||
id: string;
|
||||
|
||||
constructor(private readonly storages: StorageConnectorAPI[]) {}
|
||||
|
||||
getId() {
|
||||
if (!this.id) {
|
||||
this.id = this.storages.map(s => s.getId()).join("_");
|
||||
}
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a file to all configured storages.
|
||||
* The write operation is considered successful if one of the storage succeed.
|
||||
* @param path - The path where the file should be written.
|
||||
* @param stream - The input stream to be written to storages.
|
||||
* @param options - Write option: chunk number, encryption key, etc ...
|
||||
* @throws Error if the write operation fails for one or more storages.
|
||||
*/
|
||||
write = async (path: string, stream: Stream, options?: WriteOptions): Promise<WriteMetadata> => {
|
||||
logger.debug("Creating streams for all storages ...");
|
||||
const passThroughStreams = this.storages.map(() => new PassThrough());
|
||||
|
||||
// destroy all streams if there is an error in the input stream
|
||||
stream.on("error", err => {
|
||||
logger.error(err, "Error in input stream, destroying all write streams");
|
||||
passThroughStreams.forEach(stream => stream.destroy(err));
|
||||
});
|
||||
|
||||
// Pipe the input stream to each PassThrough stream
|
||||
stream
|
||||
.pipe(new PassThrough())
|
||||
.on("data", chunk => {
|
||||
passThroughStreams.forEach(stream => stream.write(chunk));
|
||||
})
|
||||
.on("end", () => {
|
||||
passThroughStreams.forEach(stream => stream.end());
|
||||
});
|
||||
|
||||
// Write to all storages with error handling
|
||||
const writeResults = await Promise.allSettled(
|
||||
this.storages.map((storage, index) =>
|
||||
storage.write(path, passThroughStreams[index], options),
|
||||
),
|
||||
);
|
||||
|
||||
// Log all errors and throw if all write operations fail
|
||||
const errors = writeResults.filter(result => result.status === "rejected");
|
||||
errors.forEach((error, index) => {
|
||||
const storageId = this.storages[index].getId();
|
||||
logger.error(
|
||||
new OneOfStorageWriteOneFailedException(
|
||||
storageId,
|
||||
`Error writing to storage ${storageId}`,
|
||||
(error as PromiseRejectedResult).reason,
|
||||
),
|
||||
);
|
||||
});
|
||||
if (errors.length === this.storages.length) {
|
||||
throw new WriteFileException(`Write ${path} failed for all storages`);
|
||||
}
|
||||
|
||||
const successResult = writeResults.filter(
|
||||
result => result.status === "fulfilled",
|
||||
)[0] as PromiseFulfilledResult<WriteMetadata>;
|
||||
return successResult.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads a file from the primary storage. If it fails, attempts to read from other storages.
|
||||
* @param path - The path of the file to be read.
|
||||
* @param options
|
||||
* @returns A readable stream of the file.
|
||||
* @throws Error if all storage read attempts fail.
|
||||
*/
|
||||
read = async (path: string, options?: ReadOptions): Promise<Readable> => {
|
||||
for (const storage of this.storages) {
|
||||
try {
|
||||
if (await storage.exists(path, options)) {
|
||||
return await storage.read(path, options);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
new OneOfStorageReadOneFailedException(
|
||||
storage.getId(),
|
||||
`Reading ${path} from storage ${storage} failed.`,
|
||||
err,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
throw new FileNotFountException(`Error reading ${path}`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a file exists in any of the configured storages.
|
||||
* @param path - The path of the file to check.
|
||||
* @param options
|
||||
* @returns A boolean indicating whether the file exists in any storage.
|
||||
*/
|
||||
exists = async (path: string, options?: ReadOptions): Promise<boolean> => {
|
||||
for (const storage of this.storages) {
|
||||
if (await storage.exists(path, options)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes a file from all configured storages.
|
||||
* @param path - The path of the file to be removed.
|
||||
* @param options
|
||||
*/
|
||||
remove = async (path: string, options?: DeleteOptions): Promise<boolean> => {
|
||||
return Promise.all(this.storages.map(storage => storage.remove(path, options))).then(array => {
|
||||
return array.reduce((a, b) => a && b);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw when read from one of the storages is filed.
|
||||
*/
|
||||
class StorageException extends Error {
|
||||
constructor(readonly storageId: string, details: string, error: Error) {
|
||||
super(details, error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw when read from one of the storages is filed.
|
||||
*/
|
||||
class OneOfStorageReadOneFailedException extends StorageException {}
|
||||
/**
|
||||
* Thrown when write operation to one of the storages is failed.
|
||||
*/
|
||||
class OneOfStorageWriteOneFailedException extends StorageException {}
|
||||
@@ -23,6 +23,12 @@ export type DeleteOptions = {
|
||||
};
|
||||
|
||||
export interface StorageConnectorAPI {
|
||||
/**
|
||||
* Returns identifier of a storage that should've been set in configuration.
|
||||
*
|
||||
*/
|
||||
getId(): string;
|
||||
|
||||
/**
|
||||
* Write a stream to a path
|
||||
*
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
TdriveServiceOptions,
|
||||
} from "../../framework";
|
||||
import LocalConnectorService, { LocalConfiguration } from "./connectors/local/service";
|
||||
import S3ConnectorService from "./connectors/S3/s3-service";
|
||||
import S3ConnectorService, { S3Configuration } from "./connectors/S3/s3-service";
|
||||
import StorageAPI, {
|
||||
DeleteOptions,
|
||||
ReadOptions,
|
||||
@@ -18,6 +18,10 @@ import StorageAPI, {
|
||||
WriteOptions,
|
||||
} from "./provider";
|
||||
|
||||
import { OneOfStorageStrategy } from "./oneof-storage-strategy";
|
||||
import { DefaultStorageStrategy } from "./default-storage-strategy";
|
||||
import { FileNotFountException } from "./exceptions";
|
||||
|
||||
type EncryptionConfiguration = {
|
||||
secret: string | null;
|
||||
iv: string | null;
|
||||
@@ -35,26 +39,14 @@ export default class StorageService extends TdriveService<StorageAPI> implements
|
||||
* But for the local storage it's a default value
|
||||
* @private
|
||||
*/
|
||||
private homeDir = "/tdrive";
|
||||
private homeDir = "tdrive";
|
||||
|
||||
constructor(protected options?: TdriveServiceOptions<TdriveServiceConfiguration>) {
|
||||
super(options);
|
||||
const type = this.getConnectorType();
|
||||
if (type === "S3") {
|
||||
logger.info("Using 'S3' connector for storage.");
|
||||
try {
|
||||
this.homeDir = this.configuration.get<string>("S3.homeDirectory");
|
||||
} catch (e) {
|
||||
this.logger.warn("Home directory is not set, using S3.bucket instead");
|
||||
}
|
||||
if (!this.homeDir) {
|
||||
this.homeDir = this.configuration.get<string>("S3.bucket");
|
||||
}
|
||||
if (this.homeDir && this.homeDir.startsWith("/")) {
|
||||
this.logger.error("For S3 connector home directory MUST NOT start with '/'");
|
||||
throw new Error("For S3 connector home directory MUST NOT start with '/'");
|
||||
}
|
||||
}
|
||||
//init home directory variable
|
||||
this.initHomeDirectory();
|
||||
//init connector to storage
|
||||
this.getConnector();
|
||||
}
|
||||
|
||||
api(): StorageAPI {
|
||||
@@ -67,31 +59,7 @@ export default class StorageService extends TdriveService<StorageAPI> implements
|
||||
|
||||
getConnector(): StorageConnectorAPI {
|
||||
if (!this.connector) {
|
||||
const type = this.getConnectorType();
|
||||
if (type === "S3") {
|
||||
logger.info("Using 'S3' connector for storage.");
|
||||
this.connector = new S3ConnectorService({
|
||||
bucket: this.configuration.get<string>("S3.bucket"),
|
||||
region: this.configuration.get<string>("S3.region"),
|
||||
endPoint: this.configuration.get<string>("S3.endPoint"),
|
||||
port: Number(this.configuration.get<number>("S3.port")),
|
||||
useSSL: Boolean(this.configuration.get<boolean>("S3.useSSL")),
|
||||
accessKey: this.configuration.get<string>("S3.accessKey"),
|
||||
secretKey: this.configuration.get<string>("S3.secretKey"),
|
||||
disableRemove: this.configuration.get<boolean>("S3.disableRemove"),
|
||||
});
|
||||
} else {
|
||||
logger.info(
|
||||
`Using 'local' connector for storage${
|
||||
type === "local" ? "" : " (no other connector recognized from configuration type: '%s')"
|
||||
}.`,
|
||||
type,
|
||||
);
|
||||
logger.trace(`Home directory for the storage: ${this.homeDir}`);
|
||||
this.connector = new LocalConnectorService(
|
||||
this.configuration.get<LocalConfiguration>("local"),
|
||||
);
|
||||
}
|
||||
this.connector = this.getStorageStrategy();
|
||||
}
|
||||
return this.connector;
|
||||
}
|
||||
@@ -101,7 +69,8 @@ export default class StorageService extends TdriveService<StorageAPI> implements
|
||||
}
|
||||
|
||||
exists(path: string, options?: ReadOptions): Promise<boolean> {
|
||||
return this.getConnector().exists(path, options);
|
||||
//TODO[ASH] check for all the file chunks
|
||||
return this.getConnector().exists(path + "/chunk1", options);
|
||||
}
|
||||
|
||||
async write(path: string, stream: Stream, options?: WriteOptions): Promise<WriteMetadata> {
|
||||
@@ -134,15 +103,15 @@ export default class StorageService extends TdriveService<StorageAPI> implements
|
||||
}
|
||||
|
||||
async read(path: string, options?: ReadOptions): Promise<Readable> {
|
||||
if (!(await this.exists(path, options))) {
|
||||
throw new FileNotFountException();
|
||||
}
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self = this;
|
||||
const chunks = options?.totalChunks || 1;
|
||||
let count = 1;
|
||||
|
||||
// Check if the first chunk or file exists
|
||||
await self._read(options?.totalChunks ? `${path}/chunk${count}` : path);
|
||||
|
||||
async function factory(callback: (err?: Error, stream?: Stream) => unknown) {
|
||||
if (count > chunks) {
|
||||
callback();
|
||||
@@ -216,4 +185,113 @@ export default class StorageService extends TdriveService<StorageAPI> implements
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates storage strategy with configuration.
|
||||
* "storage": {
|
||||
* "secret": "",
|
||||
* "iv": "",
|
||||
* "strategy": "oneof",
|
||||
* "type": "local",
|
||||
* "S3": {
|
||||
* "endPoint": "play.min.io",
|
||||
* "port": 9000,
|
||||
* "useSSL": false,
|
||||
* "accessKey": "ABCD",
|
||||
* "secretKey": "x1yz",
|
||||
* "disableRemove": false
|
||||
* },
|
||||
* "local": {
|
||||
* "path": "/tdrive"
|
||||
* },
|
||||
* "oneof": [
|
||||
* {
|
||||
* "type": "S3",
|
||||
* "S3": {}
|
||||
* },
|
||||
* {
|
||||
* "type": "local",
|
||||
* "local": {}
|
||||
* }]
|
||||
* },
|
||||
*/
|
||||
getStorageStrategy(): StorageConnectorAPI {
|
||||
const strategy = this.configuration.get<string>("strategy");
|
||||
if (strategy == "oneof") {
|
||||
logger.info("Creating storage with 'oneof' strategy");
|
||||
const connectors = this.configuration
|
||||
.get<Array<StorageConfiguration>>("oneof")
|
||||
.map(c => this.createConnector(c));
|
||||
return new OneOfStorageStrategy(connectors);
|
||||
} else {
|
||||
logger.info("Creating storage with 'default' strategy");
|
||||
return new DefaultStorageStrategy(this.createConnectorFromConfiguration(this.configuration));
|
||||
}
|
||||
}
|
||||
|
||||
createConnector(config: StorageConfiguration) {
|
||||
const type = config.type;
|
||||
if (type === "S3") {
|
||||
return this.newS3Connector(config.S3);
|
||||
} else {
|
||||
return this.newLocalConnector(config.local, type);
|
||||
}
|
||||
}
|
||||
|
||||
createConnectorFromConfiguration(config: TdriveServiceConfiguration) {
|
||||
const type = config.get<string>("type");
|
||||
if (type === "S3") {
|
||||
return this.newS3Connector(config.get("S3"));
|
||||
} else {
|
||||
return this.newLocalConnector(this.configuration.get<LocalConfiguration>("local"), type);
|
||||
}
|
||||
}
|
||||
|
||||
newS3Connector(config: S3Configuration) {
|
||||
logger.info("Using 'S3' connector for storage.");
|
||||
return new S3ConnectorService(config);
|
||||
}
|
||||
|
||||
newLocalConnector(config: LocalConfiguration, type: string) {
|
||||
logger.info(
|
||||
`Using 'local' connector for storage${
|
||||
type === "local" ? "" : " (no other connector recognized from configuration type: '%s')"
|
||||
}.`,
|
||||
type,
|
||||
);
|
||||
logger.trace(`Home directory for the storage: ${this.homeDir}`);
|
||||
return new LocalConnectorService(config);
|
||||
}
|
||||
|
||||
initHomeDirectory() {
|
||||
const type = this.getConnectorType();
|
||||
if (type === "S3") {
|
||||
logger.info("Using 'S3' connector for storage.");
|
||||
try {
|
||||
this.homeDir = this.configuration.get<string>("S3.homeDirectory");
|
||||
} catch (e) {
|
||||
this.logger.warn("Home directory is not set, using S3.bucket instead");
|
||||
}
|
||||
if (!this.homeDir) {
|
||||
this.homeDir = this.configuration.get<string>("S3.bucket");
|
||||
}
|
||||
if (this.homeDir && this.homeDir.startsWith("/")) {
|
||||
this.logger.error("For S3 connector home directory MUST NOT start with '/'");
|
||||
throw new Error("For S3 connector home directory MUST NOT start with '/'");
|
||||
}
|
||||
} else {
|
||||
this.logger.info("For 'local' connector setting home directory to '/tdrive'");
|
||||
this.homeDir = "/tdrive";
|
||||
}
|
||||
}
|
||||
|
||||
getId() {
|
||||
return this.connector.getId();
|
||||
}
|
||||
}
|
||||
|
||||
type StorageConfiguration = {
|
||||
type: string;
|
||||
S3?: S3Configuration;
|
||||
local?: LocalConfiguration;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Analytics, { IdentifyParams, TrackParams } from "@segment/analytics-node";
|
||||
import { Analytics as AnalyticsAbtract } from "./types";
|
||||
import axios, { AxiosInstance } from "axios";
|
||||
import { logger } from "../../../framework/logger";
|
||||
|
||||
export default class Segment implements AnalyticsAbtract {
|
||||
protected version = "5.0.0"; //Segment analytics lib version
|
||||
@@ -33,7 +34,7 @@ export default class Segment implements AnalyticsAbtract {
|
||||
try {
|
||||
this.analytics.identify(message as IdentifyParams, callback);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
logger.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +48,7 @@ export default class Segment implements AnalyticsAbtract {
|
||||
try {
|
||||
this.analytics.track(message as TrackParams, callback);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
logger.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import { logger } from "../../framework/logger";
|
||||
|
||||
function serverErrorHandler(server: FastifyInstance): void {
|
||||
server.setErrorHandler(async (err, request, reply) => {
|
||||
console.error(`Got ${reply.statusCode} error on request ${request.id} : `, err);
|
||||
logger.error(`Got ${reply.statusCode} error on request ${request.id} : `, err);
|
||||
server.log.debug(`Got ${reply.statusCode} error on request ${request.id} : ${err.toString()}`);
|
||||
await reply.send(
|
||||
reply.statusCode == 500
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Initializable, TdriveServiceProvider } from "../../../core/platform/framework";
|
||||
import { Initializable, logger, TdriveServiceProvider } from "../../../core/platform/framework";
|
||||
import { ListResult, Paginable } from "../../../core/platform/framework/api/crud-service";
|
||||
import gr from "../../global-resolver";
|
||||
import {
|
||||
@@ -39,7 +39,7 @@ export class CompanyApplicationServiceImpl implements TdriveServiceProvider, Ini
|
||||
app.application.api = null;
|
||||
return app;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
logger.error(err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ export const getAccessLevel = async (
|
||||
);
|
||||
if (matchingChannel) return matchingChannel.level;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
logger.info(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ export const getSharedByUser = (
|
||||
return getGrantorAndThrowIfEmpty(entity);
|
||||
}
|
||||
if (entity.type === "company" && entity.id === context.company.id && entity.level != "none") {
|
||||
console.log("company", entity);
|
||||
logger.info("company", entity);
|
||||
return getGrantorAndThrowIfEmpty(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export class DocumentsProcessor
|
||||
);
|
||||
content_keywords = await getKeywordsOfFile(storedFile.mime, storedFile.name, storedFile.file);
|
||||
} catch (error) {
|
||||
console.debug(error);
|
||||
logger.debug(error);
|
||||
logger.error({ error: `${error}` }, "Failed to generate content keywords");
|
||||
}
|
||||
return { content_keywords, item: message.item };
|
||||
|
||||
@@ -470,7 +470,7 @@ export class DocumentsService {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("🚀🚀 error:", error);
|
||||
logger.error(error, "🚀🚀 error:");
|
||||
}
|
||||
|
||||
await this.repository.save(driveItem);
|
||||
@@ -557,6 +557,16 @@ export class DocumentsService {
|
||||
throw Error("Move operation not permitted");
|
||||
} else {
|
||||
oldParent = item.parent_id;
|
||||
const newParentId = content.parent_id;
|
||||
const needRenameTo = await getItemName(
|
||||
newParentId,
|
||||
item.id,
|
||||
item.name,
|
||||
item.is_directory,
|
||||
this.repository,
|
||||
context,
|
||||
);
|
||||
if (needRenameTo !== item.name) renamedTo = item.name = needRenameTo;
|
||||
}
|
||||
if (key === "access_info") {
|
||||
// if manage access is disabled, we don't allow changing access level
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { FastifyInstance, FastifyPluginCallback } from "fastify";
|
||||
import { DocumentsController } from "./controllers";
|
||||
import { createDocumentSchema, createVersionSchema, beginEditingSchema } from "./schemas";
|
||||
// import profilerPlugin from "../../../utils/profiler";
|
||||
|
||||
const baseUrl = "/companies/:company_id";
|
||||
const serviceUrl = `${baseUrl}/item`;
|
||||
@@ -10,11 +9,6 @@ const editingSessionBase = "/editing_session/:editing_session_key";
|
||||
const routes: FastifyPluginCallback = (fastify: FastifyInstance, _options, next) => {
|
||||
const documentsController = new DocumentsController();
|
||||
|
||||
// fastify.register(profilerPlugin, {
|
||||
// active: documentsController.profilingEnabled,
|
||||
// outputDir: "profiles",
|
||||
// });
|
||||
|
||||
fastify.route({
|
||||
method: "GET",
|
||||
url: `${serviceUrl}`,
|
||||
|
||||
@@ -431,7 +431,7 @@ export class FileServiceImpl {
|
||||
id: externalId,
|
||||
company_id: "00000000-0000-4000-0000-000000000000",
|
||||
});
|
||||
const exist = await gr.platformServices.storage.exists(getFilePath(file) + "/chunk1");
|
||||
const exist = await gr.platformServices.storage.exists(getFilePath(file));
|
||||
if (exist) {
|
||||
return { exist: true, file };
|
||||
} else {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { UploadOptions } from "../../types";
|
||||
import { PublicFile } from "../../entities/file";
|
||||
import gr from "../../../global-resolver";
|
||||
import { formatAttachmentContentDispositionHeader } from "../../utils";
|
||||
import { logger } from "../../../../core/platform/framework";
|
||||
|
||||
export class FileController {
|
||||
async save(
|
||||
@@ -54,7 +55,7 @@ export class FileController {
|
||||
response.type(data.mime);
|
||||
return response.send(data.file);
|
||||
} catch (e) {
|
||||
console.log("!!!" + e);
|
||||
logger.info(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -80,7 +81,7 @@ export class FileController {
|
||||
response.send(data.file);
|
||||
return response;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
logger.error(err);
|
||||
response.statusCode = 500;
|
||||
response.send("");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { fromPath } from "pdf2pic";
|
||||
import { mkdirSync } from "fs";
|
||||
import { cleanFiles, getTmpFile } from "../../../../../utils/files";
|
||||
import { logger } from "../../../../../core/platform/framework";
|
||||
|
||||
class PDFConversionError extends Error {}
|
||||
|
||||
export async function convertFromPdf(
|
||||
inputPath: string,
|
||||
@@ -33,11 +36,14 @@ export async function convertFromPdf(
|
||||
//Just no more page to convert
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
const pdfConversionError = new PDFConversionError("Can't convert file with pdf-image.", {
|
||||
cause: error,
|
||||
});
|
||||
logger.error(pdfConversionError);
|
||||
for (const file of pages) {
|
||||
cleanFiles([file]);
|
||||
}
|
||||
throw Error("Can't convert file with pdf-image.");
|
||||
throw pdfConversionError;
|
||||
}
|
||||
return { output: pages, done: true };
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
CompanyStatsObject,
|
||||
CompanyUserObject,
|
||||
} from "./web/types";
|
||||
import { logger } from "../../core/platform/framework";
|
||||
|
||||
export function formatCompany(
|
||||
companyEntity: Company,
|
||||
@@ -75,6 +76,8 @@ export function formatCompany(
|
||||
},
|
||||
);
|
||||
|
||||
logger.info("🚀🚀 res.plan.features: ", res.plan.features);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -490,7 +490,7 @@ export class WorkspaceServiceImpl implements TdriveServiceProvider, Initializabl
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
logger.warn(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import WorkspacePendingUser from "../../entities/workspace_pending_users";
|
||||
import { ConsoleCompany, CreateConsoleUser } from "../../../console/types";
|
||||
import { hasCompanyAdminLevel } from "../../../../utils/company";
|
||||
import gr from "../../../global-resolver";
|
||||
import { logger } from "../../../../core/platform/framework";
|
||||
|
||||
export class WorkspaceUsersCrudController
|
||||
implements
|
||||
@@ -525,7 +526,7 @@ export class WorkspaceUsersCrudController
|
||||
|
||||
return { status: "success" };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
logger.warn(e);
|
||||
return {
|
||||
status: "error",
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { mkdirSync, existsSync, promises as fsPromise, createWriteStream, readFileSync } from "fs";
|
||||
import { Readable } from "stream";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { logger } from "../core/platform/framework";
|
||||
|
||||
const { unlink } = fsPromise;
|
||||
|
||||
@@ -50,7 +51,7 @@ export const writeToTemporaryFile = async (input: Readable, extension: string):
|
||||
|
||||
return temporaryFilePath;
|
||||
} catch (error) {
|
||||
console.debug(error);
|
||||
logger.debug(error);
|
||||
|
||||
throw Error(error);
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import fs from "fs";
|
||||
import fp from "fastify-plugin";
|
||||
import v8profiler from "v8-profiler-next";
|
||||
|
||||
export class Profiler {
|
||||
title: string;
|
||||
active: boolean;
|
||||
outputDir: string;
|
||||
constructor(options) {
|
||||
const { title, active, outputDir } = options;
|
||||
this.title = title;
|
||||
this.active = active;
|
||||
this.outputDir = outputDir;
|
||||
}
|
||||
|
||||
start() {
|
||||
if (this.active) {
|
||||
v8profiler.startProfiling(this.title, true);
|
||||
}
|
||||
}
|
||||
|
||||
finish() {
|
||||
if (this.active) {
|
||||
const profile = v8profiler.stopProfiling(this.title);
|
||||
if (profile === undefined) {
|
||||
console.log("profile is undefined: ", this.title);
|
||||
return;
|
||||
}
|
||||
profile.export((error, result) => {
|
||||
if (error) {
|
||||
console.log("Profiling error: ", error);
|
||||
} else {
|
||||
fs.writeFileSync(`${process.cwd()}/${this.outputDir}/${this.title}.cpuprofile`, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function profilerPlugin(fastify, options) {
|
||||
fastify.addHook("onRequest", async request => {
|
||||
const profiler = new Profiler({
|
||||
title: `${request.method}-${request.url}`,
|
||||
active: options.active,
|
||||
outputDir: options.outputDir || "profiles",
|
||||
});
|
||||
|
||||
profiler.start();
|
||||
|
||||
// Attach profiler to request for access in routes or other hooks
|
||||
request.profiler = profiler;
|
||||
});
|
||||
|
||||
fastify.addHook("onResponse", async request => {
|
||||
if (request.profiler) {
|
||||
request.profiler.finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default fp(profilerPlugin);
|
||||
@@ -6,6 +6,9 @@ import UserApi from "../common/user-api";
|
||||
describe("The Documents Browser Window and API", () => {
|
||||
let platform: TestPlatform;
|
||||
let currentUser: UserApi;
|
||||
let sharedWIthMeFolder: string;
|
||||
let myDriveId: string;
|
||||
let files: any;
|
||||
|
||||
beforeEach(async () => {
|
||||
platform = await init({
|
||||
@@ -25,75 +28,63 @@ describe("The Documents Browser Window and API", () => {
|
||||
],
|
||||
});
|
||||
currentUser = await UserApi.getInstance(platform);
|
||||
sharedWIthMeFolder = "shared_with_me";
|
||||
myDriveId = "user_" + currentUser.user.id;
|
||||
files = await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
expect(files).toBeDefined();
|
||||
expect(files.entries()).toBeDefined();
|
||||
expect(Array.from(files.entries())).toHaveLength(UserApi.ALL_FILES.length);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await platform?.tearDown();
|
||||
// @ts-ignore
|
||||
platform = null;
|
||||
});
|
||||
|
||||
describe("My Drive", () => {
|
||||
|
||||
it("Should successfully upload filed to the 'Shared Drive' and browse them", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
const result = await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.entries()).toBeDefined();
|
||||
expect(Array.from(result.entries())).toHaveLength(UserApi.ALL_FILES.length);
|
||||
|
||||
|
||||
it("Should successfully upload filed to the 'My Drive' and browse them", async () => {
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {});
|
||||
expect(docs).toBeDefined();
|
||||
expect(docs.children).toBeDefined();
|
||||
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length)
|
||||
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length);
|
||||
});
|
||||
|
||||
it("Should not be visible for other users", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {});
|
||||
expect(docs).toBeDefined();
|
||||
expect(docs.children).toBeDefined();
|
||||
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length)
|
||||
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length);
|
||||
|
||||
const anotherUserDocs = await anotherUser.searchDocument({});
|
||||
expect(anotherUserDocs).toBeDefined();
|
||||
expect(anotherUserDocs.entities).toBeDefined();
|
||||
expect(anotherUserDocs.entities.length).toEqual(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Shared Drive", () => {
|
||||
|
||||
it("Should successfully upload filed to the 'Shared Drive' and browse them", async () => {
|
||||
const result = await currentUser.uploadAllFilesOneByOne("root");
|
||||
expect(result).toBeDefined();
|
||||
expect(result.entries()).toBeDefined();
|
||||
expect(Array.from(result.entries())).toHaveLength(UserApi.ALL_FILES.length);
|
||||
|
||||
|
||||
const docs = await currentUser.browseDocuments("root", {});
|
||||
expect(docs).toBeDefined();
|
||||
expect(docs.children).toBeDefined();
|
||||
expect(docs.children.length).toEqual(UserApi.ALL_FILES.length);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("Shared With Me", () => {
|
||||
it("Shouldn't contain user personal files", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
await currentUser.uploadAllFilesOneByOne("user_" + currentUser.user.id);
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
|
||||
let docs = await currentUser.browseDocuments(sharedWIthMeFolder, {});
|
||||
expect(docs).toBeDefined();
|
||||
expect(docs.children?.length).toEqual(0)
|
||||
expect(docs.children?.length).toEqual(0);
|
||||
|
||||
await currentUser.uploadAllFilesOneByOne("root");
|
||||
docs = await currentUser.browseDocuments("shared_with_me", {});
|
||||
@@ -103,11 +94,7 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should contain files that were shared with the user", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
|
||||
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
|
||||
//then:: files are not searchable for user without permissions
|
||||
expect((await anotherUser.browseDocuments("shared_with_me", {})).children).toHaveLength(0);
|
||||
@@ -119,48 +106,49 @@ describe("The Documents Browser Window and API", () => {
|
||||
level: "read",
|
||||
grantor: null,
|
||||
});
|
||||
await oneUser.updateDocument(files[0].id, files[0]);
|
||||
await currentUser.updateDocument(files[0].id, files[0]);
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
//then file become searchable
|
||||
expect((await anotherUser.browseDocuments("shared_with_me", {pageSize: 1})).children).toHaveLength(1);
|
||||
expect(
|
||||
(await anotherUser.browseDocuments("shared_with_me", { pageSize: 1 })).children,
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("Should return ALL the files that was share by user at one", async () => {
|
||||
const oneUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
|
||||
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
|
||||
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
|
||||
await anotherUser.uploadAllFilesOneByOne();
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
|
||||
//give permissions to the file
|
||||
files[2].access_info.entities.push({
|
||||
type: "user",
|
||||
id: anotherUser.user.id,
|
||||
level: "read",
|
||||
// @ts-ignore
|
||||
grantor: null,
|
||||
});
|
||||
await oneUser.updateDocument(files[2].id, files[2]);
|
||||
await currentUser.updateDocument(files[2].id, files[2]);
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
//then file become searchable
|
||||
expect((await anotherUser.browseDocuments("shared_with_me", {pagination: {limitStr: 100}})).children).toHaveLength(1);
|
||||
expect(
|
||||
(await anotherUser.browseDocuments("shared_with_me", { pagination: { limitStr: 100 } }))
|
||||
.children,
|
||||
).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("User should be able to delete file that was shared with him with 'manage' permissions", async () => {
|
||||
const oneUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
|
||||
const anotherUser = await UserApi.getInstance(platform, true, {companyRole: "admin"});
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
|
||||
let files = await oneUser.uploadAllFilesOneByOne("user_" + oneUser.user.id);
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
let toDeleteDoc = files[2];
|
||||
toDeleteDoc.access_info.entities.push({
|
||||
type: "user",
|
||||
id: anotherUser.user.id,
|
||||
level: "manage",
|
||||
// @ts-ignore
|
||||
grantor: null,
|
||||
});
|
||||
await oneUser.updateDocument(toDeleteDoc.id, toDeleteDoc);
|
||||
@@ -172,19 +160,20 @@ describe("The Documents Browser Window and API", () => {
|
||||
it("User should be able to delete folder with the files that was shared with him with 'manage' permissions", async () => {
|
||||
const oneUser = await UserApi.getInstance(platform, true);
|
||||
const anotherUser = await UserApi.getInstance(platform, true);
|
||||
|
||||
|
||||
const dir = await oneUser.createDirectory("user_" + oneUser.user.id);
|
||||
const level2Dir = await oneUser.createDirectory(dir.id);
|
||||
const level2Dir2 = await oneUser.createDirectory(dir.id);
|
||||
await oneUser.uploadAllFilesOneByOne(level2Dir.id);
|
||||
await oneUser.uploadAllFilesOneByOne(level2Dir2.id);
|
||||
await oneUser.uploadAllFilesOneByOne(dir.id);
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
dir.access_info.entities.push({
|
||||
type: "user",
|
||||
id: anotherUser.user.id,
|
||||
level: "manage",
|
||||
// @ts-ignore
|
||||
grantor: null,
|
||||
});
|
||||
await oneUser.updateDocument(dir.id, dir);
|
||||
@@ -203,6 +192,7 @@ describe("The Documents Browser Window and API", () => {
|
||||
type: "user",
|
||||
id: anotherUser.user.id,
|
||||
level: "manage",
|
||||
// @ts-ignore
|
||||
grantor: null,
|
||||
});
|
||||
await oneUser.updateDocument(dir.id, dir);
|
||||
@@ -220,7 +210,5 @@ describe("The Documents Browser Window and API", () => {
|
||||
sharedDocs = await anotherUser.browseDocuments("shared_with_me");
|
||||
expect(sharedDocs.children.length).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ describe("The Drive feature", () => {
|
||||
const files = await oneUser.uploadAllFilesOneByOne();
|
||||
|
||||
// Wait for file processing
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
// Share the file with recipient user
|
||||
await anotherUser.shareWithPermissions(files[1], anotherUser.user.id, "read");
|
||||
|
||||
@@ -3,8 +3,12 @@ import { init, TestPlatform } from "../setup";
|
||||
import UserApi from "../common/user-api";
|
||||
|
||||
describe("The Documents Browser Window and API", () => {
|
||||
let sharedWIthMeFolder: string;
|
||||
let platform: TestPlatform;
|
||||
let currentUser: UserApi;
|
||||
let anotherUser: UserApi;
|
||||
let myDriveId: string;
|
||||
let files: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
platform = await init({
|
||||
@@ -23,19 +27,24 @@ describe("The Documents Browser Window and API", () => {
|
||||
"documents",
|
||||
],
|
||||
});
|
||||
currentUser = await UserApi.getInstance(platform);
|
||||
currentUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
myDriveId = "user_" + currentUser.user.id;
|
||||
sharedWIthMeFolder = "shared_with_me";
|
||||
files = await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
for (const file of files) {
|
||||
await currentUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await platform?.tearDown();
|
||||
// @ts-ignore
|
||||
platform = null;
|
||||
});
|
||||
|
||||
describe("Pagination and Sorting", () => {
|
||||
it("Should paginate documents correctly", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
let page_token = "1";
|
||||
const limitStr = "2";
|
||||
let docs = await currentUser.browseDocuments(myDriveId, {
|
||||
@@ -60,9 +69,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort documents by name in ascending order", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
const sortBy = "name";
|
||||
const sortOrder = "asc";
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {
|
||||
@@ -75,9 +81,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort documents by name in descending order", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
const sortBy = "name";
|
||||
const sortOrder = "desc";
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {
|
||||
@@ -90,9 +93,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort documents by date in ascending order", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
const sortBy = "date";
|
||||
const sortOrder = "asc";
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {
|
||||
@@ -107,9 +107,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort documents by date in descending order", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
const sortBy = "date";
|
||||
const sortOrder = "desc";
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {
|
||||
@@ -124,9 +121,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort documents by size in ascending order", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
const sortBy = "size";
|
||||
const sortOrder = "asc";
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {
|
||||
@@ -139,9 +133,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort documents by size in descending order", async () => {
|
||||
const myDriveId = "user_" + currentUser.user.id;
|
||||
await currentUser.uploadAllFilesOneByOne(myDriveId);
|
||||
|
||||
const sortBy = "size";
|
||||
const sortOrder = "desc";
|
||||
const docs = await currentUser.browseDocuments(myDriveId, {
|
||||
@@ -154,17 +145,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should paginate shared with me ", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
for (const file of files) {
|
||||
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
|
||||
// wait for files to be indexed
|
||||
await new Promise(r => setTimeout(r, 5000));
|
||||
|
||||
let page_token: any = "1";
|
||||
const limitStr = "2";
|
||||
let docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
|
||||
@@ -189,13 +169,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort shared with me by name in ascending order", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
for (const file of files) {
|
||||
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
const sortBy = "name";
|
||||
const sortOrder = "asc";
|
||||
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
|
||||
@@ -208,13 +181,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort shared with me by name in descending order", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
for (const file of files) {
|
||||
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
const sortBy = "name";
|
||||
const sortOrder = "desc";
|
||||
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
|
||||
@@ -227,13 +193,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort shared with me by size in ascending order", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
for (const file of files) {
|
||||
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
const sortBy = "size";
|
||||
const sortOrder = "asc";
|
||||
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
|
||||
@@ -246,13 +205,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort shared with me by size in descending order", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
for (const file of files) {
|
||||
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
const sortBy = "size";
|
||||
const sortOrder = "desc";
|
||||
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
|
||||
@@ -265,13 +217,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort shared with me by date in ascending order", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
for (const file of files) {
|
||||
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
const sortBy = "date";
|
||||
const sortOrder = "asc";
|
||||
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
|
||||
@@ -286,13 +231,6 @@ describe("The Documents Browser Window and API", () => {
|
||||
});
|
||||
|
||||
it("Should sort shared with me by date in descending order", async () => {
|
||||
const sharedWIthMeFolder = "shared_with_me";
|
||||
const oneUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
const anotherUser = await UserApi.getInstance(platform, true, { companyRole: "admin" });
|
||||
let files = await oneUser.uploadAllFilesOneByOne();
|
||||
for (const file of files) {
|
||||
await oneUser.shareWithPermissions(file, anotherUser.user.id, "read");
|
||||
}
|
||||
const sortBy = "date";
|
||||
const sortOrder = "desc";
|
||||
const docs = await anotherUser.browseDocuments(sharedWIthMeFolder, {
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// @ts-ignore
|
||||
import path from "path";
|
||||
// @ts-ignore
|
||||
import config from "config";
|
||||
|
||||
const ourConfigDir = path.join(__dirname, 'oneof-storage');
|
||||
let configs = config.util.loadFileConfigs(ourConfigDir);
|
||||
config.util.extendDeep(config, configs);
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
|
||||
"storage": {
|
||||
"secret": "0ea28a329df23220fa814e005bfb671c",
|
||||
"iv": "1234abcd00000000",
|
||||
"strategy": "oneof",
|
||||
"oneof": [
|
||||
{
|
||||
"type": "local",
|
||||
"local": {
|
||||
"path": "-tmp/storage1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "local",
|
||||
"local": {
|
||||
"path": "/tmp/storage2"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import "./load_test_config"
|
||||
import "reflect-metadata";
|
||||
import { afterAll, beforeAll, afterEach, describe, expect, it } from "@jest/globals";
|
||||
import { init, TestPlatform } from "../setup";
|
||||
import UserApi from "../common/user-api";
|
||||
import LocalConnectorService from "../../../src/core/platform/services/storage/connectors/local/service"
|
||||
import { StorageConnectorAPI } from "../../../src/core/platform/services/storage/provider";
|
||||
|
||||
describe("The OneOf Storage feature", () => {
|
||||
const url = "/internal/services/files/v1";
|
||||
let platform: TestPlatform;
|
||||
let helpers: UserApi;
|
||||
|
||||
beforeAll(async () => {
|
||||
platform = await init({
|
||||
services: ["webserver", "database", "storage", "files", "previews"],
|
||||
});
|
||||
helpers = await UserApi.getInstance(platform);
|
||||
}, 300000000);
|
||||
|
||||
afterEach(async () => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await platform?.tearDown();
|
||||
platform = null;
|
||||
});
|
||||
|
||||
describe("On file upload", () => {
|
||||
|
||||
it("should fail an upload POST when ALL backend storage fails", async () => {
|
||||
const thrower = () => {
|
||||
throw new Error("<Mock error done on purpose on upload to storage (for the E2E test)>");
|
||||
};
|
||||
const writeLocalMock = jest.spyOn(LocalConnectorService.prototype, "write").mockRejectedValue("Error");
|
||||
|
||||
// expect(response.statusCode).toBe(500);
|
||||
await expect(helpers.uploadRandomFile()).rejects.toThrow("Error code: 500");
|
||||
|
||||
// expect(response.statusCode).toBe(500);
|
||||
expect(writeLocalMock.mock.calls.length).toEqual(2);
|
||||
});
|
||||
|
||||
it("should successfully upload file when one backend storage fails", async () => {
|
||||
const thrower = () => {
|
||||
throw new Error("<Mock error done on purpose on upload to storage (for the E2E test)>");
|
||||
};
|
||||
|
||||
const connectors = (platform.storage.getConnector() as any).storages as Array<StorageConnectorAPI>;
|
||||
|
||||
const writeLocalMock = jest.spyOn(connectors[0], "write").mockRejectedValue("Error");
|
||||
|
||||
// expect(response.statusCode).toBe(200);
|
||||
const filesUpload = await helpers.uploadRandomFile();
|
||||
expect(filesUpload.id).toBeTruthy();
|
||||
|
||||
// expect failed upload
|
||||
expect(writeLocalMock.mock.calls.length).toBeGreaterThan(0);
|
||||
//expect that file can be downloaded
|
||||
const fileDownloadResponse = await platform.app.inject({
|
||||
method: "GET",
|
||||
url: `${url}/companies/${platform.workspace.company_id}/files/${filesUpload.id}/download`,
|
||||
});
|
||||
expect(fileDownloadResponse).toBeTruthy();
|
||||
expect(fileDownloadResponse.statusCode).toBe(200);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,185 @@
|
||||
import { Readable, PassThrough } from 'stream';
|
||||
import { OneOfStorageStrategy } from "../../../../../src/core/platform/services/storage/oneof-storage-strategy"; // Adjust the import path as necessary
|
||||
import {StorageConnectorAPI } from "../../../../../src/core/platform/services/storage/provider"; // Adjust the import path as necessary
|
||||
|
||||
function mockStream() {
|
||||
const stream = new Readable();
|
||||
stream.push("Test data");
|
||||
stream.push(null);
|
||||
return stream;
|
||||
}
|
||||
|
||||
function mockStorage(size: number) {
|
||||
return {
|
||||
write: jest.fn().mockResolvedValue({ size: size }),
|
||||
read: jest.fn(),
|
||||
exists: jest.fn(),
|
||||
remove: jest.fn().mockResolvedValue(true),
|
||||
getId: jest.fn().mockResolvedValue("Mock Storage ID")
|
||||
} as unknown as StorageConnectorAPI;
|
||||
}
|
||||
|
||||
describe('OneOfStorageStrategy', () => {
|
||||
let storage1: StorageConnectorAPI;
|
||||
let storage2: StorageConnectorAPI;
|
||||
let storage3: StorageConnectorAPI;
|
||||
let oneOfStorageStrategy: OneOfStorageStrategy;
|
||||
|
||||
beforeEach(() => {
|
||||
// Mocking two storage backends
|
||||
storage1 = mockStorage(100);
|
||||
storage2 = mockStorage(200);
|
||||
storage3 = mockStorage(300);
|
||||
|
||||
oneOfStorageStrategy = new OneOfStorageStrategy([storage1, storage2, storage3]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('write', () => {
|
||||
it('should write to all configured storages', async () => {
|
||||
const path = 'test/path';
|
||||
const stream = mockStream();
|
||||
|
||||
const result = await oneOfStorageStrategy.write(path, stream);
|
||||
|
||||
expect(storage1.write).toHaveBeenCalled();
|
||||
expect(storage2.write).toHaveBeenCalled();
|
||||
expect(result.size).toBe(100); // Assuming the first storage returned this size
|
||||
});
|
||||
|
||||
it('should throw an error if all storage writes fail', async () => {
|
||||
storage1.write = jest.fn().mockRejectedValue(new Error('Write failed'));
|
||||
storage2.write = jest.fn().mockRejectedValue(new Error('Write failed'));
|
||||
storage3.write = jest.fn().mockRejectedValue(new Error('Write failed'));
|
||||
|
||||
const path = 'test/path';
|
||||
const stream = mockStream();
|
||||
await expect(oneOfStorageStrategy.write(path, stream)).rejects.toThrow('Write test/path failed for all storages');
|
||||
});
|
||||
|
||||
it('should succeed if one storage write fails but the other succeeds', async () => {
|
||||
//given
|
||||
storage1.write = jest.fn().mockRejectedValue(new Error('Write failed'));
|
||||
storage2.write = jest.fn().mockResolvedValue({ size: 200 });
|
||||
storage3.write = jest.fn().mockRejectedValue(new Error('Write failed'));
|
||||
|
||||
const path = 'test/path';
|
||||
const stream = mockStream();
|
||||
|
||||
//when
|
||||
const result = await oneOfStorageStrategy.write(path, stream);
|
||||
|
||||
//then
|
||||
expect(result.size).toBe(200); // Assuming the second storage returned this size
|
||||
});
|
||||
|
||||
it('should verify that all data was written to the storage stream', async () => {
|
||||
const data = "Test data";
|
||||
const stream = new Readable();
|
||||
stream.push(data);
|
||||
stream.push(null);
|
||||
|
||||
storage1.write = jest.fn().mockImplementation((_, stream) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let writtenData = '';
|
||||
stream.on('data', chunk => {
|
||||
writtenData += chunk;
|
||||
});
|
||||
stream.on('end', () => {
|
||||
if (writtenData === data) {
|
||||
resolve({ size: writtenData.length });
|
||||
} else {
|
||||
reject(new Error('Data mismatch'));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const result = await oneOfStorageStrategy.write("test/path", stream);
|
||||
|
||||
expect(result.size).toBe(data.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('read', () => {
|
||||
it('should read from the first storage that has the file', async () => {
|
||||
const path = 'test/path';
|
||||
const mockStream = new Readable();
|
||||
mockStream.push('Test data');
|
||||
mockStream.push(null);
|
||||
storage1.read = jest.fn().mockResolvedValue(mockStream);
|
||||
storage1.exists = jest.fn().mockResolvedValue(true);
|
||||
|
||||
const result = await oneOfStorageStrategy.read(path);
|
||||
|
||||
expect(storage1.exists).toHaveBeenCalledWith(path, undefined);
|
||||
expect(storage1.read).toHaveBeenCalledWith(path, undefined);
|
||||
expect(result).toBe(mockStream);
|
||||
});
|
||||
|
||||
it('should fallback to the next storage if the first fails', async () => {
|
||||
const path = 'test/path';
|
||||
storage1.read = jest.fn().mockRejectedValue(new Error('Read failed'));
|
||||
storage1.exists = jest.fn().mockResolvedValue(true);
|
||||
const mockStream = new Readable();
|
||||
mockStream.push('Test data');
|
||||
mockStream.push(null);
|
||||
storage2.read = jest.fn().mockResolvedValue(mockStream);
|
||||
storage2.exists = jest.fn().mockResolvedValue(true);
|
||||
|
||||
const result = await oneOfStorageStrategy.read(path);
|
||||
|
||||
expect(storage1.exists).toHaveBeenCalled();
|
||||
expect(storage1.read).toHaveBeenCalled();
|
||||
expect(storage2.exists).toHaveBeenCalled();
|
||||
expect(storage2.read).toHaveBeenCalled();
|
||||
expect(result).toBe(mockStream);
|
||||
});
|
||||
});
|
||||
|
||||
describe('exists', () => {
|
||||
it('should return true if the file exists in any storage', async () => {
|
||||
storage1.exists = jest.fn().mockResolvedValue(false);
|
||||
storage2.exists = jest.fn().mockResolvedValue(true);
|
||||
|
||||
const result = await oneOfStorageStrategy.exists('test/path');
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(storage1.exists).toHaveBeenCalled();
|
||||
expect(storage2.exists).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return false if the file does not exist in any storage', async () => {
|
||||
storage1.exists = jest.fn().mockResolvedValue(false);
|
||||
storage2.exists = jest.fn().mockResolvedValue(false);
|
||||
|
||||
const result = await oneOfStorageStrategy.exists('test/path');
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(storage1.exists).toHaveBeenCalled();
|
||||
expect(storage2.exists).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove', () => {
|
||||
it('should remove the file from all storages', async () => {
|
||||
const result = await oneOfStorageStrategy.remove('test/path');
|
||||
|
||||
expect(storage1.remove).toHaveBeenCalledWith('test/path', undefined);
|
||||
expect(storage2.remove).toHaveBeenCalledWith('test/path', undefined);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if any storage fails to remove the file', async () => {
|
||||
storage1.remove = jest.fn().mockResolvedValue(true);
|
||||
storage2.remove = jest.fn().mockResolvedValue(false);
|
||||
|
||||
const result = await oneOfStorageStrategy.remove('test/path');
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
+72
-440
@@ -493,11 +493,6 @@
|
||||
rfdc "^1.3.0"
|
||||
yaml "^2.2.2"
|
||||
|
||||
"@ffprobe-installer/darwin-arm64@5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/@ffprobe-installer/darwin-arm64/-/darwin-arm64-5.0.1.tgz"
|
||||
integrity sha512-vwNCNjokH8hfkbl6m95zICHwkSzhEvDC3GVBcUp5HX8+4wsX10SP3B+bGur7XUzTIZ4cQpgJmEIAx6TUwRepMg==
|
||||
|
||||
"@ffprobe-installer/ffprobe@^1.4.1":
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/@ffprobe-installer/ffprobe/-/ffprobe-1.4.1.tgz"
|
||||
@@ -512,10 +507,10 @@
|
||||
"@ffprobe-installer/win32-ia32" "5.0.0"
|
||||
"@ffprobe-installer/win32-x64" "5.0.0"
|
||||
|
||||
"@gar/promisify@^1.1.3":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz"
|
||||
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
|
||||
"@ffprobe-installer/linux-x64@5.0.0":
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/@ffprobe-installer/linux-x64/-/linux-x64-5.0.0.tgz"
|
||||
integrity sha512-zgLnWJFvMGCaw1txGtz84sMEQt6mQUzdw86ih9S/kZOWnp06Gj/ams/EXxEkAxgAACCVM6/O0mkDe/6biY5tgA==
|
||||
|
||||
"@humanwhocodes/config-array@^0.11.14":
|
||||
version "0.11.14"
|
||||
@@ -536,17 +531,29 @@
|
||||
resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz"
|
||||
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
|
||||
|
||||
"@img/sharp-darwin-arm64@0.33.3":
|
||||
version "0.33.3"
|
||||
resolved "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz"
|
||||
integrity sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-darwin-arm64" "1.0.2"
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64@1.0.2":
|
||||
"@img/sharp-libvips-linux-x64@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.2.tgz"
|
||||
integrity sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==
|
||||
resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.2.tgz"
|
||||
integrity sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64@1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.2.tgz"
|
||||
integrity sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==
|
||||
|
||||
"@img/sharp-linux-x64@0.33.3":
|
||||
version "0.33.3"
|
||||
resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.3.tgz"
|
||||
integrity sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-x64" "1.0.2"
|
||||
|
||||
"@img/sharp-linuxmusl-x64@0.33.3":
|
||||
version "0.33.3"
|
||||
resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.3.tgz"
|
||||
integrity sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linuxmusl-x64" "1.0.2"
|
||||
|
||||
"@isaacs/cliui@^8.0.2":
|
||||
version "8.0.2"
|
||||
@@ -904,22 +911,6 @@
|
||||
"@nodelib/fs.scandir" "2.1.5"
|
||||
fastq "^1.6.0"
|
||||
|
||||
"@npmcli/fs@^2.1.0":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz"
|
||||
integrity sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==
|
||||
dependencies:
|
||||
"@gar/promisify" "^1.1.3"
|
||||
semver "^7.3.5"
|
||||
|
||||
"@npmcli/move-file@^2.0.0":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz"
|
||||
integrity sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==
|
||||
dependencies:
|
||||
mkdirp "^1.0.4"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
"@opensearch-project/opensearch@^2.4.0":
|
||||
version "2.7.0"
|
||||
resolved "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.7.0.tgz"
|
||||
@@ -1087,11 +1078,6 @@
|
||||
dependencies:
|
||||
defer-to-connect "^2.0.0"
|
||||
|
||||
"@tootallnate/once@2":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz"
|
||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz"
|
||||
@@ -1430,6 +1416,13 @@
|
||||
pg-protocol "*"
|
||||
pg-types "^4.0.1"
|
||||
|
||||
"@types/pino@^7.0.5":
|
||||
version "7.0.5"
|
||||
resolved "https://registry.npmjs.org/@types/pino/-/pino-7.0.5.tgz"
|
||||
integrity sha512-wKoab31pknvILkxAF8ss+v9iNyhw5Iu/0jLtRkUD74cNfOOLJNnqfFKAv0r7wVaTQxRZtWrMpGfShwwBjOcgcg==
|
||||
dependencies:
|
||||
pino "*"
|
||||
|
||||
"@types/pump@^1.1.1":
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/@types/pump/-/pump-1.1.3.tgz"
|
||||
@@ -1648,28 +1641,12 @@
|
||||
resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz"
|
||||
integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==
|
||||
|
||||
"@xprofiler/node-pre-gyp@^1.0.9":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.npmjs.org/@xprofiler/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz"
|
||||
integrity sha512-kNFT4XscrA+Hjh+jSHs49PiG/YGf08a6eNDo16qjSnCaT4B5ngrKDcNtEJ6CnS0sDP/1oZmHCBYECB6wGKP7lg==
|
||||
dependencies:
|
||||
detect-libc "^1.0.3"
|
||||
https-proxy-agent "^5.0.0"
|
||||
make-dir "^3.1.0"
|
||||
node-fetch "^2.6.5"
|
||||
node-gyp "9.3.1"
|
||||
nopt "^5.0.0"
|
||||
npmlog "^5.0.1"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.11"
|
||||
|
||||
"@zxing/text-encoding@0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz"
|
||||
integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
|
||||
|
||||
abbrev@^1.0.0, abbrev@1:
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
@@ -1718,28 +1695,13 @@ acorn-walk@^8.1.1:
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"
|
||||
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
|
||||
|
||||
agent-base@^6.0.2, agent-base@6:
|
||||
agent-base@6:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
|
||||
integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
|
||||
dependencies:
|
||||
debug "4"
|
||||
|
||||
agentkeepalive@^4.2.1:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz"
|
||||
integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
|
||||
dependencies:
|
||||
humanize-ms "^1.2.1"
|
||||
|
||||
aggregate-error@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz"
|
||||
integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
|
||||
dependencies:
|
||||
clean-stack "^2.0.0"
|
||||
indent-string "^4.0.0"
|
||||
|
||||
aggregate-error@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz"
|
||||
@@ -1928,14 +1890,6 @@ are-we-there-yet@^2.0.0:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
are-we-there-yet@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz"
|
||||
integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==
|
||||
dependencies:
|
||||
delegates "^1.0.0"
|
||||
readable-stream "^3.6.0"
|
||||
|
||||
arg@^4.1.0:
|
||||
version "4.1.3"
|
||||
resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz"
|
||||
@@ -2274,30 +2228,6 @@ buffer@^6.0.3:
|
||||
base64-js "^1.3.1"
|
||||
ieee754 "^1.2.1"
|
||||
|
||||
cacache@^16.1.0:
|
||||
version "16.1.3"
|
||||
resolved "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz"
|
||||
integrity sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==
|
||||
dependencies:
|
||||
"@npmcli/fs" "^2.1.0"
|
||||
"@npmcli/move-file" "^2.0.0"
|
||||
chownr "^2.0.0"
|
||||
fs-minipass "^2.1.0"
|
||||
glob "^8.0.1"
|
||||
infer-owner "^1.0.4"
|
||||
lru-cache "^7.7.1"
|
||||
minipass "^3.1.6"
|
||||
minipass-collect "^1.0.2"
|
||||
minipass-flush "^1.0.5"
|
||||
minipass-pipeline "^1.2.4"
|
||||
mkdirp "^1.0.4"
|
||||
p-map "^4.0.0"
|
||||
promise-inflight "^1.0.1"
|
||||
rimraf "^3.0.2"
|
||||
ssri "^9.0.0"
|
||||
tar "^6.1.11"
|
||||
unique-filename "^2.0.0"
|
||||
|
||||
cacheable-lookup@^5.0.3:
|
||||
version "5.0.4"
|
||||
resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz"
|
||||
@@ -2447,11 +2377,6 @@ class-transformer@^0.3.1:
|
||||
resolved "https://registry.npmjs.org/class-transformer/-/class-transformer-0.3.1.tgz"
|
||||
integrity sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA==
|
||||
|
||||
clean-stack@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz"
|
||||
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
|
||||
|
||||
clean-stack@^4.0.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz"
|
||||
@@ -2555,7 +2480,7 @@ color-string@^1.9.0:
|
||||
color-name "^1.0.0"
|
||||
simple-swizzle "^0.2.2"
|
||||
|
||||
color-support@^1.1.2, color-support@^1.1.3:
|
||||
color-support@^1.1.2:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz"
|
||||
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
|
||||
@@ -2880,11 +2805,6 @@ detect-indent@^6.0.0:
|
||||
resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz"
|
||||
integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==
|
||||
|
||||
detect-libc@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz"
|
||||
integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
|
||||
|
||||
detect-libc@^2.0.0, detect-libc@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz"
|
||||
@@ -3024,7 +2944,7 @@ emojilib@^2.0.2:
|
||||
resolved "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz"
|
||||
integrity sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==
|
||||
|
||||
encoding@^0.1.0, encoding@^0.1.13:
|
||||
encoding@^0.1.0:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz"
|
||||
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
|
||||
@@ -3075,16 +2995,6 @@ entities@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
|
||||
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
|
||||
|
||||
env-paths@^2.2.0:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz"
|
||||
integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
|
||||
|
||||
err-code@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz"
|
||||
integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
|
||||
@@ -3413,12 +3323,12 @@ fast-querystring@^1.0.0:
|
||||
dependencies:
|
||||
fast-decode-uri-component "^1.0.1"
|
||||
|
||||
fast-redact@^3.0.0, fast-redact@^3.1.1:
|
||||
fast-redact@^3.1.1:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz"
|
||||
integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==
|
||||
|
||||
fast-safe-stringify@^2.0.8, fast-safe-stringify@^2.1.1, fast-safe-stringify@~2.1.0:
|
||||
fast-safe-stringify@^2.1.1, fast-safe-stringify@~2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz"
|
||||
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
|
||||
@@ -3583,11 +3493,6 @@ flat-cache@^3.0.4:
|
||||
keyv "^4.5.3"
|
||||
rimraf "^3.0.2"
|
||||
|
||||
flatstr@^1.0.12:
|
||||
version "1.0.12"
|
||||
resolved "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz"
|
||||
integrity sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==
|
||||
|
||||
flatted@^3.2.9:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz"
|
||||
@@ -3683,7 +3588,7 @@ fs-extra@^10.0.0:
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
fs-minipass@^2.0.0, fs-minipass@^2.1.0:
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz"
|
||||
integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
|
||||
@@ -3695,11 +3600,6 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fsevents@^2.3.2, fsevents@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
|
||||
fstream@^1.0.12:
|
||||
version "1.0.12"
|
||||
resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz"
|
||||
@@ -3730,20 +3630,6 @@ gauge@^3.0.0:
|
||||
strip-ansi "^6.0.1"
|
||||
wide-align "^1.1.2"
|
||||
|
||||
gauge@^4.0.3:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz"
|
||||
integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==
|
||||
dependencies:
|
||||
aproba "^1.0.3 || ^2.0.0"
|
||||
color-support "^1.1.3"
|
||||
console-control-strings "^1.1.0"
|
||||
has-unicode "^2.0.1"
|
||||
signal-exit "^3.0.7"
|
||||
string-width "^4.2.3"
|
||||
strip-ansi "^6.0.1"
|
||||
wide-align "^1.1.5"
|
||||
|
||||
generate-password@^1.6.0:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.npmjs.org/generate-password/-/generate-password-1.7.1.tgz"
|
||||
@@ -3860,17 +3746,6 @@ glob@^7.2.3:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^8.0.1:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz"
|
||||
integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^5.0.1"
|
||||
once "^1.3.0"
|
||||
|
||||
globals@^11.1.0:
|
||||
version "11.12.0"
|
||||
resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
|
||||
@@ -3940,7 +3815,7 @@ got@~11.8.5:
|
||||
p-cancelable "^2.0.0"
|
||||
responselike "^2.0.0"
|
||||
|
||||
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
|
||||
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.9:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
@@ -4055,7 +3930,7 @@ htmlparser2@^6.1.0:
|
||||
domutils "^2.5.2"
|
||||
entities "^2.0.0"
|
||||
|
||||
http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
|
||||
http-cache-semantics@^4.0.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz"
|
||||
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
|
||||
@@ -4071,15 +3946,6 @@ http-errors@^2.0.0, http-errors@2.0.0:
|
||||
statuses "2.0.1"
|
||||
toidentifier "1.0.1"
|
||||
|
||||
http-proxy-agent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz"
|
||||
integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==
|
||||
dependencies:
|
||||
"@tootallnate/once" "2"
|
||||
agent-base "6"
|
||||
debug "4"
|
||||
|
||||
http2-wrapper@^1.0.0-beta.5.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz"
|
||||
@@ -4101,13 +3967,6 @@ human-signals@^2.1.0:
|
||||
resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
|
||||
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
||||
|
||||
humanize-ms@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz"
|
||||
integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
|
||||
dependencies:
|
||||
ms "^2.0.0"
|
||||
|
||||
i18n@^0.15.1:
|
||||
version "0.15.1"
|
||||
resolved "https://registry.npmjs.org/i18n/-/i18n-0.15.1.tgz"
|
||||
@@ -4170,21 +4029,11 @@ imurmurhash@^0.1.4:
|
||||
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
|
||||
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
|
||||
|
||||
indent-string@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz"
|
||||
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
|
||||
|
||||
indent-string@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz"
|
||||
integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==
|
||||
|
||||
infer-owner@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz"
|
||||
integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
|
||||
@@ -4287,11 +4136,6 @@ is-interactive@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz"
|
||||
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
|
||||
|
||||
is-lambda@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz"
|
||||
integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
|
||||
@@ -5175,11 +5019,6 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
lru-cache@^7.7.1:
|
||||
version "7.18.3"
|
||||
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz"
|
||||
integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
|
||||
|
||||
lru-cache@~4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz"
|
||||
@@ -5215,28 +5054,6 @@ make-error@^1.1.1, make-error@1.x:
|
||||
resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
|
||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
|
||||
|
||||
make-fetch-happen@^10.0.3:
|
||||
version "10.2.1"
|
||||
resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz"
|
||||
integrity sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==
|
||||
dependencies:
|
||||
agentkeepalive "^4.2.1"
|
||||
cacache "^16.1.0"
|
||||
http-cache-semantics "^4.1.0"
|
||||
http-proxy-agent "^5.0.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
is-lambda "^1.0.1"
|
||||
lru-cache "^7.7.1"
|
||||
minipass "^3.1.6"
|
||||
minipass-collect "^1.0.2"
|
||||
minipass-fetch "^2.0.3"
|
||||
minipass-flush "^1.0.5"
|
||||
minipass-pipeline "^1.2.4"
|
||||
negotiator "^0.6.3"
|
||||
promise-retry "^2.0.1"
|
||||
socks-proxy-agent "^7.0.0"
|
||||
ssri "^9.0.0"
|
||||
|
||||
make-plural@^7.0.0:
|
||||
version "7.4.0"
|
||||
resolved "https://registry.npmjs.org/make-plural/-/make-plural-7.4.0.tgz"
|
||||
@@ -5388,13 +5205,6 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^5.0.1:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz"
|
||||
integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
minimatch@^5.1.0:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz"
|
||||
@@ -5443,45 +5253,6 @@ minio@^7.1.3:
|
||||
xml "^1.0.1"
|
||||
xml2js "^0.5.0"
|
||||
|
||||
minipass-collect@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz"
|
||||
integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-fetch@^2.0.3:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz"
|
||||
integrity sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==
|
||||
dependencies:
|
||||
minipass "^3.1.6"
|
||||
minipass-sized "^1.0.3"
|
||||
minizlib "^2.1.2"
|
||||
optionalDependencies:
|
||||
encoding "^0.1.13"
|
||||
|
||||
minipass-flush@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz"
|
||||
integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-pipeline@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz"
|
||||
integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass-sized@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz"
|
||||
integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==
|
||||
dependencies:
|
||||
minipass "^3.0.0"
|
||||
|
||||
minipass@^3.0.0:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz"
|
||||
@@ -5489,20 +5260,6 @@ minipass@^3.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
minipass@^3.1.1:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz"
|
||||
integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
minipass@^3.1.6:
|
||||
version "3.3.6"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz"
|
||||
integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz"
|
||||
@@ -5513,7 +5270,7 @@ minipass@^5.0.0:
|
||||
resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz"
|
||||
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
|
||||
|
||||
minizlib@^2.1.1, minizlib@^2.1.2:
|
||||
minizlib@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz"
|
||||
integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
|
||||
@@ -5569,7 +5326,7 @@ moo@^0.5.0, moo@^0.5.1:
|
||||
resolved "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz"
|
||||
integrity sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==
|
||||
|
||||
ms@^2.0.0, ms@^2.1.1, ms@^2.1.3:
|
||||
ms@^2.1.1, ms@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
@@ -5597,11 +5354,6 @@ mustache@^4.2.0:
|
||||
resolved "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz"
|
||||
integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
|
||||
|
||||
nan@^2.18.0:
|
||||
version "2.19.0"
|
||||
resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz"
|
||||
integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==
|
||||
|
||||
natural-compare-lite@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz"
|
||||
@@ -5631,7 +5383,7 @@ needle@^2.5.2:
|
||||
iconv-lite "^0.4.4"
|
||||
sax "^1.2.4"
|
||||
|
||||
negotiator@^0.6.3, negotiator@0.6.3:
|
||||
negotiator@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz"
|
||||
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
|
||||
@@ -5684,29 +5436,13 @@ node-ensure@^0.0.0:
|
||||
resolved "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz"
|
||||
integrity sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==
|
||||
|
||||
node-fetch@^2.6.5, node-fetch@^2.6.7:
|
||||
node-fetch@^2.6.7:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz"
|
||||
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-gyp@9.3.1:
|
||||
version "9.3.1"
|
||||
resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz"
|
||||
integrity sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==
|
||||
dependencies:
|
||||
env-paths "^2.2.0"
|
||||
glob "^7.1.4"
|
||||
graceful-fs "^4.2.6"
|
||||
make-fetch-happen "^10.0.3"
|
||||
nopt "^6.0.0"
|
||||
npmlog "^6.0.0"
|
||||
rimraf "^3.0.2"
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.2"
|
||||
which "^2.0.2"
|
||||
|
||||
node-int64@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz"
|
||||
@@ -5753,13 +5489,6 @@ nopt@^5.0.0:
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
|
||||
nopt@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz"
|
||||
integrity sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==
|
||||
dependencies:
|
||||
abbrev "^1.0.0"
|
||||
|
||||
nopt@~1.0.10:
|
||||
version "1.0.10"
|
||||
resolved "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz"
|
||||
@@ -5809,16 +5538,6 @@ npmlog@^5.0.1:
|
||||
gauge "^3.0.0"
|
||||
set-blocking "^2.0.0"
|
||||
|
||||
npmlog@^6.0.0:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz"
|
||||
integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==
|
||||
dependencies:
|
||||
are-we-there-yet "^3.0.0"
|
||||
console-control-strings "^1.1.0"
|
||||
gauge "^4.0.3"
|
||||
set-blocking "^2.0.0"
|
||||
|
||||
object-assign@^4, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
||||
@@ -5957,13 +5676,6 @@ p-locate@^5.0.0:
|
||||
dependencies:
|
||||
p-limit "^3.0.2"
|
||||
|
||||
p-map@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz"
|
||||
integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
|
||||
dependencies:
|
||||
aggregate-error "^3.0.0"
|
||||
|
||||
p-map@^5.1.0, p-map@^5.3.0:
|
||||
version "5.5.0"
|
||||
resolved "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz"
|
||||
@@ -6153,7 +5865,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
|
||||
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
pino-abstract-transport@^1.0.0, pino-abstract-transport@^1.2.0:
|
||||
pino-abstract-transport@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz"
|
||||
integrity sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==
|
||||
@@ -6161,6 +5873,13 @@ pino-abstract-transport@^1.0.0, pino-abstract-transport@^1.2.0:
|
||||
readable-stream "^4.0.0"
|
||||
split2 "^4.0.0"
|
||||
|
||||
pino-abstract-transport@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz"
|
||||
integrity sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==
|
||||
dependencies:
|
||||
split2 "^4.0.0"
|
||||
|
||||
pino-pretty@^10.0.0:
|
||||
version "10.3.1"
|
||||
resolved "https://registry.npmjs.org/pino-pretty/-/pino-pretty-10.3.1.tgz"
|
||||
@@ -6181,45 +5900,22 @@ pino-pretty@^10.0.0:
|
||||
sonic-boom "^3.0.0"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
pino-std-serializers@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz"
|
||||
integrity sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==
|
||||
|
||||
pino-std-serializers@^6.1.0:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz"
|
||||
integrity sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==
|
||||
|
||||
pino-std-serializers@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz"
|
||||
integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==
|
||||
|
||||
pino@^6.8.0:
|
||||
version "6.14.0"
|
||||
resolved "https://registry.npmjs.org/pino/-/pino-6.14.0.tgz"
|
||||
integrity sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==
|
||||
dependencies:
|
||||
fast-redact "^3.0.0"
|
||||
fast-safe-stringify "^2.0.8"
|
||||
flatstr "^1.0.12"
|
||||
pino-std-serializers "^3.1.0"
|
||||
process-warning "^1.0.0"
|
||||
quick-format-unescaped "^4.0.3"
|
||||
sonic-boom "^1.0.2"
|
||||
|
||||
pino@^9.0.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.npmjs.org/pino/-/pino-9.1.0.tgz"
|
||||
integrity sha512-qUcgfrlyOtjwhNLdbhoL7NR4NkHjzykAPw0V2QLFbvu/zss29h4NkRnibyFzBrNCbzCOY3WZ9hhKSwfOkNggYA==
|
||||
pino@*, pino@^9.0.0, pino@^9.5.0:
|
||||
version "9.5.0"
|
||||
resolved "https://registry.npmjs.org/pino/-/pino-9.5.0.tgz"
|
||||
integrity sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==
|
||||
dependencies:
|
||||
atomic-sleep "^1.0.0"
|
||||
fast-redact "^3.1.1"
|
||||
on-exit-leak-free "^2.1.0"
|
||||
pino-abstract-transport "^1.2.0"
|
||||
pino-abstract-transport "^2.0.0"
|
||||
pino-std-serializers "^7.0.0"
|
||||
process-warning "^3.0.0"
|
||||
process-warning "^4.0.0"
|
||||
quick-format-unescaped "^4.0.3"
|
||||
real-require "^0.2.0"
|
||||
safe-stable-stringify "^2.3.1"
|
||||
@@ -6332,16 +6028,16 @@ process-nextick-args@~2.0.0:
|
||||
resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
process-warning@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz"
|
||||
integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==
|
||||
|
||||
process-warning@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz"
|
||||
integrity sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==
|
||||
|
||||
process-warning@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/process-warning/-/process-warning-4.0.0.tgz"
|
||||
integrity sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==
|
||||
|
||||
process@^0.11.10:
|
||||
version "0.11.10"
|
||||
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
|
||||
@@ -6352,19 +6048,6 @@ promise-breaker@^5.0.0:
|
||||
resolved "https://registry.npmjs.org/promise-breaker/-/promise-breaker-5.0.0.tgz"
|
||||
integrity sha512-mgsWQuG4kJ1dtO6e/QlNDLFtMkMzzecsC69aI5hlLEjGHFNpHrvGhFi4LiK5jg2SMQj74/diH+wZliL9LpGsyA==
|
||||
|
||||
promise-inflight@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz"
|
||||
integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==
|
||||
|
||||
promise-retry@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz"
|
||||
integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
|
||||
dependencies:
|
||||
err-code "^2.0.2"
|
||||
retry "^0.12.0"
|
||||
|
||||
promise@~1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/promise/-/promise-1.3.0.tgz"
|
||||
@@ -6745,11 +6428,6 @@ ret@~0.4.0:
|
||||
resolved "https://registry.npmjs.org/ret/-/ret-0.4.3.tgz"
|
||||
integrity sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==
|
||||
|
||||
retry@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz"
|
||||
integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==
|
||||
|
||||
reusify@^1.0.0, reusify@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
|
||||
@@ -7050,16 +6728,7 @@ socket.io@^4.6.2:
|
||||
socket.io-adapter "~2.5.2"
|
||||
socket.io-parser "~4.2.4"
|
||||
|
||||
socks-proxy-agent@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz"
|
||||
integrity sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==
|
||||
dependencies:
|
||||
agent-base "^6.0.2"
|
||||
debug "^4.3.3"
|
||||
socks "^2.6.2"
|
||||
|
||||
socks@^2.6.2, socks@^2.7.1:
|
||||
socks@^2.7.1:
|
||||
version "2.8.3"
|
||||
resolved "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz"
|
||||
integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==
|
||||
@@ -7067,14 +6736,6 @@ socks@^2.6.2, socks@^2.7.1:
|
||||
ip-address "^9.0.5"
|
||||
smart-buffer "^4.2.0"
|
||||
|
||||
sonic-boom@^1.0.2:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz"
|
||||
integrity sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==
|
||||
dependencies:
|
||||
atomic-sleep "^1.0.0"
|
||||
flatstr "^1.0.12"
|
||||
|
||||
sonic-boom@^3.0.0:
|
||||
version "3.8.1"
|
||||
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz"
|
||||
@@ -7083,9 +6744,9 @@ sonic-boom@^3.0.0:
|
||||
atomic-sleep "^1.0.0"
|
||||
|
||||
sonic-boom@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz"
|
||||
integrity sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==
|
||||
version "4.2.0"
|
||||
resolved "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz"
|
||||
integrity sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==
|
||||
dependencies:
|
||||
atomic-sleep "^1.0.0"
|
||||
|
||||
@@ -7169,13 +6830,6 @@ sprintf-js@~1.0.2:
|
||||
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
|
||||
integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
|
||||
|
||||
ssri@^9.0.0:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz"
|
||||
integrity sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==
|
||||
dependencies:
|
||||
minipass "^3.1.1"
|
||||
|
||||
stack-utils@^2.0.3:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz"
|
||||
@@ -7400,7 +7054,7 @@ tar-stream@^2.2.0:
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^3.1.1"
|
||||
|
||||
tar@^6.1.11, tar@^6.1.2:
|
||||
tar@^6.1.11:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz"
|
||||
integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
|
||||
@@ -7691,20 +7345,6 @@ undici-types@~5.26.4:
|
||||
resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
unique-filename@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz"
|
||||
integrity sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==
|
||||
dependencies:
|
||||
unique-slug "^3.0.0"
|
||||
|
||||
unique-slug@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz"
|
||||
integrity sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==
|
||||
dependencies:
|
||||
imurmurhash "^0.1.4"
|
||||
|
||||
universalify@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz"
|
||||
@@ -7784,14 +7424,6 @@ v8-compile-cache-lib@^3.0.1:
|
||||
resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz"
|
||||
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
|
||||
|
||||
v8-profiler-next@^1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.npmjs.org/v8-profiler-next/-/v8-profiler-next-1.10.0.tgz"
|
||||
integrity sha512-HME7CR3V8gkBEAutcMyGS0vK0XH2hFQhF5SvSdrF/mdjWIGoaiY+WH3RpY7ePY7J7vNDbQfP+Ikefdi1z/mJXg==
|
||||
dependencies:
|
||||
"@xprofiler/node-pre-gyp" "^1.0.9"
|
||||
nan "^2.18.0"
|
||||
|
||||
v8-to-istanbul@^9.0.1:
|
||||
version "9.2.0"
|
||||
resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz"
|
||||
@@ -7888,14 +7520,14 @@ which@^1.2.9:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
which@^2.0.1, which@^2.0.2:
|
||||
which@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
|
||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wide-align@^1.1.2, wide-align@^1.1.5:
|
||||
wide-align@^1.1.2:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz"
|
||||
integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
version: "2"
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
# rabbitmq:
|
||||
|
||||
@@ -31,6 +31,7 @@ module.exports = {
|
||||
'@typescript-eslint/no-this-alias': 'warn',
|
||||
'react/prop-types': 'warn',
|
||||
'no-useless-escape': 'warn',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'warn',
|
||||
'@typescript-eslint/ban-types': 'warn',
|
||||
'@typescript-eslint/ban-ts-comment': 'warn',
|
||||
|
||||
Generated
+10858
-4142
File diff suppressed because it is too large
Load Diff
@@ -232,7 +232,7 @@
|
||||
"react-transition-group": "^4.4.1",
|
||||
"react-virtualized": "^9.22.2",
|
||||
"react-virtuoso": "2.10.2",
|
||||
"react-zoom-pan-pinch": "^2.1.3",
|
||||
"react-zoom-pan-pinch": "^2.6.1",
|
||||
"recoil": "^0.7.6",
|
||||
"redux": "^4.0.5",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
|
||||
@@ -54,13 +54,13 @@
|
||||
left: calc(50% - 25px);
|
||||
position: absolute;
|
||||
top: calc(50% - 25px);
|
||||
width: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.path {
|
||||
stroke-dasharray: 1,200;
|
||||
stroke-dashoffset: 0;
|
||||
animation:
|
||||
animation:
|
||||
dash 1.5s ease-in-out infinite,
|
||||
color 6s ease-in-out infinite
|
||||
;
|
||||
@@ -136,22 +136,5 @@
|
||||
document.getElementById('body').className = 'electron';
|
||||
}
|
||||
</script>
|
||||
<script async src="https://cdn.headwayapp.co/widget.js"></script>
|
||||
<script>
|
||||
if(location.origin.indexOf("tdrive.app") >= 0){
|
||||
!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._loadOptions=e};analytics.SNIPPET_VERSION="4.13.1";
|
||||
analytics.load("Vl5xpgcpGRe4BmSYp9xPlAeQdqLP5lLe");
|
||||
analytics.page();
|
||||
}}();
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
if(location.origin.indexOf("canary.tdrive.app") >= 0){
|
||||
const canaryTag = document.createElement("div");
|
||||
canaryTag.id = "canary_tag";
|
||||
document.body.appendChild(canaryTag);
|
||||
window.canary = true;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -197,6 +197,7 @@
|
||||
"hooks.use-drive-actions.unable_remove_file": "Unable to remove this file.",
|
||||
"hooks.use-drive-actions.unable_restore_file": "Unable to restore this item.",
|
||||
"hooks.use-drive-actions.unable_update_file": "Unable to update this file.",
|
||||
"hooks.use-drive-actions.update_caused_a_rename": "Item was renamed to '{{$2}}'.",
|
||||
"login.create_account": "Create account",
|
||||
"login.login_error": "Error during login",
|
||||
"molecules.download_banner.download_button": "Download desktop app",
|
||||
|
||||
@@ -190,6 +190,7 @@
|
||||
"hooks.use-drive-actions.unable_remove_file": "Impossible de supprimer ce fichier",
|
||||
"hooks.use-drive-actions.unable_restore_file": "Impossible de restaurer cet élément.",
|
||||
"hooks.use-drive-actions.unable_update_file": "Impossible de mettre à jour ce fichier",
|
||||
"hooks.use-drive-actions.update_caused_a_rename": "Renommé en '{{$2}}'.",
|
||||
"login.create_account": "Créer un compte",
|
||||
"login.login_error": "Erreur lors de la connexion",
|
||||
"molecules.download_banner.download_button": "Télécharger l'application de bureau",
|
||||
|
||||
@@ -197,6 +197,7 @@
|
||||
"hooks.use-drive-actions.unable_remove_file": "Невозможно удалить эти файлы.",
|
||||
"hooks.use-drive-actions.unable_restore_file": "Невозможно восстановить эти файлы.",
|
||||
"hooks.use-drive-actions.unable_update_file": "Невозможно обновить эти файлы.",
|
||||
"hooks.use-drive-actions.update_caused_a_rename": "Элемент был переименован в «{{$2}}».",
|
||||
"login.create_account": "Создать учетную запись",
|
||||
"login.login_error": "Ошибка при входе в систему",
|
||||
"molecules.download_banner.download_button": "Скачать настольное приложение",
|
||||
|
||||
@@ -179,6 +179,7 @@
|
||||
"hooks.use-drive-actions.unable_remove_file": "Không thể xóa tệp này.",
|
||||
"hooks.use-drive-actions.unable_restore_file": "Không thể khôi phục mục này.",
|
||||
"hooks.use-drive-actions.unable_update_file": "Không thể cập nhật tệp này.",
|
||||
"hooks.use-drive-actions.update_caused_a_rename": "Mục đã được đổi tên thành '{{$2}}'.",
|
||||
"login.create_account": "Tạo tài khoản",
|
||||
"login.login_error": "Lỗi trong khi đăng nhập",
|
||||
"molecules.download_banner.download_button": "Tải xuống ứng dụng dành cho máy tính",
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
useRef,
|
||||
} from "react";
|
||||
|
||||
let interval: any = null;
|
||||
let interval: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
export const AnimatedHeight = memo(
|
||||
(props: { children: ReactNode } & InputHTMLAttributes<HTMLDivElement>) => {
|
||||
@@ -28,7 +28,8 @@ export const AnimatedHeight = memo(
|
||||
updateSize();
|
||||
}, 200);
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
if (interval)
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ const Template: ComponentStory<any> = (props: { label: string; disabled: boolean
|
||||
<Title className='my-5'>CheckboxSlider</Title>
|
||||
|
||||
<CheckboxSlider
|
||||
onClick={e => setChecked(!checked)}
|
||||
onClick={() => setChecked(!checked)}
|
||||
checked={checked}
|
||||
disabled={props.disabled}
|
||||
/>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { action } from '@storybook/addon-actions';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
import { ComponentStory } from '@storybook/react';
|
||||
import { CheckCircleIcon, ExclamationCircleIcon } from '@heroicons/react/outline';
|
||||
import { Title } from '../text';
|
||||
|
||||
import { ConfirmModal, ConfirmModalProps } from './confirm';
|
||||
const icons = {
|
||||
@@ -36,6 +35,7 @@ export default {
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const Template: ComponentStory<any> = (props: ConfirmModalProps) => {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import './connection-indicator.scss';
|
||||
import ErrorOutlinedIcon from '@material-ui/icons/ErrorOutlined';
|
||||
import HourglassEmpty from '@material-ui/icons/HourglassEmpty';
|
||||
@@ -9,7 +9,7 @@ import { useRecoilState } from 'recoil';
|
||||
// import WebSocket, { WebsocketEvents } from '@features/global/types/websocket-types';
|
||||
|
||||
export default () => {
|
||||
const [{ connected, reconnecting }, setState] = useRecoilState(ConnectedState);
|
||||
const [{ connected, reconnecting }] = useRecoilState(ConnectedState);
|
||||
|
||||
return (
|
||||
<div className={'connection_indicator ' + (connected === false ? 'visible' : '')}>
|
||||
|
||||
@@ -1,24 +1,21 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import InitService from '../../features/global/services/init-service';
|
||||
// import InitService from '../../features/global/services/init-service';
|
||||
import LocalStorage from '../../features/global/framework/local-storage-service';
|
||||
import DownloadBanner from '@molecules/download-banner';
|
||||
import { detectDesktopAppPresence } from '../../../utils/browser-detect';
|
||||
|
||||
export default (): React.ReactElement => {
|
||||
const [showBanner, setShowBanner] = useState(false);
|
||||
const [ , setShowBanner] = useState(false);
|
||||
|
||||
const download = (): void => {
|
||||
const appDownloadUrl = InitService?.server_infos?.configuration?.app_download_url;
|
||||
// const download = (): void => {
|
||||
// const appDownloadUrl = InitService?.server_infos?.configuration?.app_download_url;
|
||||
// if (appDownloadUrl)
|
||||
// window.open(appDownloadUrl, '_blank');
|
||||
// };
|
||||
|
||||
if (appDownloadUrl) {
|
||||
window.open(appDownloadUrl, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
const removeBanner = (): void => {
|
||||
LocalStorage.setItem('show_app_banner', 'false');
|
||||
setShowBanner(false);
|
||||
};
|
||||
// const removeBanner = (): void => {
|
||||
// LocalStorage.setItem('show_app_banner', 'false');
|
||||
// setShowBanner(false);
|
||||
// };
|
||||
|
||||
useEffect(() => {
|
||||
if (LocalStorage.getItem('show_app_banner') === 'false') {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { getDevice } from '../../features/global/utils/device';
|
||||
import configuration from '../../environment/environment';
|
||||
import { Smartphone, X } from 'react-feather';
|
||||
import './style.scss';
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class PopupComponent extends React.Component {
|
||||
{this.state.popupManager.canClose() && (
|
||||
<div className="header">
|
||||
<div className="close" onClick={() => this.state.popupManager.close()}>
|
||||
<CloseIcon class="m-icon" />
|
||||
<CloseIcon className="m-icon" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FolderIcon } from '@heroicons/react/solid';
|
||||
import Highlighter from 'react-highlight-words';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { onDriveItemDownloadClick } from '../common';
|
||||
import ResultContext from './result-context';
|
||||
import { Button } from '@atoms/button/button';
|
||||
@@ -15,18 +15,14 @@ import { SearchInputState } from '@features/search/state/search-input';
|
||||
import { UserType } from '@features/users/types/user';
|
||||
import { useDrivePreview } from '@features/drive/hooks/use-drive-preview';
|
||||
import Media from '@molecules/media';
|
||||
import { DriveCurrentFolderAtom } from '@views/client/body/drive/browser';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import { useCurrentUser } from 'app/features/users/hooks/use-current-user';
|
||||
import useRouterCompany from 'app/features/router/hooks/use-router-company';
|
||||
import { DocumentIcon } from '@views/client/body/drive/documents/document-icon';
|
||||
|
||||
export default (props: { driveItem: DriveItem & { user?: UserType }}) => {
|
||||
const history = useHistory();
|
||||
const input = useRecoilValue(SearchInputState);
|
||||
const { user } = useCurrentUser();
|
||||
const [_, setParentId] = useRecoilState(DriveCurrentFolderAtom({ initialFolderId: 'user_'+user?.id }));
|
||||
const file = props.driveItem;
|
||||
const name = file?.name;
|
||||
const extension = name?.split('.').pop();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
type TreeItem = { [key: string]: File | TreeItem };
|
||||
|
||||
export type FileTreeObject = {
|
||||
|
||||
@@ -10,7 +10,6 @@ import AlertManager from '@features/global/services/alert-manager-service';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import JWTStorage from '@features/auth/jwt-storage-service';
|
||||
import Globals from '@features/global/services/globals-tdrive-app-service';
|
||||
import { useCurrentUser } from '@features/users/hooks/use-current-user';
|
||||
import UserAPIClient from '../../features/users/api/user-api-client';
|
||||
import { getUser } from '@features/users/hooks/use-user-list';
|
||||
|
||||
@@ -68,6 +67,7 @@ class CurrentUser extends Observable {
|
||||
const data = {
|
||||
status: user.tutorial_status,
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
Api.post('/ajax/users/account/set_tutorial_status', data, () => {});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
onChangeCompanyApplications,
|
||||
} from '../state/company-applications';
|
||||
import CompanyApplicationsAPIClient from 'app/features/applications/api/company-applications-api-client';
|
||||
import { useCurrentCompany } from '../../companies/hooks/use-companies';
|
||||
import { Application } from 'app/features/applications/types/application';
|
||||
import { LoadingState } from 'app/features/global/state/atoms/Loading';
|
||||
import useRouterWorkspace from 'app/features/router/hooks/use-router-workspace';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { atomFamily, selectorFamily } from 'recoil';
|
||||
|
||||
import { Application } from 'app/features/applications/types/application';
|
||||
import Collections from 'app/deprecated/CollectionsV1/Collections/Collections';
|
||||
import _ from 'lodash';
|
||||
|
||||
//Retro compatibility
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections';
|
||||
|
||||
import { CompanyType } from '@features/companies/types/company';
|
||||
import CompanyAPIClient from '@features/companies/api/company-api-client';
|
||||
import _ from 'lodash';
|
||||
|
||||
const companies: { [key: string]: CompanyType } = {};
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import Languages from '@features/global/services/languages-service';
|
||||
import { ToasterService as Toaster } from '@features/global/services/toaster-service';
|
||||
import { ConsoleMemberRole } from '@features/console/types/types';
|
||||
import Logger from '@features/global/framework/logger-service';
|
||||
import { JWTDataType } from '@features/auth/jwt-storage-service';
|
||||
|
||||
class ConsoleService {
|
||||
logger: Logger.Logger;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { MouseEventHandler } from 'react';
|
||||
import React from 'react';
|
||||
import {useDraggable} from '@dnd-kit/core';
|
||||
|
||||
type DraggableProps={
|
||||
@@ -7,7 +7,7 @@ type DraggableProps={
|
||||
}
|
||||
|
||||
export function Draggable(props:DraggableProps) {
|
||||
const {attributes, listeners, setNodeRef, transform} = useDraggable({
|
||||
const { attributes, listeners, setNodeRef } = useDraggable({
|
||||
id: `draggable-${props.id+1}`,
|
||||
data: {
|
||||
child: props.children
|
||||
|
||||
@@ -17,7 +17,7 @@ export const useDriveActions = (inPublicSharing?: boolean) => {
|
||||
const companyId = useRouterCompany();
|
||||
const sharedFilter = useRecoilValue(SharedWithMeFilterState);
|
||||
const sortItem = useRecoilValue(DriveItemSort);
|
||||
const [paginateItem, _] = useRecoilState(DriveItemPagination);
|
||||
const [ paginateItem ] = useRecoilState(DriveItemPagination);
|
||||
const { getQuota } = useUserQuota();
|
||||
|
||||
const refresh = useRecoilCallback(
|
||||
@@ -138,9 +138,11 @@ export const useDriveActions = (inPublicSharing?: boolean) => {
|
||||
);
|
||||
|
||||
const update = useCallback(
|
||||
async (update: Partial<DriveItem>, id: string, parentId: string) => {
|
||||
async (update: Partial<DriveItem>, id: string, parentId: string, previousName?: string) => {
|
||||
try {
|
||||
await DriveApiClient.update(companyId, id, update);
|
||||
const newItem = await DriveApiClient.update(companyId, id, update);
|
||||
if (previousName && previousName !== newItem.name && !update.name)
|
||||
ToasterService.warn(Languages.t('hooks.use-drive-actions.update_caused_a_rename', [previousName, newItem.name]));
|
||||
await refresh(id || '', true);
|
||||
if (!inPublicSharing) await refresh(parentId || '', true);
|
||||
if (update?.parent_id !== parentId) await refresh(update?.parent_id || '', true);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ToasterService } from '@features/global/services/toaster-service';
|
||||
import { LoadingStateInitTrue } from '@features/global/state/atoms/Loading';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { DriveItemAtom, DriveItemChildrenAtom, DriveItemPagination } from '../state/store';
|
||||
import { DriveItem } from '../types';
|
||||
@@ -20,7 +20,7 @@ export const useDriveItem = (id: string) => {
|
||||
// const children = useRecoilValue(DriveItemChildrenAtom(id));
|
||||
const [children, setChildren] = useRecoilState(DriveItemChildrenAtom(id));
|
||||
const [loading, setLoading] = useRecoilState(LoadingStateInitTrue('useDriveItem-' + id));
|
||||
const [_, setPaginateItem] = useRecoilState(DriveItemPagination);
|
||||
const [, setPaginateItem] = useRecoilState(DriveItemPagination);
|
||||
const {
|
||||
refresh: refreshItem,
|
||||
create,
|
||||
@@ -171,6 +171,7 @@ export const useDriveItem = (id: string) => {
|
||||
updateLevel,
|
||||
remove,
|
||||
refresh,
|
||||
restore,
|
||||
loadNextPage,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -6,18 +6,15 @@ import { useRecoilState } from 'recoil';
|
||||
import { DriveApiClient } from '../api-client/api-client';
|
||||
import { DriveViewerState } from '../state/viewer';
|
||||
import { DriveItem } from '../types';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
import { DriveCurrentFolderAtom } from 'app/views/client/body/drive/browser';
|
||||
import { useCurrentUser } from 'app/features/users/hooks/use-current-user';
|
||||
|
||||
export const useDrivePreviewModal = () => {
|
||||
const history = useHistory();
|
||||
const company = useRouterCompany();
|
||||
const [status, setStatus] = useRecoilState(DriveViewerState);
|
||||
const { user } = useCurrentUser();
|
||||
const [ parentId, setParentId ] = useRecoilState(
|
||||
const [ , setParentId ] = useRecoilState(
|
||||
DriveCurrentFolderAtom({ initialFolderId: 'user_'+user?.id }),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { string } from 'prop-types';
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export type SharedWithMeFilter = {
|
||||
|
||||
@@ -23,7 +23,7 @@ export const useSearchDriveItems = () => {
|
||||
const [loading, setLoading] = useRecoilState(LoadingState('useSearchDriveItems'));
|
||||
|
||||
const [searched, setSearched] = useRecoilState(SearchDriveItemsResultsState(companyId));
|
||||
const [recent, setRecent] = useRecoilState(RecentDriveItemsState(companyId));
|
||||
const [, setRecent] = useRecoilState(RecentDriveItemsState(companyId));
|
||||
|
||||
const opt = _.omitBy(
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect } from "react";
|
||||
import LoginService from '@features/auth/login-service';
|
||||
import UserAPIClient from '@features/users/api/user-api-client';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { CurrentUserState } from '../state/atoms/current-user';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
|
||||
@@ -4,8 +4,6 @@ import { atomFamily, selectorFamily, useSetRecoilState } from 'recoil';
|
||||
import { WorkspaceType } from '@features/workspaces/types/workspace';
|
||||
import WorkspaceAPIClient from '@features/workspaces/api/workspace-api-client';
|
||||
import Logger from '@features/global/framework/logger-service';
|
||||
import _ from 'lodash';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections';
|
||||
|
||||
const logger = Logger.getLogger('WorkspaceListState');
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ import { useDriveUpload } from '@features/drive/hooks/use-drive-upload';
|
||||
import { DriveItemSelectedList, DriveItemSort } from '@features/drive/state/store';
|
||||
import { formatBytes } from '@features/drive/utils';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
import _, { set } from 'lodash';
|
||||
import _ from 'lodash';
|
||||
import { memo, Suspense, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { atomFamily, useRecoilState, useSetRecoilState, useRecoilValue } from 'recoil';
|
||||
import { atomFamily, useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { DrivePreview } from '../../viewer/drive-preview';
|
||||
import {
|
||||
useOnBuildContextMenu,
|
||||
@@ -40,7 +40,7 @@ import useRouteState from 'app/features/router/hooks/use-route-state';
|
||||
import { SharedWithMeFilterState } from '@features/drive/state/shared-with-me-filter';
|
||||
import MenusManager from '@components/menus/menus-manager.jsx';
|
||||
import Languages from 'features/global/services/languages-service';
|
||||
import {DndContext, useSensors, useSensor, PointerSensor, DragOverlay} from '@dnd-kit/core';
|
||||
import { DndContext, useSensors, useSensor, PointerSensor, DragOverlay } from '@dnd-kit/core';
|
||||
import { Droppable } from 'app/features/dragndrop/hook/droppable';
|
||||
import { Draggable } from 'app/features/dragndrop/hook/draggable';
|
||||
import { useDriveActions } from '@features/drive/hooks/use-drive-actions';
|
||||
@@ -49,7 +49,6 @@ import { useCurrentUser } from 'app/features/users/hooks/use-current-user';
|
||||
import { ConfirmModal } from './modals/confirm-move';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { SortIcon } from 'app/atoms/icons-agnostic';
|
||||
import { useDrivePreview, useDrivePreviewLoading } from 'app/features/drive/hooks/use-drive-preview';
|
||||
|
||||
export const DriveCurrentFolderAtom = atomFamily<
|
||||
string,
|
||||
@@ -78,12 +77,9 @@ export default memo(
|
||||
? (user?.companies || []).find(company => company?.company.id === companyId)?.role
|
||||
: 'member';
|
||||
setTdriveTabToken(tdriveTabContextToken || null);
|
||||
const [filter, __] = useRecoilState(SharedWithMeFilterState);
|
||||
const { viewId, dirId, itemId } = useRouteState();
|
||||
const { status } = useDrivePreview();
|
||||
const { openWithId, close } = useDrivePreview();
|
||||
const [ filter ] = useRecoilState(SharedWithMeFilterState);
|
||||
const { viewId, dirId } = useRouteState();
|
||||
const [sortLabel] = useRecoilState(DriveItemSort)
|
||||
const { loading: isModalLoading } = useDrivePreviewLoading();
|
||||
const [parentId, _setParentId] = useRecoilState(
|
||||
DriveCurrentFolderAtom({
|
||||
context: context,
|
||||
|
||||
@@ -22,9 +22,7 @@ import { copyToClipboard } from '@features/global/utils/CopyClipboard';
|
||||
import { SharedWithMeFilterState } from '@features/drive/state/shared-with-me-filter';
|
||||
import { getCurrentUserList } from '@features/users/hooks/use-user-list';
|
||||
import useRouteState from 'app/features/router/hooks/use-route-state';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
import _, { set } from 'lodash';
|
||||
import _ from 'lodash';
|
||||
import Languages from 'features/global/services/languages-service';
|
||||
import { hasAnyPublicLinkAccess } from '@features/files/utils/access-info-helpers';
|
||||
import FeatureTogglesService, {
|
||||
@@ -42,7 +40,7 @@ export const useOnBuildContextMenu = (
|
||||
const [checkedIds, setChecked] = useRecoilState(DriveItemSelectedList);
|
||||
const checked = children.filter(c => checkedIds[c.id]);
|
||||
|
||||
const [_, setParentId] = useRecoilState(
|
||||
const [setParentId] = useRecoilState(
|
||||
DriveCurrentFolderAtom({ initialFolderId: initialParentId || 'root' }),
|
||||
);
|
||||
|
||||
@@ -59,11 +57,6 @@ export const useOnBuildContextMenu = (
|
||||
const setUsersModalState = useSetRecoilState(UsersModalAtom);
|
||||
const { open: preview } = useDrivePreview();
|
||||
const { viewId } = useRouteState();
|
||||
const company = useRouterCompany();
|
||||
|
||||
function getIdsFromArray(arr: DriveItem[]): string[] {
|
||||
return arr.map(obj => obj.id);
|
||||
}
|
||||
|
||||
return useCallback(
|
||||
async (parent?: Partial<DriveItemDetails> | null, item?: DriveItem) => {
|
||||
@@ -148,6 +141,7 @@ export const useOnBuildContextMenu = (
|
||||
},
|
||||
item.id,
|
||||
item.parent_id,
|
||||
item.name,
|
||||
);
|
||||
},
|
||||
}),
|
||||
@@ -377,7 +371,7 @@ export const useOnBuildContextMenu = (
|
||||
};
|
||||
|
||||
export const useOnBuildFileTypeContextMenu = () => {
|
||||
const [filter, setFilter] = useRecoilState(SharedWithMeFilterState);
|
||||
const [, setFilter] = useRecoilState(SharedWithMeFilterState);
|
||||
const mimeTypes = [
|
||||
{ key: Languages.t('components.item_context_menu.all'), value: '' },
|
||||
{ key: 'CSV', value: 'text/csv' },
|
||||
@@ -413,8 +407,8 @@ export const useOnBuildFileTypeContextMenu = () => {
|
||||
};
|
||||
|
||||
export const useOnBuildPeopleContextMenu = () => {
|
||||
const [filter, setFilter] = useRecoilState(SharedWithMeFilterState);
|
||||
const [_userList, setUserList] = useState(getCurrentUserList());
|
||||
const [, setFilter] = useRecoilState(SharedWithMeFilterState);
|
||||
const [_userList] = useState(getCurrentUserList());
|
||||
let userList = _userList;
|
||||
userList = _.uniqBy(userList, 'id');
|
||||
return useCallback(() => {
|
||||
@@ -438,7 +432,7 @@ export const useOnBuildPeopleContextMenu = () => {
|
||||
};
|
||||
|
||||
export const useOnBuildDateContextMenu = () => {
|
||||
const [filter, setFilter] = useRecoilState(SharedWithMeFilterState);
|
||||
const [, setFilter] = useRecoilState(SharedWithMeFilterState);
|
||||
return useCallback(() => {
|
||||
const menuItems = [
|
||||
{
|
||||
|
||||
@@ -9,14 +9,12 @@ export type DriveItemProps = {
|
||||
checked: boolean;
|
||||
onClick?: () => void;
|
||||
onBuildContextMenu: () => Promise<any[]>;
|
||||
inPublicSharing?: boolean;
|
||||
};
|
||||
|
||||
export type DriveItemOverlayProps = {
|
||||
item: DriveItem|null;
|
||||
className: string;
|
||||
};
|
||||
export const menuBuilder = async () => {};
|
||||
|
||||
export const CheckableIcon = ({
|
||||
show,
|
||||
|
||||
@@ -5,13 +5,12 @@ import Menu from '@components/menus/menu';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
import { useDrivePreview } from '@features/drive/hooks/use-drive-preview';
|
||||
import { formatBytes } from '@features/drive/utils';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { PublicIcon } from '../components/public-icon';
|
||||
import { CheckableIcon, DriveItemOverlayProps, DriveItemProps } from './common';
|
||||
import './style.scss';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import useRouteState from 'app/features/router/hooks/use-route-state';
|
||||
import { DocumentIcon } from './document-icon';
|
||||
import { hasAnyPublicLinkAccess } from '@features/files/utils/access-info-helpers';
|
||||
import { formatDateShort } from 'app/features/global/utils/Numbers';
|
||||
@@ -23,11 +22,10 @@ export const DocumentRow = ({
|
||||
checked,
|
||||
onClick,
|
||||
onBuildContextMenu,
|
||||
inPublicSharing,
|
||||
}: DriveItemProps) => {
|
||||
const history = useHistory();
|
||||
const [hover, setHover] = useState(false);
|
||||
const { open, close, isOpen } = useDrivePreview();
|
||||
const {open} = useDrivePreview();
|
||||
const company = useRouterCompany();
|
||||
|
||||
const preview = () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DesktopComputerIcon } from '@heroicons/react/solid';
|
||||
import { Base } from '@atoms/text';
|
||||
|
||||
export const DriveItem = ({ className, onClick }: { className?: string; onClick: Function }) => {
|
||||
export const DriveItem = ({ className, onClick }: { className?: string; onClick: () => void }) => {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useCompanyApplications } from 'app/features/applications/hooks/use-company-applications';
|
||||
import Browser from './browser';
|
||||
import { SelectorModal } from './modals/selector';
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export type ConfirmModalType = {
|
||||
parent_id: string;
|
||||
mode: 'move' | 'select-file' | 'select-files';
|
||||
title: string;
|
||||
onSelected: (ids: string[]) => Promise<void>;
|
||||
onSelected?: (ids: string[]) => Promise<void>;
|
||||
};
|
||||
|
||||
export const ConfirmModalAtom = atom<ConfirmModalType>({
|
||||
@@ -21,7 +21,6 @@ export const ConfirmModalAtom = atom<ConfirmModalType>({
|
||||
parent_id: '',
|
||||
mode: 'move',
|
||||
title: '',
|
||||
onSelected: async () => {},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -40,7 +39,7 @@ const ConfirmModalContent = () => {
|
||||
|
||||
const handleClose = async () => {
|
||||
setLoading(true);
|
||||
await state.onSelected(selected.map((i) => i.id));
|
||||
state.onSelected && await state.onSelected(selected.map((i) => i.id));
|
||||
setState({ ...state, open: false });
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { CreateModalAtom, CreateModalAtomType } from '.';
|
||||
import { CreateModalAtom } from '.';
|
||||
import { Button } from '@atoms/button/button';
|
||||
import { Input } from '@atoms/input/input-text';
|
||||
import { Info } from '@atoms/text';
|
||||
@@ -9,7 +9,7 @@ import Languages from "features/global/services/languages-service";
|
||||
|
||||
export const CreateFolder = () => {
|
||||
const [name, setName] = useState<string>('');
|
||||
const [loading, _] = useState<boolean>(false);
|
||||
const [loading] = useState<boolean>(false);
|
||||
const [state, setState] = useRecoilState(CreateModalAtom);
|
||||
const { create } = useDriveActions();
|
||||
const inputRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Button } from '@atoms/button/button';
|
||||
import { Input } from '@atoms/input/input-text';
|
||||
import { Info } from '@atoms/text';
|
||||
import { useDriveActions } from '@features/drive/hooks/use-drive-actions';
|
||||
import { useState } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
@@ -7,9 +7,7 @@ import { Application } from '@features/applications/types/application';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
DocumentDownloadIcon,
|
||||
FolderAddIcon,
|
||||
FolderDownloadIcon,
|
||||
LinkIcon,
|
||||
} from '@heroicons/react/outline';
|
||||
import { ReactNode } from 'react';
|
||||
@@ -35,8 +33,6 @@ export const CreateModalAtom = atom<CreateModalAtomType>({
|
||||
});
|
||||
|
||||
export const CreateModal = ({
|
||||
selectFromDevice,
|
||||
selectFolderFromDevice,
|
||||
addFromUrl,
|
||||
}: {
|
||||
selectFromDevice: () => void;
|
||||
|
||||
@@ -5,14 +5,12 @@ import Languages from 'features/global/services/languages-service';
|
||||
export const AccessLevel = ({
|
||||
level,
|
||||
onChange,
|
||||
canRemove,
|
||||
hiddenLevels,
|
||||
className,
|
||||
}: {
|
||||
disabled?: boolean;
|
||||
level: DriveFileAccessLevel | null;
|
||||
onChange: (level: DriveFileAccessLevel & 'remove') => void;
|
||||
canRemove?: boolean;
|
||||
className?: string;
|
||||
hiddenLevels?: string[];
|
||||
}) => {
|
||||
|
||||
@@ -4,7 +4,6 @@ import Avatar from '@atoms/avatar';
|
||||
import { Base, Info } from '@atoms/text';
|
||||
import { atom, useRecoilState } from 'recoil';
|
||||
import { useDriveItem } from '@features/drive/hooks/use-drive-item';
|
||||
import AlertManager from '@features/global/services/alert-manager-service';
|
||||
import { useCurrentUser } from '@features/users/hooks/use-current-user';
|
||||
import { useUser } from '@features/users/hooks/use-user';
|
||||
import currentUserService from '@features/users/services/current-user-service';
|
||||
@@ -55,7 +54,7 @@ const UserAccessLevel = ({
|
||||
}) => {
|
||||
const user = useUser(userId);
|
||||
const { user: currentUser } = useCurrentUser();
|
||||
const { item, loading, updateLevel } = useDriveItem(id);
|
||||
const { updateLevel } = useDriveItem(id);
|
||||
const [level, setLevel] = useState<DriveFileAccessLevel>(role == "admin" ? "manage" : "read");
|
||||
//const level = role == "admin" ? "manage" : "read";
|
||||
|
||||
@@ -78,7 +77,6 @@ const UserAccessLevel = ({
|
||||
<AccessLevel
|
||||
disabled={userId === currentUser?.id}
|
||||
level={level}
|
||||
canRemove
|
||||
onChange={level => {
|
||||
setLevel(level);
|
||||
updateLevel(userId || '', level);
|
||||
|
||||
@@ -15,7 +15,7 @@ export type SelectorModalType = {
|
||||
parent_id: string;
|
||||
mode: 'move' | 'select-file' | 'select-files';
|
||||
title: string;
|
||||
onSelected: (ids: string[]) => Promise<void>;
|
||||
onSelected?: (ids: string[]) => Promise<void>;
|
||||
};
|
||||
|
||||
export const SelectorModalAtom = atom<SelectorModalType>({
|
||||
@@ -25,7 +25,6 @@ export const SelectorModalAtom = atom<SelectorModalType>({
|
||||
parent_id: '',
|
||||
mode: 'move',
|
||||
title: '',
|
||||
onSelected: async () => {},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -39,7 +38,7 @@ export const SelectorModal = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const SelectorModalContent = (key:any,showfiles:boolean) => {
|
||||
const SelectorModalContent = (key: any) => {
|
||||
const [state, setState] = useRecoilState(SelectorModalAtom);
|
||||
const [selected, setSelected] = useState<DriveItem[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -91,8 +90,8 @@ const SelectorModalContent = (key:any,showfiles:boolean) => {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{key.showfiles && (
|
||||
|
||||
{key.showfiles && (
|
||||
<>
|
||||
{files.map(file => (
|
||||
<div
|
||||
@@ -135,7 +134,7 @@ const SelectorModalContent = (key:any,showfiles:boolean) => {
|
||||
className="float-right"
|
||||
onClick={async () => {
|
||||
setLoading(true);
|
||||
await state.onSelected(selected.map(i => i.id));
|
||||
state.onSelected && await state.onSelected(selected.map(i => i.id));
|
||||
setState({ ...state, open: false });
|
||||
setLoading(false);
|
||||
}}
|
||||
|
||||
@@ -41,7 +41,7 @@ const AccessModalContent = (props: {
|
||||
onCloseModal: () => void,
|
||||
}) => {
|
||||
const { id } = props;
|
||||
const { item, access, loading, update, refresh } = useDriveItem(id);
|
||||
const { item, access, loading, refresh } = useDriveItem(id);
|
||||
const { refresh: refreshCompany } = useCurrentCompany();
|
||||
useEffect(() => {
|
||||
refresh(id);
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import Avatar from '@atoms/avatar';
|
||||
import A from '@atoms/link';
|
||||
import { Modal, ModalContent } from '@atoms/modal';
|
||||
import { Base } from '@atoms/text';
|
||||
import { useCompanyApplications } from '@features/applications/hooks/use-company-applications';
|
||||
import { Application } from '@features/applications/types/application';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import {
|
||||
ChevronLeftIcon,
|
||||
DocumentDownloadIcon,
|
||||
FolderAddIcon,
|
||||
FolderDownloadIcon,
|
||||
LinkIcon,
|
||||
} from '@heroicons/react/outline';
|
||||
import { ReactNode } from 'react';
|
||||
import { atom, useRecoilState } from 'recoil';
|
||||
@@ -34,14 +29,12 @@ export const UploadModelAtom = atom<UploadModalAtomType>({
|
||||
export const UploadModal = ({
|
||||
selectFromDevice,
|
||||
selectFolderFromDevice,
|
||||
addFromUrl,
|
||||
}: {
|
||||
selectFromDevice: () => void;
|
||||
selectFolderFromDevice: () => void;
|
||||
addFromUrl: (url: string, name: string) => void;
|
||||
}) => {
|
||||
const [state, setState] = useRecoilState(UploadModelAtom);
|
||||
const { applications } = useCompanyApplications();
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
||||
@@ -10,7 +10,7 @@ import FeatureTogglesService, {
|
||||
FeatureNames,
|
||||
} from '@features/global/services/feature-toggles-service';
|
||||
|
||||
export default ({ sidebar }: { sidebar?: boolean }): JSX.Element => {
|
||||
export default (): JSX.Element => {
|
||||
const { user } = useCurrentUser();
|
||||
|
||||
if (!user) return <></>;
|
||||
|
||||
@@ -61,25 +61,22 @@ export default class UserParameter extends Component {
|
||||
if (this.state.page === 1) {
|
||||
return (
|
||||
<form className="" autoComplete="off">
|
||||
<div className="title">{this.state.i18n.t('scenes.apps.account.title')}</div>
|
||||
<div className="group_section">
|
||||
<Attribute
|
||||
label={this.state.i18n.t('scenes.apps.account.languages.menu_title')}
|
||||
description={this.state.i18n.t('scenes.apps.account.languages.text')}
|
||||
>
|
||||
<div className="parameters_form">
|
||||
<select
|
||||
value={this.state.i18n.language}
|
||||
onChange={ev => currentUserService.updateLanguage(ev.target.value)}
|
||||
>
|
||||
<option value="en">English</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="ru">Русский</option>
|
||||
<option value="vi">Tiếng Việt</option>
|
||||
</select>
|
||||
</div>
|
||||
</Attribute>
|
||||
</div>
|
||||
<Attribute
|
||||
label={this.state.i18n.t('scenes.apps.account.languages.menu_title')}
|
||||
description={this.state.i18n.t('scenes.apps.account.languages.text')}
|
||||
>
|
||||
<div className="parameters_form">
|
||||
<select
|
||||
value={this.state.i18n.language}
|
||||
onChange={ev => currentUserService.updateLanguage(ev.target.value)}
|
||||
>
|
||||
<option value="en">English</option>
|
||||
<option value="fr">Français</option>
|
||||
<option value="ru">Русский</option>
|
||||
<option value="vi">Tiếng Việt</option>
|
||||
</select>
|
||||
</div>
|
||||
</Attribute>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ export const CreateModalWithUploadZones = ({ initialParentId }: { initialParentI
|
||||
const setUploadModalState = useSetRecoilState(UploadModelAtom);
|
||||
const { uploadTree, uploadFromUrl } = useDriveUpload();
|
||||
const { user } = useCurrentUser();
|
||||
const [parentId, _] = useRecoilState(
|
||||
const [ parentId ] = useRecoilState(
|
||||
DriveCurrentFolderAtom({ initialFolderId: initialParentId || 'user_'+user?.id }),
|
||||
);
|
||||
|
||||
@@ -96,7 +96,7 @@ export const CreateModalWithUploadZones = ({ initialParentId }: { initialParentI
|
||||
export default () => {
|
||||
const { user } = useCurrentUser();
|
||||
const { viewId, dirId } = useRouteState();
|
||||
const [parentId, _] = useRecoilState(DriveCurrentFolderAtom({ initialFolderId: dirId || viewId || 'user_'+user?.id }));
|
||||
const [ parentId ] = useRecoilState(DriveCurrentFolderAtom({ initialFolderId: dirId || viewId || 'user_'+user?.id }));
|
||||
const { access, item } = useDriveItem(parentId);
|
||||
const { children: trashChildren } = useDriveItem(viewId === 'trash' ? 'trash' : 'trash_'+user?.id);
|
||||
const uploadZoneRef = useRef<UploadZone | null>(null);
|
||||
|
||||
@@ -53,7 +53,7 @@ export default () => {
|
||||
<div className="sm:hidden block mb-2">
|
||||
<div className="flex flex-row space-between w-full">
|
||||
<div className="grow">
|
||||
<Account sidebar />
|
||||
<Account />
|
||||
</div>
|
||||
<AppGrid />
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Transition } from '@headlessui/react';
|
||||
import { fadeTransition } from 'src/utils/transitions';
|
||||
@@ -24,7 +25,6 @@ import Controls from './controls';
|
||||
interface DrivePreviewProps {
|
||||
items: DriveItem[];
|
||||
}
|
||||
|
||||
export const DrivePreview: React.FC<DrivePreviewProps> = ({ items }) => {
|
||||
const history = useHistory();
|
||||
const company = useRouterCompany();
|
||||
@@ -64,6 +64,7 @@ export const DrivePreview: React.FC<DrivePreviewProps> = ({ items }) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (items.length < 2)
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
return () => {};
|
||||
addShortcut({ shortcut: 'Right', handler: handleSwitchRight });
|
||||
addShortcut({ shortcut: 'Left', handler: handleSwitchLeft });
|
||||
@@ -183,4 +184,7 @@ export const DrivePreview: React.FC<DrivePreviewProps> = ({ items }) => {
|
||||
</Transition>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
};
|
||||
DrivePreview.propTypes = {
|
||||
items: PropTypes.any.isRequired,
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import { Modal } from '@atoms/modal';
|
||||
import * as Text from '@atoms/text';
|
||||
import { addShortcut, removeShortcut } from '@features/global/services/shortcut-service';
|
||||
import { formatSize } from '@features/global/utils/format-file-size';
|
||||
import useRouterWorkspace from '@features/router/hooks/use-router-workspace';
|
||||
import currentUserService from '@features/users/services/current-user-service';
|
||||
import { UserType } from '@features/users/types/user';
|
||||
import {
|
||||
@@ -125,13 +124,12 @@ const Navigation = () => {
|
||||
};
|
||||
|
||||
const Footer = () => {
|
||||
const { status, close } = useFileViewer();
|
||||
const { status } = useFileViewer();
|
||||
const { download } = useViewerDisplayData();
|
||||
const { type = '' } = useViewerDisplayData();
|
||||
const user = status?.details?.user as UserType;
|
||||
const name = status.details?.metadata?.name;
|
||||
const extension = name?.split('.').pop();
|
||||
const workspaceId = useRouterWorkspace();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
+6651
-6274
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user