Skip to content
Snippets Groups Projects
Verified Commit 11901f35 authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

feat: new feature for transfer the part that has been changed #217

parent 359392c8
No related branches found
No related tags found
No related merge requests found
# Changelog
## [3.70.0] - 2024-06-25
### Add Features
......@@ -9,15 +7,18 @@
- complete change of form control to a derivation of dataset [#216](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/216)
- new dataset feature refreshOnMutation [#215](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/215)
- new comprehensive options display [#213](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/213)
### Bug Fixes
- initialize of loaded html fields [#210](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/210)
- values from the value attribute are now displayed correctly after loading the options. [#212](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/212)
- If a value is specified in the select, it is now also displayed with a label from the options. [#212](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/212)
### Changes
- doc, little bugs and tidy
- test adjustments and minor layout adjustments
### Code Refactoring
- adjustments to the form stylesheets [#214](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/214)
......
......@@ -32,8 +32,6 @@ domReady.then(() => {
return;
}
fieldSet.insertAdjacentHTML('beforeend', html);
// form.refresh();
});
......@@ -41,71 +39,3 @@ domReady.then(() => {
});
/**
* Interne Daten löschen, nicht übertragen
* Änderungen werden global geändert
* diese Werte stehen nach dem speichern nicht mehr zur Verfügung
for (const [key, value] of Object.entries(data.dataset)) {
for (const [k, v] of Object.entries(data.dataset[key])) {
if (k.indexOf(internalDataPrefix) !== -1) {
delete data.dataset[key][k];
};
}
}
//nicht mit den Original daten arbeiten
//da sich so auch die Originaldaten ändern
let currentData = clone(data);
let d = diff(currentData.dataset,lastData.dataset);
/**
* Daten für den nächsten Vergleich speichern
lastData = clone(currentData);
let changedKeys = [];
for (const [key, value] of Object.entries(d)) {
let index = value.path[0]
if(changedKeys.includes(index)===false){
changedKeys.push(index);
}
}
/**
* Daten die sich nicht geändert haben löschen
let updateData = [];
for (const [key, value] of Object.entries(currentData.dataset)) {
if(changedKeys.includes(key)===true){
updateData.push(currentData.dataset[key]);
}
};
/**
* Zeit umformatieren für die Daten die noch
* übertragen werden sollen
for (const [key, value] of Object.entries(updateData)) {
let time = updateData[key]?.scheduler?.time;
if (time !== undefined) {
/**
* Locale Zeit '2024-03-22T11:22:33'
let d = new Date(Date.parse(time));
/**
* UTC Zeit '2024-03-22T10:22:33.000Z'
d = d.toISOString();
updateData[key].scheduler.time = d;
}
}
return updateData;
*/
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>only try to transfer the part that has been changed #217</title>
<script src="./217.mjs" type="module"></script>
</head>
<body>
<h1>only try to transfer the part that has been changed #217</h1>
<p></p>
<ul>
<li><a href="https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/217">Issue #217</a></li>
<li><a href="/">Back to overview</a></li>
</ul>
<main>
<monster-datasource-rest id="ds210"
data-monster-option-read-url="/issue-217.json"
data-monster-option-write-url="/issue-217"
data-monster-option-write-acceptedstatus="400::200"
data-monster-option-features-autoinit="true">
</monster-datasource-rest>
<monster-dataset data-monster-option-index="0"
data-monster-option-datasource-selector="#ds210"
data-monster-option-mapping-data="">
ID:
<div data-monster-replace="path:data.id"></div>
<div data-monster-replace="path:data.name"></div>
</monster-dataset>
<monster-form data-monster-option-datasource-selector="#ds210"
data-monster-option-mapping-data=""
data-monster-option-features-mutationobserver="true"
>
<monster-field-set data-monster-option-labels-title="my title">
<label for="id">field id</label><input id="id" type="number"
data-monster-attributes="value path:data.id"
data-monster-bind="path:data.id">
<label for="field1">field id</label><input id="field1"
data-monster-attributes="value path:data.field1"
data-monster-bind="path:data.field1">
<label for="field2">field id</label><input id="field2"
data-monster-attributes="value path:data.field2"
data-monster-bind="path:data.field2">
<label for="field3">field id</label><input id="field3"
data-monster-attributes="value path:data.field3"
data-monster-bind="path:data.field3">
</monster-field-set>
<monster-field-set data-monster-option-labels-title="">
<monster-datasource-save-button data-monster-option-datasource-selector="#ds210">ok
</monster-datasource-save-button>
</monster-field-set>
</monster-form>
</main>
</body>
</html>
/**
* @file development/issues/open/217.mjs
* @url https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/217
* @description only try to transfer the part that has been changed
* @issue 217
*/
import "../../../source/components/style/property.pcss";
import "../../../source/components/style/color.pcss";
import "../../../source/components/style/normalize.pcss";
import "../../../source/components/style/typography.pcss";
import "../../../source/components/style/form.pcss";
import "../../../source/components/datatable/datasource/rest.mjs";
import "../../../source/components/datatable/save-button.mjs";
import "../../../source/components/form/form.mjs";
import "../../../source/components/form/field-set.mjs";
import "../../../source/components/form/select.mjs";
import "../../../source/components/form/context-help.mjs";
import "../../../source/components/form/context-error.mjs";
import {domReady} from "../../../source/dom/ready.mjs";
domReady.then(() => {
});
const json =
`{
"0": {
"id": 1000,
"field1": "dataset 1, value field 1",
"field2": "dataset 1, value field 2",
"field3": "dataset 1, value field 3"
},
"1": {
"id": 1001,
"field1": "dataset 2, value field 1",
"field2": "dataset 2, value field 2",
"field3": "dataset 2, value field 3"
}
}`;
// check if json is valid
JSON.parse(json)
const json400Error=`[
{
"sys": {
"type": "Error",
"message": "Invalid request"
}
}
]`
// check if json is valid
JSON.parse(json400Error)
const json200Error=`[
{
"sys": {
"type": "Error",
"message": "Invalid request"
}
}
]`
// check if json is valid
JSON.parse(json200Error)
export default [
{
url: '/issue-217.json',
method: 'get',
rawResponse: async (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.statusCode = 200
setTimeout(function() {
res.end(json)
}, 10);
},
},
{
url: '/issue-217',
method: 'post',
rawResponse: async (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.statusCode = 400
setTimeout(function() {
res.end(json400Error)
}, 10);
},
}
];
\ No newline at end of file
......@@ -12,8 +12,10 @@
* SPDX-License-Identifier: AGPL-3.0
*/
import {diff} from "../../../data/diff.mjs";
import {addAttributeToken} from "../../../dom/attributes.mjs";
import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
import {isArray} from "../../../types/is.mjs";
import {Datasource, dataSourceSymbol} from "../datasource.mjs";
import {DatasourceStyleSheet} from "../stylesheet/datasource.mjs";
import {instanceSymbol} from "../../../constants.mjs";
......@@ -302,6 +304,9 @@ class Rest extends Datasource {
removeFilter.call(this);
}
/**
* @returns {Promise<never>|*}
*/
read() {
return this.fetch();
}
......@@ -489,7 +494,8 @@ function initAutoInit() {
}
setTimeout(() => {
this.fetch().catch(() => {});
this.fetch().catch(() => {
});
}, 0);
}
......
......@@ -77,9 +77,6 @@ class SaveButton extends CustomElement {
* @property {Object} classes The classes
* @property {string} classes.bar The bar class
* @property {string} classes.badge The badge class
* @property {object} mapping The mapping
* @property {string} mapping.data The data
* @property {number} mapping.index The index
* @property {Array} ignoreChanges The ignore changes (regex)
* @property {Array} data The data
* @return {Object}
......@@ -105,11 +102,6 @@ class SaveButton extends CustomElement {
changes: "0",
mapping: {
data: "dataset",
index: 0,
},
ignoreChanges: [],
data: {},
......
......@@ -164,13 +164,6 @@ class Form extends DataSet {
}
function initDataSourceHandler() {
if (!this[datasourceLinkedElementSymbol]) {
return;
}
console.log(this[datasourceLinkedElementSymbol]);
this[datasourceLinkedElementSymbol].setOption("write.responseCallback", (response) => {
console.log("response!!!", response);
})
}
......
......@@ -12,14 +12,22 @@
* SPDX-License-Identifier: AGPL-3.0
*/
import { internalSymbol, instanceSymbol } from "../../constants.mjs";
import { isObject } from "../../types/is.mjs";
import {instanceSymbol} from "../../constants.mjs";
import {isArray, isFunction, isObject} from "../../types/is.mjs";
import {Datasource} from "../datasource.mjs";
import {diff} from "../diff.mjs";
import {Pathfinder} from "../pathfinder.mjs";
import {Pipe} from "../pipe.mjs";
export {Server};
/**
* @private
* @type {symbol}
*/
const serverVersionSymbol = Symbol("serverVersion");
/**
* Base class for all server data sources
*
......@@ -48,6 +56,7 @@ class Server extends Datasource {
*/
transformServerPayload(payload) {
payload = doTransform.call(this, "read", payload);
this[serverVersionSymbol] = payload;
const dataPath = this.getOption("read.path");
if (dataPath) {
......@@ -66,6 +75,7 @@ class Server extends Datasource {
*/
prepareServerPayload(payload) {
payload = doTransform.call(this, "write", payload);
payload = doDiff.call(this, payload);
const sheathingObject = this.getOption("write.sheathing.object");
const sheathingPath = this.getOption("write.sheathing.path");
......@@ -80,6 +90,32 @@ class Server extends Datasource {
}
}
/**
*
* @param obj
* @returns {*}
*/
function doDiff(obj) {
if (this[serverVersionSymbol] === null || this[serverVersionSymbol] === undefined) {
return obj;
}
const callback = this.getOption("write.partial.callback");
if (!isFunction(callback)) {
return obj;
}
const results = diff(this[serverVersionSymbol], obj);
if (!results) {
return obj;
}
obj = callback(obj, results);
this[serverVersionSymbol] = obj;
return obj;
}
/**
* @private
* @param {string} type
......@@ -92,6 +128,14 @@ function doTransform(type, obj) {
const pipe = new Pipe(transformation);
const callbacks = this.getOption(`${type}.mapping.callbacks`);
if (isArray(callbacks)) {
for (const callback of callbacks) {
if (typeof callback === "function") {
pipe.setCallback(callback);
}
}
}
if (isObject(callbacks)) {
for (const key in callbacks) {
if (
......
......@@ -13,7 +13,8 @@
*/
import {internalSymbol, instanceSymbol} from "../../../constants.mjs";
import {isObject, isFunction} from "../../../types/is.mjs";
import {isObject, isFunction, isArray} from "../../../types/is.mjs";
import {diff} from "../../diff.mjs";
import {Server} from "../server.mjs";
import {WriteError} from "./restapi/writeerror.mjs";
import {DataFetchError} from "./restapi/data-fetch-error.mjs";
......@@ -30,6 +31,7 @@ const rawDataSymbol = Symbol.for(
"@schukai/monster/data/datasource/server/restapi/rawdata",
);
/**
* The RestAPI is a class that enables a REST API server.
*
......@@ -75,6 +77,8 @@ class RestAPI extends Server {
* @property {Monster.Data.Datasource~exampleCallback[]} write.mapping.callback with the help of the callback, the structures can be adjusted before writing.
* @property {Object} write.report
* @property {String} write.report.path Path to validations
* @property {Object} write.partial
* @property {Function} write.partial.callback Callback function to be executed after the request has been completed. (obj, diffResult) => obj
* @property {Object} write.sheathing
* @property {Object} write.sheathing.object Object to be wrapped
* @property {string} write.sheathing.path Path to the data
......@@ -107,6 +111,10 @@ class RestAPI extends Server {
report: {
path: undefined,
},
partial: {
callback: null,
}
},
read: {
init: {
......@@ -135,10 +143,11 @@ class RestAPI extends Server {
if (!init["method"]) init["method"] = "GET";
let callback = this.getOption("read.responseCallback");
if (!callback)
if (!callback) {
callback = (obj) => {
this.set(this.transformServerPayload.call(this, obj));
};
}
return fetchData.call(this, init, "read", callback);
}
......
......@@ -6,6 +6,43 @@ import {Queue} from "../../../source/types/queue.mjs";
describe('Diff', function () {
describe('test to datasets', function () {
var obj1, obj2;
beforeEach(() => {
obj1 = [
{
"id": 1,
"name": "test"
},
{
"id": 2,
"name": "test2"
}
]
obj2 = [
{
"id": 1,
"name": "test"
},
{
"id": "3",
"name": "test2"
}
]
});
it('should return the difference between two datasets', function () {
let d = diff(obj1, obj2);
expect(JSON.stringify(d)).is.equal('[{"operator":"update","path":["1","id"],"first":{"value":2,"type":"number"},"second":{"value":"3","type":"string"}}]');
});
})
describe('Diff special cases', function () {
var obj1, obj2;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment