feat: Use relative paths for local file assets (#1027)
Esse commit está contido em:
gerado
+9
-3
@@ -11916,6 +11916,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mock-fs": {
|
||||||
|
"version": "4.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.13.0.tgz",
|
||||||
|
"integrity": "sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"moo": {
|
"moo": {
|
||||||
"version": "0.4.3",
|
"version": "0.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz",
|
||||||
@@ -12097,7 +12103,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.3.0",
|
"version": "5.3.0",
|
||||||
"resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||||
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
|
"integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
}
|
}
|
||||||
@@ -12234,7 +12240,7 @@
|
|||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
@@ -17293,7 +17299,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.4.4",
|
"version": "0.4.4",
|
||||||
"resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
|
||||||
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
|||||||
@@ -119,6 +119,7 @@
|
|||||||
"foreman": "^3.0.1",
|
"foreman": "^3.0.1",
|
||||||
"jest-enzyme": "^7.0.1",
|
"jest-enzyme": "^7.0.1",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
|
"mock-fs": "^4.13.0",
|
||||||
"node-sass": "^4.14.1",
|
"node-sass": "^4.14.1",
|
||||||
"popper.js": "^1.14.6",
|
"popper.js": "^1.14.6",
|
||||||
"redux-immutable-state-invariant": "^2.1.0",
|
"redux-immutable-state-invariant": "^2.1.0",
|
||||||
|
|||||||
@@ -398,6 +398,7 @@ export default class MockFactory {
|
|||||||
public static createLocalFileSystemOptions(): ILocalFileSystemProxyOptions {
|
public static createLocalFileSystemOptions(): ILocalFileSystemProxyOptions {
|
||||||
return {
|
return {
|
||||||
folderPath: "C:\\projects\\vott\\project",
|
folderPath: "C:\\projects\\vott\\project",
|
||||||
|
relativePath: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path, { relative } from "path";
|
||||||
import shortid from "shortid";
|
import shortid from "shortid";
|
||||||
import LocalFileSystem from "./localFileSystem";
|
import LocalFileSystem from "./localFileSystem";
|
||||||
|
import mockFs from "mock-fs";
|
||||||
|
|
||||||
jest.mock("electron", () => ({
|
jest.mock("electron", () => ({
|
||||||
dialog: {
|
dialog: {
|
||||||
@@ -9,14 +10,36 @@ jest.mock("electron", () => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
import { dialog } from "electron";
|
import { dialog } from "electron";
|
||||||
|
import { AssetService } from "../../../services/assetService";
|
||||||
|
|
||||||
describe("LocalFileSystem Storage Provider", () => {
|
describe("LocalFileSystem Storage Provider", () => {
|
||||||
let localFileSystem: LocalFileSystem = null;
|
let localFileSystem: LocalFileSystem = null;
|
||||||
|
const sourcePath = path.join("path", "to", "my", "source");
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
localFileSystem = new LocalFileSystem(null);
|
localFileSystem = new LocalFileSystem(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
mockFs({
|
||||||
|
path: {
|
||||||
|
to: {
|
||||||
|
my: {
|
||||||
|
source: {
|
||||||
|
"file1.jpg": "contents",
|
||||||
|
"file2.jpg": "contents",
|
||||||
|
"file3.jpg": "contents",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
mockFs.restore();
|
||||||
|
});
|
||||||
|
|
||||||
it("writes, reads and deletes a file as text", async () => {
|
it("writes, reads and deletes a file as text", async () => {
|
||||||
const filePath = path.join(process.cwd(), "test-output", `${shortid.generate()}.json`);
|
const filePath = path.join(process.cwd(), "test-output", `${shortid.generate()}.json`);
|
||||||
const contents = {
|
const contents = {
|
||||||
@@ -89,4 +112,35 @@ describe("LocalFileSystem Storage Provider", () => {
|
|||||||
it("deleting file that doesn't exist resolves successfully", async () => {
|
it("deleting file that doesn't exist resolves successfully", async () => {
|
||||||
await expect(localFileSystem.deleteFile("/path/to/fake/file.txt")).resolves.not.toBeNull();
|
await expect(localFileSystem.deleteFile("/path/to/fake/file.txt")).resolves.not.toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("getAssets uses an absolute path when relative not specified", async () => {
|
||||||
|
AssetService.createAssetFromFilePath = jest.fn(() => []);
|
||||||
|
await localFileSystem.getAssets(sourcePath);
|
||||||
|
const calls: any[] = (AssetService.createAssetFromFilePath as any).mock.calls;
|
||||||
|
expect(calls).toHaveLength(3);
|
||||||
|
calls.forEach((call, index) => {
|
||||||
|
const absolutePath = path.join(sourcePath, `file${index + 1}.jpg`);
|
||||||
|
expect(call).toEqual([
|
||||||
|
absolutePath,
|
||||||
|
undefined,
|
||||||
|
absolutePath,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("getAssets uses a path relative to the source connection when specified", async () => {
|
||||||
|
AssetService.createAssetFromFilePath = jest.fn(() => []);
|
||||||
|
await localFileSystem.getAssets(sourcePath, true);
|
||||||
|
const calls: any[] = (AssetService.createAssetFromFilePath as any).mock.calls;
|
||||||
|
expect(calls).toHaveLength(3);
|
||||||
|
calls.forEach((call, index) => {
|
||||||
|
const relativePath = `file${index + 1}.jpg`;
|
||||||
|
const absolutePath = path.join(sourcePath, relativePath);
|
||||||
|
expect(call).toEqual([
|
||||||
|
absolutePath,
|
||||||
|
undefined,
|
||||||
|
relativePath,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import fs from "fs";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import rimraf from "rimraf";
|
import rimraf from "rimraf";
|
||||||
import { IStorageProvider } from "../../../providers/storage/storageProviderFactory";
|
import { IStorageProvider } from "../../../providers/storage/storageProviderFactory";
|
||||||
import { IAsset, AssetType, StorageType } from "../../../models/applicationState";
|
import { IAsset, AssetType, StorageType, IConnection } from "../../../models/applicationState";
|
||||||
import { AssetService } from "../../../services/assetService";
|
import { AssetService } from "../../../services/assetService";
|
||||||
import { strings } from "../../../common/strings";
|
import { strings } from "../../../common/strings";
|
||||||
|
import { ILocalFileSystemProxyOptions } from "../../../providers/storage/localFileSystemProxy";
|
||||||
|
|
||||||
export default class LocalFileSystem implements IStorageProvider {
|
export default class LocalFileSystem implements IStorageProvider {
|
||||||
public storageType: StorageType.Local;
|
public storageType: StorageType.Local;
|
||||||
@@ -136,9 +137,12 @@ export default class LocalFileSystem implements IStorageProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAssets(folderPath?: string): Promise<IAsset[]> {
|
public async getAssets(sourceConnectionFolderPath?: string, relativePath: boolean = false): Promise<IAsset[]> {
|
||||||
return (await this.listFiles(path.normalize(folderPath)))
|
return (await this.listFiles(path.normalize(sourceConnectionFolderPath)))
|
||||||
.map((filePath) => AssetService.createAssetFromFilePath(filePath))
|
.map((filePath) => AssetService.createAssetFromFilePath(
|
||||||
|
filePath,
|
||||||
|
undefined,
|
||||||
|
relativePath ? path.relative(sourceConnectionFolderPath, filePath) : filePath))
|
||||||
.filter((asset) => asset.type !== AssetType.Unknown);
|
.filter((asset) => asset.type !== AssetType.Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ describe("Load default model from filesystem with TF io.IOHandler", () => {
|
|||||||
return Promise.resolve([]);
|
return Promise.resolve([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
const handler = new ElectronProxyHandler("folder");
|
const handler = new ElectronProxyHandler("folder", false);
|
||||||
try {
|
try {
|
||||||
const model = await tf.loadGraphModel(handler);
|
const model = await tf.loadGraphModel(handler);
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { LocalFileSystemProxy, ILocalFileSystemProxyOptions } from "../../provid
|
|||||||
export class ElectronProxyHandler implements tfc.io.IOHandler {
|
export class ElectronProxyHandler implements tfc.io.IOHandler {
|
||||||
protected readonly provider: LocalFileSystemProxy;
|
protected readonly provider: LocalFileSystemProxy;
|
||||||
|
|
||||||
constructor(folderPath: string) {
|
constructor(folderPath: string, relativePath: boolean) {
|
||||||
const options: ILocalFileSystemProxyOptions = { folderPath };
|
const options: ILocalFileSystemProxyOptions = { folderPath, relativePath };
|
||||||
this.provider = new LocalFileSystemProxy(options);
|
this.provider = new LocalFileSystemProxy(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export class ObjectDetection {
|
|||||||
const response = await axios.get(modelFolderPath + "/classes.json");
|
const response = await axios.get(modelFolderPath + "/classes.json");
|
||||||
this.jsonClasses = JSON.parse(JSON.stringify(response.data));
|
this.jsonClasses = JSON.parse(JSON.stringify(response.data));
|
||||||
} else {
|
} else {
|
||||||
const handler = new ElectronProxyHandler(modelFolderPath);
|
const handler = new ElectronProxyHandler(modelFolderPath, false);
|
||||||
this.model = await tf.loadGraphModel(handler);
|
this.model = await tf.loadGraphModel(handler);
|
||||||
this.jsonClasses = await handler.loadClasses();
|
this.jsonClasses = await handler.loadClasses();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class TestAssetProvider implements IAssetProvider {
|
|||||||
public initialize(): Promise<void> {
|
public initialize(): Promise<void> {
|
||||||
throw new Error("Method not implemented");
|
throw new Error("Method not implemented");
|
||||||
}
|
}
|
||||||
public getAssets(containerName?: string): Promise<IAsset[]> {
|
public getAssets(): Promise<IAsset[]> {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import getHostProcess, { HostProcessType } from "../../common/hostProcess";
|
|||||||
export interface IAssetProvider {
|
export interface IAssetProvider {
|
||||||
initialize?(): Promise<void>;
|
initialize?(): Promise<void>;
|
||||||
getAssets(containerName?: string): Promise<IAsset[]>;
|
getAssets(containerName?: string): Promise<IAsset[]>;
|
||||||
|
addDefaultPropsToNewConnection?(connection: IConnection): IConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -191,8 +191,8 @@ export class AzureBlobStorage implements IStorageProvider {
|
|||||||
* @param containerName - Container from which to retrieve assets. Defaults to
|
* @param containerName - Container from which to retrieve assets. Defaults to
|
||||||
* container specified in Azure Cloud Storage options
|
* container specified in Azure Cloud Storage options
|
||||||
*/
|
*/
|
||||||
public async getAssets(containerName?: string): Promise<IAsset[]> {
|
public async getAssets(): Promise<IAsset[]> {
|
||||||
containerName = (containerName) ? containerName : this.options.containerName;
|
const { containerName } = this.options;
|
||||||
const files = await this.listFiles(containerName);
|
const files = await this.listFiles(containerName);
|
||||||
const result: IAsset[] = [];
|
const result: IAsset[] = [];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { IpcRendererProxy } from "../../common/ipcRendererProxy";
|
|||||||
import { LocalFileSystemProxy, ILocalFileSystemProxyOptions } from "./localFileSystemProxy";
|
import { LocalFileSystemProxy, ILocalFileSystemProxyOptions } from "./localFileSystemProxy";
|
||||||
import { StorageProviderFactory } from "./storageProviderFactory";
|
import { StorageProviderFactory } from "./storageProviderFactory";
|
||||||
import registerProviders from "../../registerProviders";
|
import registerProviders from "../../registerProviders";
|
||||||
|
import MockFactory from "../../common/mockFactory";
|
||||||
|
|
||||||
describe("LocalFileSystem Proxy Storage Provider", () => {
|
describe("LocalFileSystem Proxy Storage Provider", () => {
|
||||||
it("Provider is registered with the StorageProviderFactory", () => {
|
it("Provider is registered with the StorageProviderFactory", () => {
|
||||||
@@ -19,6 +20,7 @@ describe("LocalFileSystem Proxy Storage Provider", () => {
|
|||||||
let provider: LocalFileSystemProxy = null;
|
let provider: LocalFileSystemProxy = null;
|
||||||
const options: ILocalFileSystemProxyOptions = {
|
const options: ILocalFileSystemProxyOptions = {
|
||||||
folderPath: "/test",
|
folderPath: "/test",
|
||||||
|
relativePath: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -122,5 +124,40 @@ describe("LocalFileSystem Proxy Storage Provider", () => {
|
|||||||
expect(IpcRendererProxy.send).toBeCalledWith("LocalFileSystem:listContainers", [expectedContainerPath]);
|
expect(IpcRendererProxy.send).toBeCalledWith("LocalFileSystem:listContainers", [expectedContainerPath]);
|
||||||
expect(actualFolders).toEqual(expectedFolders);
|
expect(actualFolders).toEqual(expectedFolders);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("sends relative path argument according to options", async () => {
|
||||||
|
const sendFunction = jest.fn();
|
||||||
|
IpcRendererProxy.send = sendFunction;
|
||||||
|
await provider.getAssets();
|
||||||
|
const { folderPath, relativePath } = options;
|
||||||
|
expect(IpcRendererProxy.send).toBeCalledWith("LocalFileSystem:getAssets", [folderPath, relativePath]);
|
||||||
|
sendFunction.mockReset();
|
||||||
|
|
||||||
|
const newFolderPath = "myFolder";
|
||||||
|
const newRelativePath = true;
|
||||||
|
|
||||||
|
const relativeProvider = new LocalFileSystemProxy({
|
||||||
|
folderPath: newFolderPath,
|
||||||
|
relativePath: newRelativePath,
|
||||||
|
});
|
||||||
|
await relativeProvider.getAssets();
|
||||||
|
expect(IpcRendererProxy.send).toBeCalledWith("LocalFileSystem:getAssets", [newFolderPath, newRelativePath]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds default props to a new connection", () => {
|
||||||
|
const connection = MockFactory.createTestConnection();
|
||||||
|
delete connection.providerOptions["relativePath"];
|
||||||
|
expect(connection).not.toHaveProperty("providerOptions.relativePath");
|
||||||
|
delete connection.id;
|
||||||
|
expect(provider.addDefaultPropsToNewConnection(connection))
|
||||||
|
.toHaveProperty("providerOptions.relativePath", true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not add default props to existing connection", () => {
|
||||||
|
const connection = MockFactory.createTestConnection();
|
||||||
|
delete connection.providerOptions["relativePath"];
|
||||||
|
expect(provider.addDefaultPropsToNewConnection(connection))
|
||||||
|
.not.toHaveProperty("providerOptions.relativePath");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { IpcRendererProxy } from "../../common/ipcRendererProxy";
|
import { IpcRendererProxy } from "../../common/ipcRendererProxy";
|
||||||
import { IStorageProvider } from "./storageProviderFactory";
|
import { IStorageProvider } from "./storageProviderFactory";
|
||||||
import { IAssetProvider } from "./assetProviderFactory";
|
import { IAssetProvider } from "./assetProviderFactory";
|
||||||
import { IAsset, StorageType } from "../../models/applicationState";
|
import { IAsset, IConnection, StorageType } from "../../models/applicationState";
|
||||||
|
|
||||||
const PROXY_NAME = "LocalFileSystem";
|
const PROXY_NAME = "LocalFileSystem";
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ const PROXY_NAME = "LocalFileSystem";
|
|||||||
*/
|
*/
|
||||||
export interface ILocalFileSystemProxyOptions {
|
export interface ILocalFileSystemProxyOptions {
|
||||||
folderPath: string;
|
folderPath: string;
|
||||||
|
relativePath: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,6 +27,7 @@ export class LocalFileSystemProxy implements IStorageProvider, IAssetProvider {
|
|||||||
if (!this.options) {
|
if (!this.options) {
|
||||||
this.options = {
|
this.options = {
|
||||||
folderPath: null,
|
folderPath: null,
|
||||||
|
relativePath: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,8 +127,26 @@ export class LocalFileSystemProxy implements IStorageProvider, IAssetProvider {
|
|||||||
* Retrieve assets from directory
|
* Retrieve assets from directory
|
||||||
* @param folderName - Directory containing assets
|
* @param folderName - Directory containing assets
|
||||||
*/
|
*/
|
||||||
public getAssets(folderName?: string): Promise<IAsset[]> {
|
public getAssets(): Promise<IAsset[]> {
|
||||||
const folderPath = [this.options.folderPath, folderName].join("/");
|
const { folderPath, relativePath } = this.options;
|
||||||
return IpcRendererProxy.send(`${PROXY_NAME}:getAssets`, [folderPath]);
|
return IpcRendererProxy.send(`${PROXY_NAME}:getAssets`, [folderPath, relativePath]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds default properties to new connections
|
||||||
|
*
|
||||||
|
* Currently adds `relativePath: true` to the providerOptions. Pre-existing connections
|
||||||
|
* will only use absolute path
|
||||||
|
*
|
||||||
|
* @param connection Connection
|
||||||
|
*/
|
||||||
|
public addDefaultPropsToNewConnection(connection: IConnection): IConnection {
|
||||||
|
return connection.id ? connection : {
|
||||||
|
...connection,
|
||||||
|
providerOptions: {
|
||||||
|
...connection.providerOptions,
|
||||||
|
relativePath: true,
|
||||||
|
} as any,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class TestStorageProvider implements IStorageProvider {
|
|||||||
public deleteContainer(folderPath: string): Promise<void> {
|
public deleteContainer(folderPath: string): Promise<void> {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
public getAssets(containerName?: string): Promise<IAsset[]> {
|
public getAssets(): Promise<IAsset[]> {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import ConnectionForm from "./connectionForm";
|
|||||||
import ConnectionItem from "./connectionItem";
|
import ConnectionItem from "./connectionItem";
|
||||||
import "./connectionsPage.scss";
|
import "./connectionsPage.scss";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
import { AssetProviderFactory } from "../../../../providers/storage/assetProviderFactory";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties for Connection Page
|
* Properties for Connection Page
|
||||||
@@ -134,12 +135,20 @@ export default class ConnectionPage extends React.Component<IConnectionPageProps
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onFormSubmit = async (connection: IConnection) => {
|
private onFormSubmit = async (connection: IConnection) => {
|
||||||
|
connection = this.addDefaultPropsIfNewConnection(connection);
|
||||||
await this.props.actions.saveConnection(connection);
|
await this.props.actions.saveConnection(connection);
|
||||||
toast.success(interpolate(strings.connections.messages.saveSuccess, { connection }));
|
toast.success(interpolate(strings.connections.messages.saveSuccess, { connection }));
|
||||||
|
|
||||||
this.props.history.goBack();
|
this.props.history.goBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private addDefaultPropsIfNewConnection(connection: IConnection): IConnection {
|
||||||
|
const assetProvider = AssetProviderFactory.createFromConnection(connection);
|
||||||
|
return !connection.id && assetProvider.addDefaultPropsToNewConnection
|
||||||
|
? assetProvider.addDefaultPropsToNewConnection(connection)
|
||||||
|
: connection;
|
||||||
|
}
|
||||||
|
|
||||||
private onFormCancel() {
|
private onFormCancel() {
|
||||||
this.props.history.goBack();
|
this.props.history.goBack();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import HtmlFileReader from "../common/htmlFileReader";
|
|||||||
import { encodeFileURI } from "../common/utils";
|
import { encodeFileURI } from "../common/utils";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import registerMixins from "../registerMixins";
|
import registerMixins from "../registerMixins";
|
||||||
|
import MD5 from "md5.js";
|
||||||
|
|
||||||
describe("Asset Service", () => {
|
describe("Asset Service", () => {
|
||||||
describe("Static Methods", () => {
|
describe("Static Methods", () => {
|
||||||
@@ -24,6 +25,22 @@ describe("Asset Service", () => {
|
|||||||
expect(asset.format).toEqual("jpg");
|
expect(asset.format).toEqual("jpg");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("creates an asset using file path as identifier", () => {
|
||||||
|
const path = "c:/dir1/dir2/asset1.jpg";
|
||||||
|
const asset = AssetService.createAssetFromFilePath(path);
|
||||||
|
const expectedIdenfifier = `file:${path}`;
|
||||||
|
const expectedId = new MD5().update(expectedIdenfifier).digest("hex");
|
||||||
|
expect(asset.id).toEqual(expectedId);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("creates an asset using passed in identifier", () => {
|
||||||
|
const path = "C:\\dir1\\dir2\\asset1.jpg";
|
||||||
|
const identifier = "asset1.jpg";
|
||||||
|
const asset = AssetService.createAssetFromFilePath(path, undefined, identifier);
|
||||||
|
const expectedId = new MD5().update(identifier).digest("hex");
|
||||||
|
expect(asset.id).toEqual(expectedId);
|
||||||
|
});
|
||||||
|
|
||||||
it("creates an asset from an encoded file", () => {
|
it("creates an asset from an encoded file", () => {
|
||||||
const path = "C:\\dir1\\dir2\\asset%201.jpg";
|
const path = "C:\\dir1\\dir2\\asset%201.jpg";
|
||||||
const asset = AssetService.createAssetFromFilePath(path);
|
const asset = AssetService.createAssetFromFilePath(path);
|
||||||
|
|||||||
@@ -23,13 +23,15 @@ export class AssetService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create IAsset from filePath
|
* Create IAsset from filePath
|
||||||
* @param filePath - filepath of asset
|
* @param assetFilePath - filepath of asset
|
||||||
* @param fileName - name of asset
|
* @param assetFileName - name of asset
|
||||||
*/
|
*/
|
||||||
public static createAssetFromFilePath(filePath: string, fileName?: string): IAsset {
|
public static createAssetFromFilePath(
|
||||||
Guard.empty(filePath);
|
assetFilePath: string,
|
||||||
|
assetFileName?: string,
|
||||||
const normalizedPath = filePath.toLowerCase();
|
assetIdentifier?: string): IAsset {
|
||||||
|
Guard.empty(assetFilePath);
|
||||||
|
const normalizedPath = assetFilePath.toLowerCase();
|
||||||
|
|
||||||
// If the path is not already prefixed with a protocol
|
// If the path is not already prefixed with a protocol
|
||||||
// then assume it comes from the local file system
|
// then assume it comes from the local file system
|
||||||
@@ -37,17 +39,18 @@ export class AssetService {
|
|||||||
!normalizedPath.startsWith("https://") &&
|
!normalizedPath.startsWith("https://") &&
|
||||||
!normalizedPath.startsWith("file:")) {
|
!normalizedPath.startsWith("file:")) {
|
||||||
// First replace \ character with / the do the standard url encoding then encode unsupported characters
|
// First replace \ character with / the do the standard url encoding then encode unsupported characters
|
||||||
filePath = encodeFileURI(filePath, true);
|
assetFilePath = encodeFileURI(assetFilePath, true);
|
||||||
}
|
}
|
||||||
|
assetIdentifier = assetIdentifier || assetFilePath;
|
||||||
|
|
||||||
const md5Hash = new MD5().update(filePath).digest("hex");
|
const md5Hash = new MD5().update(assetIdentifier).digest("hex");
|
||||||
const pathParts = filePath.split(/[\\\/]/);
|
const pathParts = assetFilePath.split(/[\\\/]/);
|
||||||
// Example filename: video.mp4#t=5
|
// Example filename: video.mp4#t=5
|
||||||
// fileNameParts[0] = "video"
|
// fileNameParts[0] = "video"
|
||||||
// fileNameParts[1] = "mp4"
|
// fileNameParts[1] = "mp4"
|
||||||
// fileNameParts[2] = "t=5"
|
// fileNameParts[2] = "t=5"
|
||||||
fileName = fileName || pathParts[pathParts.length - 1];
|
assetFileName = assetFileName || pathParts[pathParts.length - 1];
|
||||||
const fileNameParts = fileName.split(".");
|
const fileNameParts = assetFileName.split(".");
|
||||||
const extensionParts = fileNameParts[fileNameParts.length - 1].split(/[\?#]/);
|
const extensionParts = fileNameParts[fileNameParts.length - 1].split(/[\?#]/);
|
||||||
const assetFormat = extensionParts[0];
|
const assetFormat = extensionParts[0];
|
||||||
|
|
||||||
@@ -58,8 +61,8 @@ export class AssetService {
|
|||||||
format: assetFormat,
|
format: assetFormat,
|
||||||
state: AssetState.NotVisited,
|
state: AssetState.NotVisited,
|
||||||
type: assetType,
|
type: assetType,
|
||||||
name: fileName,
|
name: assetFileName,
|
||||||
path: filePath,
|
path: assetFilePath,
|
||||||
size: null,
|
size: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Referência em uma Nova Issue
Bloquear um usuário