diff --git a/application/views/templates/FHC-Common.php b/application/views/templates/FHC-Common.php
index 6c6f58b8f..aa724def8 100644
--- a/application/views/templates/FHC-Common.php
+++ b/application/views/templates/FHC-Common.php
@@ -38,6 +38,7 @@
$filterwidget = isset($filterwidget) ? $filterwidget : false;
$navigationcomponent = isset($navigationcomponent) ? $navigationcomponent : false;
$navigationwidget = isset($navigationwidget) ? $navigationwidget : false;
+ $restclient = isset($restclient) ? $restclient : false;
$tablecomponent = isset($tablecomponent) ? $tablecomponent : false;
$tablewidget = isset($tablewidget) ? $tablewidget : false;
$udfs = isset($udfs) ? $udfs : false;
diff --git a/application/views/templates/FHC-Footer.php b/application/views/templates/FHC-Footer.php
index 70f2f6b3f..c6e4d2a24 100644
--- a/application/views/templates/FHC-Footer.php
+++ b/application/views/templates/FHC-Footer.php
@@ -32,7 +32,7 @@
// From vendor folder
// Axios V0.27
- if ($axios027 === true) generateJSsInclude('vendor/axios/axios/axios.min.js');
+ if ($axios027 === true) generateJSsInclude('vendor/axios/axios/dist/axios.min.js');
// Bootstrap 5 JS
if ($bootstrap5 === true) generateJSsInclude('vendor/twbs/bootstrap5/dist/js/bootstrap.min.js');
@@ -132,6 +132,9 @@
// PhrasesLib JS
if ($phrases != null) generateJSsInclude('public/js/PhrasesLib.js');
+ // RESTClient
+ if ($restclient === true) generateJSsInclude('public/js/RESTClient.js');
+
// TableWidget JS
if ($tablewidget === true) generateJSsInclude('public/js/TableWidget.js');
diff --git a/composer.json b/composer.json
index e5ebd2893..84839bf70 100644
--- a/composer.json
+++ b/composer.json
@@ -43,8 +43,8 @@
"name": "axios/axios",
"version": "0.27.2",
"dist": {
- "url": "https://unpkg.com/axios@0.27.2/dist/axios.min.js",
- "type": "file"
+ "url": "https://github.com/axios/axios/archive/refs/tags/v0.27.2.zip",
+ "type": "zip"
}
}
},
@@ -343,7 +343,7 @@
"afarkas/html5shiv": "3.7.*",
"alvaro-prieto/colresizable": "1.6",
- "axios/axios": "0.27.2",
+ "axios/axios": "0.27.*",
"blackrockdigital/startbootstrap-sb-admin-2": "3.3.*",
"borgar/textile-js": "2.0.4",
diff --git a/public/js/RESTClient.js b/public/js/RESTClient.js
new file mode 100644
index 000000000..eb0ebaa63
--- /dev/null
+++ b/public/js/RESTClient.js
@@ -0,0 +1,225 @@
+/**
+ * FH-Complete
+ *
+ * @package FHC-Helper
+ * @author FHC-Team
+ * @copyright Copyright (c) 2022 fhcomplete.net
+ * @license GPLv3
+ * @link https://fhcomplete.net
+ * @since Version 1.0.0
+ */
+
+//--------------------------------------------------------------------------------------------------------------------
+// Configs
+
+// To see debug messages into the browser console set this parameter as true
+const CORE_REST_CLIENT_DEBUG = false;
+
+// Default timeout (milliseconds)
+const CORE_REST_CLIENT_TIMEOUT = 1000;
+
+//--------------------------------------------------------------------------------------------------------------------
+// Constants
+
+// Success
+const CORE_REST_CLIENT_SUCCESS = 0;
+
+// Properties present in a response
+const CORE_REST_CLIENT_ERROR = "error";
+const CORE_REST_CLIENT_RETVAL = "retval";
+
+// HTTP method parameters
+const CRC_HTTP_GET_METHOD = "get";
+const CRC_HTTP_POST_METHOD = "post";
+
+/**
+ * Definition and initialization of the object CoreRESTClient
+ */
+const CoreRESTClient = {
+ //------------------------------------------------------------------------------------------------------------------
+ // Public methods
+
+ /**
+ * Performs a call using the HTTP GET method
+ * wsParameters is an object
+ * axiosParameters is an object
+ */
+ get: function(wsURL, wsParameters, axiosParameters = null) {
+ return CoreRESTClient._axiosCall(wsURL, wsParameters, CRC_HTTP_GET_METHOD, axiosParameters);
+ },
+
+ /**
+ * Performs a call using the HTTP POST method
+ * wsParameters is an object
+ * axiosParameters is an object
+ */
+ post: function(wsURL, wsParameters, axiosParameters = null) {
+ return CoreRESTClient._axiosCall(wsURL, wsParameters, CRC_HTTP_POST_METHOD, axiosParameters);
+ },
+
+ /**
+ * Checks if the response is a success
+ */
+ isSuccess: function(response) {
+
+ if (typeof response === "object" && response.hasOwnProperty(CORE_REST_CLIENT_ERROR)
+ && response.hasOwnProperty(CORE_REST_CLIENT_RETVAL) && response.error == CORE_REST_CLIENT_SUCCESS)
+ {
+ return true;
+ }
+
+ return false;
+ },
+
+ /**
+ * Checks if the response is an error
+ */
+ isError: function(response) {
+ return !CoreRESTClient.isSuccess(response);
+ },
+
+ /**
+ * Checks if the response has data
+ */
+ hasData: function(response) {
+
+ if (CoreRESTClient.isSuccess(response))
+ {
+ if ((typeof response[CORE_REST_CLIENT_RETVAL] === "object" && Object.keys(response[CORE_REST_CLIENT_RETVAL]).length > 0)
+ || (typeof response[CORE_REST_CLIENT_RETVAL] === "array" && response[CORE_REST_CLIENT_RETVAL].length > 0)
+ || (typeof response[CORE_REST_CLIENT_RETVAL] === "string" && response[CORE_REST_CLIENT_RETVAL].trim() != "")
+ || typeof response[CORE_REST_CLIENT_RETVAL] === "number")
+ {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ /**
+ * Retrives data from response object
+ */
+ getData: function(response) {
+
+ if (CoreRESTClient.hasData(response))
+ {
+ return response[CORE_REST_CLIENT_RETVAL];
+ }
+
+ return null;
+ },
+
+ /**
+ * Retrives error message from response object
+ */
+ getError: function(response) {
+
+ if (typeof response[CORE_REST_CLIENT_RETVAL] === "object"
+ && Object.keys(response[CORE_REST_CLIENT_RETVAL]).length > 0
+ && response.hasOwnProperty(CORE_REST_CLIENT_RETVAL))
+ {
+ return response[CORE_REST_CLIENT_RETVAL];
+ }
+
+ return "Generic error";
+ },
+
+ /**
+ * Retrives code from response object
+ */
+ getErrorCode: function(response) {
+
+ if (typeof response[CORE_REST_CLIENT_RETVAL] === "object" && response.hasOwnProperty(CORE_REST_CLIENT_ERROR))
+ {
+ return response[CORE_REST_CLIENT_ERROR];
+ }
+
+ return 1; // Generic error
+ },
+
+ //------------------------------------------------------------------------------------------------------------------
+ // Private methods
+
+ /**
+ * Generate the router URI using the connection parameters
+ */
+ _generateRouterURI: function(wsURL) {
+ var uri = null;
+
+ // Checks if global JS object FHC_JS_DATA_STORAGE_OBJECT exists
+ if (typeof FHC_JS_DATA_STORAGE_OBJECT !== "undefined")
+ {
+ uri = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + "/" + wsURL;
+ }
+
+ return uri;
+ },
+
+ /**
+ * Method to print debug info after a controller has been called
+ */
+ _printDebug: function(parameters, response, errorThrown) {
+
+ if (CORE_REST_CLIENT_DEBUG === true) // If global const CORE_REST_CLIENT_DEBUG is true, but really true!
+ {
+ // Print info about called controller
+ console.log("Called controller: " + parameters.remoteController);
+ console.log("Call parameters:"); // parameters given to this call
+ console.log(parameters);
+
+ if (response != null) // if there is a response...
+ {
+ console.log("Controller Response:");
+ console.log(response); // ...print it
+ }
+ if (errorThrown != null) // if there is a jQuery error...
+ {
+ console.log("jQuery error:");
+ console.log(errorThrown); // ...print it
+ }
+ console.log("--------------------------------------------------------------------------------------------");
+ }
+ },
+
+ /**
+ * Performs a call to the server were the CI PHP layer is running
+ * - wsURL: alias of the core controller to call
+ * - wsParameters: parameters to give to the called controller
+ * - type: POST or GET HTTP method
+ * - axiosParameters: an object to configure the axios call
+ */
+ _axiosCall: function(wsURL, wsParameters, type, axiosParameters) {
+
+ // Axios config object
+ let axiosCallObj = {
+ method: type,
+ url: CoreRESTClient._generateRouterURI(wsURL),
+ timeout: CORE_REST_CLIENT_TIMEOUT // default time out
+ };
+
+ //
+ if (type == CRC_HTTP_GET_METHOD)
+ {
+ axiosCallObj.params = wsParameters;
+ }
+ else
+ {
+ axiosCallObj.headers = { "Content-Type": "multipart/form-data" };
+ axiosCallObj.data = wsParameters;
+ }
+
+ // Check if axiosParameters is an object
+ if (typeof axiosParameters === "object")
+ {
+ // And then copies the its properties into axiosCallObj
+ for (var prop in axiosParameters) axiosCallObj[prop] = axiosParameters[prop];
+ }
+
+ console.log(axiosCallObj);
+
+ // Perform the ajax call via axios
+ return axios(axiosCallObj);
+ }
+};
+
diff --git a/public/js/components/Fetch.js b/public/js/components/Fetch.js
index a3a11dcfe..7e867e740 100644
--- a/public/js/components/Fetch.js
+++ b/public/js/components/Fetch.js
@@ -1,46 +1,66 @@
export const CoreFetchCmpt = {
- props: ["apifunction"],
- data: function() {
- return {
- loading: false,
- error: null,
- data: []
- };
- },
- template: `
-
-
- Loading ...
-
-
- {{ JSON.stringify(error, null, 4) }}
-
-
- {{ JSON.stringify(data, null, 4) }}
-
-
- `,
- created: function () {
- this.fetchData();
- },
- methods: {
- fetchData: function() {
- var that = this;
-
- this.loading = true;
- this.error = null;
-
- this.apifunction()
- .then(function(response) {
- that.data = response.data;
- that.$emit('datafetched', that.data.data);
- })
- .catch(function(error) {
- that.error = error;
- })
- .finally(function() {
- that.loading = false;
- });
- }
- }
-};
\ No newline at end of file
+ data: function() {
+ return {
+ loading: false,
+ error: false,
+ errorMessage: null
+ };
+ },
+ emits: ['dataFetched'],
+ props: {
+ apiFunction: Function
+ },
+ created: function () {
+ this.fetchData();
+ },
+ methods: {
+ fetchData: function() {
+ // Loader started
+ this.loading = true;
+
+ // Checks if the apifunction is a callable function
+ if (typeof this.apiFunction == "function")
+ {
+ // Call the function stored in apiFunction
+ let apiFunctionResult = this.apiFunction();
+
+ // It is expected that the function returns a Promise
+ if (apiFunctionResult instanceof Promise)
+ {
+ apiFunctionResult.then(this._success).catch(this._error).then(this._finally);
+ }
+ else // otherwise display an error
+ {
+ this._setError("The called apiFunction does not return a Promise");
+ }
+ }
+ else // otherwise display an error
+ {
+ this._setError("Property apiFunction is not a function");
+ }
+ },
+ _setError(errorMessage) {
+ this.loading = false;
+ this.error = true;
+ this.errorMessage = errorMessage;
+ },
+ _success: function(response) {
+ this.$emit('dataFetched', response.data);
+ },
+ _error: function(error) {
+ this._setError(error.message);
+ },
+ _finally: function() {
+ this.loading = false;
+ }
+ },
+ template: `
+
+ Loading...
+
+
+ {{ errorMessage }}
+
+ `
+};
+
diff --git a/public/js/components/Filter.js b/public/js/components/Filter.js
index 9fb3015ec..5c356b5fb 100644
--- a/public/js/components/Filter.js
+++ b/public/js/components/Filter.js
@@ -1,3 +1,7 @@
+import {CoreFetchCmpt} from '../components/Fetch.js';
+
+const CORE_FILTER_CMPT_TIMEOUT = 7000;
+
export const CoreFilterCmpt = {
emits: ['nwNewEntry'],
data() {
@@ -11,9 +15,10 @@ export const CoreFilterCmpt = {
notFilterFields: null
};
},
- created() {
- this._fetchFilterData();
+ components: {
+ CoreFetchCmpt
},
+ created() {},
updated() {
let filterCmptTablesorter = $("#filterTableDataset");
@@ -40,17 +45,22 @@ export const CoreFilterCmpt = {
},
methods: {
saveCustomFilter(el) {
- FHC_AjaxClient.ajaxCallPost(
- "components/Filter/saveCustomFilter",
+
+ CoreRESTClient.post(
+ 'components/Filter/saveCustomFilter',
{
filterUniqueId: this._getCurrentPage(),
filterType: this.filterType,
customFilterName: document.getElementById('customFilterName').value
- },
+ },
{
- successCallback: function(data) {console.log(data)}
+ timeout: CORE_FILTER_CMPT_TIMEOUT
}
- );
+ )
+ .then(function (response) { console.log(response); })
+ .catch(function (error) {
+ console.error(error);
+ });
},
applyFilterFields(el) {
let filterFields = [];
@@ -90,117 +100,171 @@ export const CoreFilterCmpt = {
filterFields.push(filterField);
}
- FHC_AjaxClient.ajaxCallPost(
- "components/Filter/applyFilterFields",
+ CoreRESTClient.post(
+ 'components/Filter/applyFilterFields',
{
filterUniqueId: this._getCurrentPage(),
filterType: this.filterType,
filterFields: filterFields
- },
+ },
{
- successCallback: this._fetchFilterData
+ timeout: CORE_FILTER_CMPT_TIMEOUT
}
- );
+ )
+ .then(this.fetchFilterData)
+ .catch(function (error) {
+ console.error(error);
+ });
},
addFilterField(el) {
- FHC_AjaxClient.ajaxCallPost(
- "components/Filter/addFilterField",
- {
- filterUniqueId: this._getCurrentPage(),
- filterType: this.filterType,
- filterField: el.currentTarget.value
- },
- {
- successCallback: this._fetchFilterData
- }
- );
- },
- addSelectedField(el) {
- FHC_AjaxClient.ajaxCallPost(
- "components/Filter/addSelectedField",
+
+ CoreRESTClient.post(
+ 'components/Filter/addFilterField',
{
filterUniqueId: this._getCurrentPage(),
filterType: this.filterType,
selectedField: el.currentTarget.value
- },
+ },
{
- successCallback: this._fetchFilterData
+ timeout: CORE_FILTER_CMPT_TIMEOUT
}
- );
+ )
+ .then(this.fetchFilterData)
+ .catch(function (error) {
+ console.error(error);
+ });
+ },
+ addSelectedField(el) {
+
+ CoreRESTClient.post(
+ 'components/Filter/addSelectedField',
+ {
+ filterUniqueId: this._getCurrentPage(),
+ filterType: this.filterType,
+ selectedField: el.currentTarget.value
+ },
+ {
+ timeout: CORE_FILTER_CMPT_TIMEOUT
+ }
+ )
+ .then(this.fetchFilterData)
+ .catch(function (error) {
+ console.error(error);
+ });
},
removeSelectedField(el) {
- FHC_AjaxClient.ajaxCallPost(
- "components/Filter/removeSelectedField",
+
+ CoreRESTClient.post(
+ 'components/Filter/removeSelectedField',
{
filterUniqueId: this._getCurrentPage(),
filterType: this.filterType,
selectedField: el.currentTarget.getAttribute('field-to-remove')
- },
+ },
{
- successCallback: this._fetchFilterData
+ timeout: CORE_FILTER_CMPT_TIMEOUT
}
- );
+ )
+ .then(this.fetchFilterData)
+ .catch(function (error) {
+ console.error(error);
+ });
},
removeFilterField(el) {
- FHC_AjaxClient.ajaxCallPost(
- "components/Filter/removeFilterField",
+
+ CoreRESTClient.post(
+ 'components/Filter/removeFilterField',
{
filterUniqueId: this._getCurrentPage(),
filterType: this.filterType,
filterField: el.currentTarget.getAttribute('field-to-remove')
- },
+ },
{
- successCallback: this._fetchFilterData
+ timeout: CORE_FILTER_CMPT_TIMEOUT
}
- );
+ )
+ .then(this.fetchFilterData)
+ .catch(function (error) {
+ console.error(error);
+ });
},
fetchFilterDataById(el) {
- FHC_AjaxClient.ajaxCallGet(
- "components/Filter/getFilter",
+
+ var that = this;
+
+ CoreRESTClient.get(
+ 'components/Filter/getFilter',
{
filterUniqueId: this._getCurrentPage(),
filterType: this.filterType,
filter_id: el.currentTarget.getAttribute("href").substring(1)
- },
+ },
{
- successCallback: this._render
+ timeout: CORE_FILTER_CMPT_TIMEOUT
}
- );
+ )
+ .then(function (response) { that.render(response.data); })
+ .catch(function (error) {
+ console.error(error);
+ });
},
- _fetchFilterData() {
- FHC_AjaxClient.ajaxCallGet(
- "components/Filter/getFilter",
+ fetchFilterData() {
+
+ var that = this;
+
+ CoreRESTClient.get(
+ 'components/Filter/getFilter',
{
filterUniqueId: this._getCurrentPage(),
filterType: this.filterType // props!!
- },
+ },
{
- successCallback: this._render
+ timeout: CORE_FILTER_CMPT_TIMEOUT
+ }
+ )
+ .then(function (response) { that.render(response.data); })
+ .catch(function (error) {
+ console.error(error);
+ });
+ },
+ fetchFilterDataApi() {
+
+ return CoreRESTClient.get(
+ 'components/Filter/getFilter',
+ {
+ filterUniqueId: this._getCurrentPage(),
+ filterType: this.filterType // props!!
+ },
+ {
+ timeout: CORE_FILTER_CMPT_TIMEOUT
}
);
},
_getCurrentPage: function() {
return FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method;
},
- _render(data) {
-
- if (FHC_AjaxClient.hasData(data))
+ render(response) {
+
+ console.log('render');
+
+ if (CoreRESTClient.hasData(response))
{
- this.dataset = FHC_AjaxClient.getData(data).dataset;
- this.fields = FHC_AjaxClient.getData(data).fields;
- this.selectedFields = FHC_AjaxClient.getData(data).selectedFields;
+ let data = CoreRESTClient.getData(response);
+ this.dataset = data.dataset;
+ this.fields = data.fields;
+ this.selectedFields = data.selectedFields;
this.notSelectedFields = this.fields.filter(x => this.selectedFields.indexOf(x) === -1);
this.filterFields = [];
let tmpFilterFields = [];
- for (let i = 0; i < FHC_AjaxClient.getData(data).datasetMetadata.length; i++)
+ for (let i = 0; i < data.datasetMetadata.length; i++)
{
- for (let j = 0; j < FHC_AjaxClient.getData(data).filters.length; j++)
+ for (let j = 0; j < data.filters.length; j++)
{
- if (FHC_AjaxClient.getData(data).datasetMetadata[i].name == FHC_AjaxClient.getData(data).filters[j].name)
+ if (data.datasetMetadata[i].name == data.filters[j].name)
{
- let filter = FHC_AjaxClient.getData(data).filters[j];
- filter.type = FHC_AjaxClient.getData(data).datasetMetadata[i].type;
+ let filter = data.filters[j];
+ filter.type = data.datasetMetadata[i].type;
this.filterFields.push(filter);
tmpFilterFields.push(filter.name);
@@ -210,12 +274,12 @@ export const CoreFilterCmpt = {
}
this.notFilterFields = this.fields.filter(x => tmpFilterFields.indexOf(x) === -1);
- this._setFieldsToDisplay(FHC_AjaxClient.getData(data));
- this._setSideMenu(FHC_AjaxClient.getData(data));
+ this._setFieldsToDisplay(data);
+ this._setSideMenu(data);
}
else
{
- console.error(FHC_AjaxClient.getError(data));
+ console.error(CoreRESTClient.getError(response));
}
},
_setFieldsToDisplay(data) {
@@ -277,6 +341,9 @@ export const CoreFilterCmpt = {
}
},
template: `
+
+
+