mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-926: Migrate import code to a dedicated module.
This commit is contained in:
@@ -20,11 +20,11 @@
|
|||||||
/**
|
/**
|
||||||
* The controller for the connection import page.
|
* The controller for the connection import page.
|
||||||
*/
|
*/
|
||||||
angular.module('settings').controller('importConnectionsController', ['$scope', '$injector',
|
angular.module('import').controller('importConnectionsController', ['$scope', '$injector',
|
||||||
function importConnectionsController($scope, $injector) {
|
function importConnectionsController($scope, $injector) {
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
const connectionImportParseService = $injector.get('connectionImportParseService');
|
const connectionParseService = $injector.get('connectionParseService');
|
||||||
const connectionService = $injector.get('connectionService');
|
const connectionService = $injector.get('connectionService');
|
||||||
|
|
||||||
function processData(type, data) {
|
function processData(type, data) {
|
||||||
@@ -36,18 +36,18 @@ angular.module('settings').controller('importConnectionsController', ['$scope',
|
|||||||
|
|
||||||
case "application/json":
|
case "application/json":
|
||||||
case "text/json":
|
case "text/json":
|
||||||
requestBody = connectionImportParseService.parseJSON(data);
|
requestBody = connectionParseService.parseJSON(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "text/csv":
|
case "text/csv":
|
||||||
requestBody = connectionImportParseService.parseCSV(data);
|
requestBody = connectionParseService.parseCSV(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "application/yaml":
|
case "application/yaml":
|
||||||
case "application/x-yaml":
|
case "application/x-yaml":
|
||||||
case "text/yaml":
|
case "text/yaml":
|
||||||
case "text/x-yaml":
|
case "text/x-yaml":
|
||||||
requestBody = connectionImportParseService.parseYAML(data);
|
requestBody = connectionParseService.parseYAML(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
24
guacamole/src/main/frontend/src/app/import/importModule.js
Normal file
24
guacamole/src/main/frontend/src/app/import/importModule.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module for code supporting importing user-supplied files. Currently, only
|
||||||
|
* connection import is supported.
|
||||||
|
*/
|
||||||
|
angular.module('import', ['rest']);
|
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* 'License'); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* global _ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service for parsing user-provided CSV connection data for bulk import.
|
||||||
|
*/
|
||||||
|
angular.module('import').factory('connectionCSVService',
|
||||||
|
['$injector', function connectionCSVService($injector) {
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
const $q = $injector.get('$q');
|
||||||
|
const $routeParams = $injector.get('$routeParams');
|
||||||
|
const schemaService = $injector.get('schemaService');
|
||||||
|
|
||||||
|
const service = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a promise that resolves to an object detailing the connection
|
||||||
|
* attributes for the current data source, as well as the connection
|
||||||
|
* paremeters for every protocol, for the current data source.
|
||||||
|
*
|
||||||
|
* The object that the promise will contain an "attributes" key that maps to
|
||||||
|
* a set of attribute names, and a "protocolParameters" key that maps to an
|
||||||
|
* object mapping protocol names to sets of parameter names for that protocol.
|
||||||
|
*
|
||||||
|
* The intended use case for this object is to determine if there is a
|
||||||
|
* connection parameter or attribute with a given name, by e.g. checking the
|
||||||
|
* path `.protocolParameters[protocolName]` to see if a protocol exists,
|
||||||
|
* checking the path `.protocolParameters[protocolName][fieldName]` to see
|
||||||
|
* if a parameter exists for a given protocol, or checking the path
|
||||||
|
* `.attributes[fieldName]` to check if a connection attribute exists.
|
||||||
|
*
|
||||||
|
* @returns {Promise.<Object>}
|
||||||
|
*/
|
||||||
|
function getFieldLookups() {
|
||||||
|
|
||||||
|
// The current data source - the one that the connections will be
|
||||||
|
// imported into
|
||||||
|
const dataSource = $routeParams.dataSource;
|
||||||
|
|
||||||
|
// Fetch connection attributes and protocols for the current data source
|
||||||
|
return $q.all({
|
||||||
|
attributes : schemaService.getConnectionAttributes(dataSource),
|
||||||
|
protocols : schemaService.getProtocols(dataSource)
|
||||||
|
})
|
||||||
|
.then(function connectionStructureRetrieved({attributes, protocols}) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
// Translate the forms and fields into a flat map of attribute
|
||||||
|
// name to `true` boolean value
|
||||||
|
attributes: attributes.reduce(
|
||||||
|
(attributeMap, form) => {
|
||||||
|
form.fields.forEach(
|
||||||
|
field => attributeMap[field.name] = true);
|
||||||
|
return attributeMap
|
||||||
|
}, {}),
|
||||||
|
|
||||||
|
// Translate the protocol definitions into a map of protocol
|
||||||
|
// name to map of field name to `true` boolean value
|
||||||
|
protocolParameters: _.mapValues(
|
||||||
|
protocols, protocol => protocol.connectionForms.reduce(
|
||||||
|
(protocolFieldMap, form) => {
|
||||||
|
form.fields.forEach(
|
||||||
|
field => protocolFieldMap[field.name] = true);
|
||||||
|
return protocolFieldMap;
|
||||||
|
}, {}))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @returns {Promise.<Function.<String[], Object>>}
|
||||||
|
* A promise that will resolve to a function that translates a CSV data
|
||||||
|
* row (array of strings) to a connection object.
|
||||||
|
*/
|
||||||
|
service.getCSVTransformer = function getCSVTransformer(headerRow) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return service;
|
||||||
|
|
||||||
|
}]);
|
@@ -26,8 +26,8 @@ import { parse as parseYAMLData } from 'yaml'
|
|||||||
* A service for parsing user-provided JSON, YAML, or JSON connection data into
|
* A service for parsing user-provided JSON, YAML, or JSON connection data into
|
||||||
* an appropriate format for bulk uploading using the PATCH REST endpoint.
|
* an appropriate format for bulk uploading using the PATCH REST endpoint.
|
||||||
*/
|
*/
|
||||||
angular.module('settings').factory('connectionImportParseService',
|
angular.module('import').factory('connectionParseService',
|
||||||
['$injector', function connectionImportParseService($injector) {
|
['$injector', function connectionParseService($injector) {
|
||||||
|
|
||||||
// Required types
|
// Required types
|
||||||
const Connection = $injector.get('Connection');
|
const Connection = $injector.get('Connection');
|
||||||
@@ -71,35 +71,6 @@ angular.module('settings').factory('connectionImportParseService',
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a provided YAML representation of a connection list into a JSON
|
|
||||||
* string to be submitted to the PATCH REST endpoint. The returned JSON
|
|
||||||
* string will contain a PATCH operation to create each connection in the
|
|
||||||
* provided list.
|
|
||||||
*
|
|
||||||
* @param {String} yamlData
|
|
||||||
* The YAML-encoded connection list to convert to a PATCH request body.
|
|
||||||
*
|
|
||||||
* @return {Promise.<Connection[]>}
|
|
||||||
* A promise resolving to an array of Connection objects, one for each
|
|
||||||
* connection in the provided CSV.
|
|
||||||
*/
|
|
||||||
service.parseYAML = function parseYAML(yamlData) {
|
|
||||||
|
|
||||||
// Parse from YAML into a javascript array
|
|
||||||
const parsedData = parseYAMLData(yamlData);
|
|
||||||
|
|
||||||
// Check that the data is the correct format, and not empty
|
|
||||||
performBasicChecks(parsedData);
|
|
||||||
|
|
||||||
// Convert to an array of Connection objects and return
|
|
||||||
const deferredConnections = $q.defer();
|
|
||||||
deferredConnections.resolve(
|
|
||||||
parsedData.map(connection => new Connection(connection)));
|
|
||||||
return deferredConnections.promise;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise that resolves to an object detailing the connection
|
* Returns a promise that resolves to an object detailing the connection
|
||||||
@@ -321,6 +292,35 @@ angular.module('settings').factory('connectionImportParseService',
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a provided YAML representation of a connection list into a JSON
|
||||||
|
* string to be submitted to the PATCH REST endpoint. The returned JSON
|
||||||
|
* string will contain a PATCH operation to create each connection in the
|
||||||
|
* provided list.
|
||||||
|
*
|
||||||
|
* @param {String} yamlData
|
||||||
|
* The YAML-encoded connection list to convert to a PATCH request body.
|
||||||
|
*
|
||||||
|
* @return {Promise.<Connection[]>}
|
||||||
|
* A promise resolving to an array of Connection objects, one for each
|
||||||
|
* connection in the provided CSV.
|
||||||
|
*/
|
||||||
|
service.parseYAML = function parseYAML(yamlData) {
|
||||||
|
|
||||||
|
// Parse from YAML into a javascript array
|
||||||
|
const parsedData = parseYAMLData(yamlData);
|
||||||
|
|
||||||
|
// Check that the data is the correct format, and not empty
|
||||||
|
performBasicChecks(parsedData);
|
||||||
|
|
||||||
|
// Convert to an array of Connection objects and return
|
||||||
|
const deferredConnections = $q.defer();
|
||||||
|
deferredConnections.resolve(
|
||||||
|
parsedData.map(connection => new Connection(connection)));
|
||||||
|
return deferredConnections.promise;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a provided JSON representation of a connection list into a JSON
|
* Convert a provided JSON representation of a connection list into a JSON
|
||||||
* string to be submitted to the PATCH REST endpoint. The returned JSON
|
* string to be submitted to the PATCH REST endpoint. The returned JSON
|
@@ -20,7 +20,7 @@
|
|||||||
/**
|
/**
|
||||||
* Service which defines the ParseError class.
|
* Service which defines the ParseError class.
|
||||||
*/
|
*/
|
||||||
angular.module('settings').factory('ParseError', [function defineParseError() {
|
angular.module('import').factory('ParseError', [function defineParseError() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An error representing a parsing failure when attempting to convert
|
* An error representing a parsing failure when attempting to convert
|
@@ -127,10 +127,10 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Connection import page
|
// Connection import page
|
||||||
.when('/settings/:dataSource/import', {
|
.when('/import/:dataSource/connection', {
|
||||||
title : 'APP.NAME',
|
title : 'APP.NAME',
|
||||||
bodyClassName : 'settings',
|
bodyClassName : 'settings',
|
||||||
templateUrl : 'app/settings/templates/settingsImport.html',
|
templateUrl : 'app/import/templates/connectionImport.html',
|
||||||
controller : 'importConnectionsController',
|
controller : 'importConnectionsController',
|
||||||
resolve : { updateCurrentToken: updateCurrentToken }
|
resolve : { updateCurrentToken: updateCurrentToken }
|
||||||
})
|
})
|
||||||
|
@@ -156,41 +156,38 @@ angular.module('rest').factory('connectionService', ['$injector',
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a request to the REST API to create multiple connections, returning a
|
* Makes a request to the REST API to apply a supplied list of connection
|
||||||
* a promise that can be used for processing the results of the call. This
|
* patches, returning a promise that can be used for processing the results
|
||||||
* operation is atomic - if any errors are encountered during the connection
|
* of the call.
|
||||||
* creation process, the entire request will fail, and no connections will be
|
*
|
||||||
* created.
|
* This operation is atomic - if any errors are encountered during the
|
||||||
|
* connection patching process, the entire request will fail, and no
|
||||||
|
* changes will be persisted.
|
||||||
*
|
*
|
||||||
* @param {Connection[]} connections The connections to create.
|
* @param {DirectoryPatch.<Connection>[]} patches
|
||||||
|
* An array of patches to apply.
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
* A promise for the HTTP call which will succeed if and only if the
|
* A promise for the HTTP call which will succeed if and only if the
|
||||||
* create operation is successful.
|
* patch operation is successful.
|
||||||
*/
|
*/
|
||||||
service.createConnections = function createConnections(dataSource, connections) {
|
service.patchConnections = function patchConnections(dataSource, patches) {
|
||||||
|
|
||||||
// An object containing a PATCH operation to create each connection
|
// Make the PATCH request
|
||||||
const patchBody = connections.map(connection => ({
|
|
||||||
op: "add",
|
|
||||||
path: "/",
|
|
||||||
value: connection
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Make a PATCH request to create the connections
|
|
||||||
return authenticationService.request({
|
return authenticationService.request({
|
||||||
method : 'PATCH',
|
method : 'PATCH',
|
||||||
url : 'api/session/data/' + encodeURIComponent(dataSource) + '/connections',
|
url : 'api/session/data/' + encodeURIComponent(dataSource) + '/connections',
|
||||||
data : patchBody
|
data : patches
|
||||||
})
|
})
|
||||||
|
|
||||||
// Clear the cache
|
// Clear the cache
|
||||||
.then(function connectionUpdated(){
|
.then(function connectionsPatched(){
|
||||||
cacheService.connections.removeAll();
|
cacheService.connections.removeAll();
|
||||||
|
|
||||||
// Clear users cache to force reload of permissions for this
|
// Clear users cache to force reload of permissions for any
|
||||||
// newly updated connection
|
// newly created or replaced connections
|
||||||
cacheService.users.removeAll();
|
cacheService.users.removeAll();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service which defines the DirectoryPatch class.
|
||||||
|
*/
|
||||||
|
angular.module('rest').factory('DirectoryPatch', [function defineDirectoryPatch() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object consumed by REST API calls when representing changes to an
|
||||||
|
* arbitrary set of directory-based objects.
|
||||||
|
* @constructor
|
||||||
|
*
|
||||||
|
* @template DirectoryObject
|
||||||
|
* The directory-based object type that this DirectoryPatch will
|
||||||
|
* operate on.
|
||||||
|
*
|
||||||
|
* @param {DirectoryObject|Object} [template={}]
|
||||||
|
* The object whose properties should be copied within the new
|
||||||
|
* DirectoryPatch.
|
||||||
|
*/
|
||||||
|
var DirectoryPatch = function DirectoryPatch(template) {
|
||||||
|
|
||||||
|
// Use empty object by default
|
||||||
|
template = template || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The operation to apply to the objects indicated by the path. Valid
|
||||||
|
* operation values are defined within DirectoryPatch.Operation.
|
||||||
|
*
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
this.op = template.op;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path of the objects to modify. For creation of new objects, this
|
||||||
|
* should be "/". Otherwise, it should be "/{identifier}", specifying
|
||||||
|
* the identifier of the existing object being modified.
|
||||||
|
*
|
||||||
|
* @type {String}
|
||||||
|
* @default '/'
|
||||||
|
*/
|
||||||
|
this.path = template.path || '/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object being added or replaced, or the identifier of the object
|
||||||
|
* being removed.
|
||||||
|
*
|
||||||
|
* @type {DirectoryObject|String}
|
||||||
|
*/
|
||||||
|
this.value = template.value;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All valid patch operations for directory-based objects.
|
||||||
|
*/
|
||||||
|
DirectoryPatch.Operation = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified object to the relation.
|
||||||
|
*/
|
||||||
|
ADD : "add",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified object from the relation.
|
||||||
|
*/
|
||||||
|
REPLACE : "replace",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified object from the relation.
|
||||||
|
*/
|
||||||
|
REMOVE : "remove"
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return DirectoryPatch;
|
||||||
|
|
||||||
|
}]);
|
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service which defines the DirectoryPatchOutcome class.
|
||||||
|
*/
|
||||||
|
angular.module('rest').factory('DirectoryPatchOutcome', [
|
||||||
|
function defineDirectoryPatchOutcome() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object returned by a PATCH request to a directory REST API,
|
||||||
|
* representing the outcome associated with a particular patch in the
|
||||||
|
* request. This object can indicate either a successful or unsuccessful
|
||||||
|
* response. The error field is only meaningful for unsuccessful patches.
|
||||||
|
* @constructor
|
||||||
|
*
|
||||||
|
* @template DirectoryObject
|
||||||
|
* The directory-based object type that this DirectoryPatchOutcome
|
||||||
|
* represents a patch outcome for.
|
||||||
|
*
|
||||||
|
* @param {DirectoryObject|Object} [template={}]
|
||||||
|
* The object whose properties should be copied within the new
|
||||||
|
* DirectoryPatchOutcome.
|
||||||
|
*/
|
||||||
|
var DirectoryPatchOutcome = function DirectoryPatchOutcome(template) {
|
||||||
|
|
||||||
|
// Use empty object by default
|
||||||
|
template = template || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The operation to apply to the objects indicated by the path. Valid
|
||||||
|
* operation values are defined within DirectoryPatch.Operation.
|
||||||
|
*
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
this.op = template.op;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path of the object operated on by the corresponding patch in the
|
||||||
|
* request.
|
||||||
|
*
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
this.path = template.path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of the object operated on by the corresponding patch
|
||||||
|
* in the request. If the object was newly created and the PATCH request
|
||||||
|
* did not fail, this will be the identifier of the newly created object.
|
||||||
|
*
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
this.identifier = template.identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The error message associated with the failure, if the patch failed to
|
||||||
|
* apply.
|
||||||
|
*
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
this.error = template.error;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return DirectoryPatch;
|
||||||
|
|
||||||
|
}]);
|
Reference in New Issue
Block a user