Commit c8c2474f authored by Sven Franck's avatar Sven Franck

offline work-in-progress commit

parent 2a7c34a3
......@@ -52,7 +52,7 @@
{"field": "total_price", "show": true, "persist": true, "sort":false},
{"field": "price_currency", "show": "true", "priority": 4, "merge": "total_price"},
{"field": "translated_simulation_state_title", "show":"true", "priority": 5},
{"custom": true, "show": true, "persist": true, "sort": false, "action_list": [{"class_list": "action translate", "action": "download", "icon":"file-alt", "text": "Download", "text_i18n":"portable_type_dict.invoice_dict.download"}]}
{"custom": true, "show": true, "persist": true, "sort": false, "action_list": [{"class_list": "action translate", "action": "get", "icon":"file-alt", "text": "Download", "text_i18n":"portable_type_dict.invoice_dict.download"}]}
]
}
],
......
......@@ -769,8 +769,8 @@
map.actions = {
/**
* Generate a new object
* @method install
* POST an object
* @method new
* @param {object} obj Action Object
**/
"new": function (obj) {
......@@ -778,14 +778,23 @@
},
/**
* Update an object
* @method submit
* PUT an object
* @method update
* @param {object} obj Action Object
**/
"update": function (obj) {
storage.write(obj);
},
/**
* GET an object
* @method get
* @param {object} obj Action Object
**/
"get": function (obj) {
storage.fetch(obj);
},
/**
* Create an installation = new service object
* @method install
......@@ -1095,31 +1104,6 @@
.fail(util.error);
},
/**
* Download a document as pdf
* @method download
* @param {string} type
* @param {string} portal type
* @param {string} identifier
**/
"download": function (obj) {
var store;
store = app.storage_dict;
util.loader("", "status_dict.downloading");
store.items.get({"_id": window.decodeURIComponent(obj.element.href.split("/").pop())},{"_view": "web_view"})
.then(function(response) {
util.loader("", "status_dict.rendering");
window.location.href = util.parse(response).data._links.slapos_jump.href;
})
.fail(function (error){
util.error(error);
util.loader("", "status_dict.failed", "ban-circle");
});
},
// ==============================================================
/**
......@@ -1644,7 +1628,6 @@
// loop data (!)
for (k = 0; k < items.length; k += 1) {
item = items[k].doc;
if (item === undefined) {
util.error("mapTableRows: Missing include_docs/data-set");
......@@ -1659,7 +1642,6 @@
// set id so it can be retrieved for radio/checkbox
// TODO: remove this! don't set on every cell...
cell.id = item.id || items[k]["_id"];
if (props.link) {
cell.href = item[props.link_source] ||
("#" + core + "/" + window.encodeURIComponent(item[props.link_identifier || "id"]));
......@@ -1671,10 +1653,10 @@
// action menu
if (props.action_menu && cell.action_list) {
// HACK to add correct HREF and reference
if (item._relative_url) {
if (item._id) {
for (o = 0; o < cell.action_list.length; o += 1) {
cell.action_list[o].reference = spec.set_id;
cell.action_list[o].href = window.encodeURIComponent(item._relative_url);
cell.action_list[o].href = window.encodeURIComponent(item._id);
}
}
cell.action_list = cell.action_list || [];
......@@ -5231,6 +5213,111 @@
// generate storage object
storage = {};
/*
if (store.property_dict.storage) {
// access storage
fetch = reply.pass.value || reply.pass.state.query.force;
return store.items.get({"_id": window.decodeURIComponent(fetch)})
.then(function(answer) {
query = util.parse(answer).data._links.slapos_jump._query;
if (pass.config.initial_query === undefined) {
pass.config.initial_query = {};
}
pass.config.initial_query.query = query;
pass.config.initial_query.skip_type = true;
pass.preserve_lookup = reply.pass.value;
// set a flag to now run allDocs
pass.force_allDocs = true;
// pass hacked query back into chain
if (reply.response) {
return {
"response": util.parse(reply.response),
"pass": pass
};
}
return {
"pass": pass
}
}).fail(util.error);
}
return (reply);
*/
/**
* Fetch data from storage = GET or ALLDOCS
* @method fetch
* @param {object} obj Action object
*/
// TODO: only use on lookup architecture pass.x or pass.state.x
// TODO: this means state needs to have url_pointer set earilier, so
// there is no need to look it up in oass.config.property_dict...
storage.fetch = function (obj) {
var pass, query, method, map, config, answer, lookup, pointer, action,
quirk;
pass = obj.pass;
quirk = obj.state || pass.config;
lookup = obj.state || quirk.property_dict || {};
query = obj.query || lookup.query || {};
pointer = (lookup["url_pointer"] || {}).jump;
// TODO: action handling, should be a form submit not set on element!
action = ((obj.element || {}).href || "").split("/").pop();
query._id = query._id || window.decodeURIComponent(action);
if (action) {
pointer = undefined;
query = {"_id": query._id}
}
switch (true) {
case ((query.select_list || []).length > 0 && !query.include_docs):
map = "values";
break;
case (!!query._id):
map = "single_item";
method = "get";
config = {
"_view": quirk.view
};
break;
}
// TODO: remove this - pass custom query to storage
if (pointer && !config) {
config = {
"_jump": pointer
};
}
return RSVP.resolve(
app.storage_dict.items[method || "allDocs"](query, config)
).then(function (response) {
if (response.status === 200) {
// TODO: actions should have their own callback set on state!
if (action) {
util.loader("", "status_dict.rendering");
window.location.href = response.data._links.slapos_jump.href;
}
answer = storage.mapResponse(response, map);
if (app.storage_dict.property_dict.force_sync) {
//storage.sync(mapped, parcel.storage);
}
}
return {
"response": answer || response,
"pass": pass
};
}).fail(util.error);
},
/**
* Write to storage = POST or PUT
* @method write
......@@ -5244,23 +5331,23 @@
valid = storage.validate(obj);
data = storage.parseForm(valid, prefix, true);
// post or put
if (form.identifier) {
// this must be a PUT, set id, method and view
data._id = form.identifier.value;
method = "put";
config = {
"_view": obj.state.view
};
data._id = form.identifier.value;
} else {
// POSTING, set action set in JSON config
config = {
"action": obj.state.url_pointer[obj.element.getAttribute("data-action")]
};
}
RSVP.resolve(
app.storage_dict.items[method || "post"](data, config)
)
RSVP.resolve(app.storage_dict.items[method || "post"](data, config))
.then(function (response) {
// TODO: if this is strictly a storage operation, do this elsewhere!
if (response.status === 201) {
util.loader("", "status_dict.saved", "check");
if (obj.state.callback) {
......@@ -5411,43 +5498,45 @@
storage.mapResponse = function (response, convert) {
var answer, i, record, key, data, pushit, value_dict;
answer = {"data": {"total_rows": null, "rows": []}};
pushit = function (obj, record) {
var new_record = {
"id": record.id,
"key": record.id,
"value": {},
"doc": obj
if (convert) {
answer = {"data": {"total_rows": null, "rows": []}};
pushit = function (obj, record) {
var new_record = {
"id": record.id,
"key": record.id,
"value": {},
"doc": obj
};
if (record._missing) {
new_record._missing = true;
}
if (record._conflict_list) {
new_record._conflict_list = record._conflict_list;
}
return new_record;
};
if (record._missing) {
new_record._missing = true;
}
if (record._conflict_list) {
new_record._conflict_list = record._conflict_list;
}
return new_record;
};
if (convert === "single_item") {
answer.data.total_rows = 1;
answer.data.rows.push(pushit(response.data, response));
} else {
answer.data.total_rows = response.data.total_rows;
for (i = 0; i < response.data.total_rows; i += 1) {
data = {};
record = response.data.rows[i];
value_dict = record.value;
for (key in value_dict) {
if (value_dict.hasOwnProperty(key)) {
data[key] = value_dict[key];
if (convert === "single_item") {
answer.data.total_rows = 1;
answer.data.rows.push(pushit(response.data, response));
} else {
answer.data.total_rows = response.data.total_rows;
for (i = 0; i < response.data.total_rows; i += 1) {
data = {};
record = response.data.rows[i];
value_dict = record.value;
for (key in value_dict) {
if (value_dict.hasOwnProperty(key)) {
data[key] = value_dict[key];
}
}
// TODO: verfiy this is valid!
data["_id"] = record.id;
answer.data.rows.push(pushit(data, record));
}
// TODO: verfiy this is valid!
data["_id"] = record.id;
answer.data.rows.push(pushit(data, record));
}
}
return answer;
return answer || response;
};
/**
......@@ -5746,7 +5835,7 @@
// );
}
return app.fetchData({
return storage.fetch({
"storage": "items",
"query": answer.query,
"pass": {"profile": answer.profile}
......@@ -6815,7 +6904,7 @@
* @param {object} reply Response from previous promise and pass-params
* @return {object} response object/promise
*/
app.fetchDataQuery = function (reply) {
storage.fetchQuery = function (reply) {
var parsed, pass = reply.pass, key, value, force_fields;
force_fields = app.storage_dict.property_dict.force_field_definitions;
......@@ -6864,7 +6953,7 @@
// get an item?
if (pass.mode !== "new" || pass.config.initial_query !== undefined) {
return app.fetchData({
return storage.fetch({
"storage": "items",
"query": pass.state.query,
"pass": pass
......@@ -6882,7 +6971,7 @@
* @param {object} reply Response from previous promise and pass-params
* @return {object} response object/promise
*/
app.fetchDataTotal = function (reply) {
storage.fetchTotal = function (reply) {
var pass = reply.pass, last;
if (pass.skip === undefined) {
......@@ -6932,24 +7021,27 @@
}
}
if (pass.skip === undefined &&
(pass.no_auth || ((pass.auth && pass.active_login) ||
(pass.mode === "new" || pass.purge))) &&
(pass.state && pass.state.query._id === undefined)
) {
// get ALL RECORDS matching query
if (pass.config.initial_query) {
// make sure limit is reset from any sample loading [0,1]
pass.state.query.limit = [];
if (!app.storage_dict.property_dict.skip_total_records) {
if (pass.skip === undefined &&
(pass.no_auth || ((pass.auth && pass.active_login) ||
(pass.mode === "new" || pass.purge))) &&
(pass.state && pass.state.query._id === undefined)
) {
// store the complete initial query, not only the "query"
pass.state.initial_query = pass.config.initial_query;
return app.fetchData({
"pass": pass,
"storage": "items",
"query": pass.state.query
});
// get ALL RECORDS matching query
if (pass.config.initial_query) {
// make sure limit is reset from any sample loading [0,1]
pass.state.query.limit = [];
// store the complete initial query, not only the "query"
pass.state.initial_query = pass.config.initial_query;
return storage.fetch({
"pass": pass,
"storage": "items",
"query": pass.state.query
});
}
}
}
return {
......@@ -7094,7 +7186,7 @@
* @param {object} reply Response from previous promise and pass-params
* @return {object} response object/promise
*/
app.fetchDataSample = function (reply) {
storage.fetchSample = function (reply) {
var pass = reply.pass;
if (reply.response) {
......@@ -7134,7 +7226,7 @@
// try to get 1 record for this portal type
if ((pass.create !== false || pass.purge) && pass.config.initial_query &&
(pass.no_auth || (pass.auth && pass.active_login))) {
return app.fetchData({
return storage.fetch({
"storage": "items",
"query": app.generateQueryObject({"limit": [0, 1]}, pass.type),
"pass": pass
......@@ -7291,8 +7383,8 @@
.then(app.checkAuth)
.then(app.fetchFields)
.then(app.store)
.then(app.fetchDataTotal)
.then(app.fetchDataQuery)
.then(storage.fetchTotal)
.then(storage.fetchQuery)
.then(app.makeContent)
.fail(util.error);
......@@ -7368,67 +7460,67 @@
);
};
/**
* Try fetching data from JIO. Fallback to loading fake data until accessible
* @method fetchData
* @param {object} parcel Storage, query options and pass to return
* @return {object} promise object/pass
*/
app.fetchData = function (parcel) {
var method, convert, select_list, hacked_view, pass, skip, query, mapped;
pass = parcel.pass;
query = parcel.query;
skip = query && query.limit && query.limit.length === 0 &&
app.storage_dict.property_dict.skip_total_records;
// return here, if skipping total query
if (skip) {
return {
"pass": parcel.pass
};
}
select_list = parcel.query && parcel.query.select_list && parcel.query.select_list.length;
// single item query GET
if (parcel.query._id) {
// TODO: don't set if don't need...
delete parcel.query.limit;
hacked_view = {"_view": parcel.pass.config.view}
method = "get";
convert = "single_item";
}
// query that will return value {} object vs. doc
if (select_list && parcel.query.include_docs === undefined) {
convert = "values";
}
return app.storage_dict[parcel.storage][method || "allDocs"](parcel.query, hacked_view)
.then(function (response) {
// TODO: best way?
if (convert !== undefined && response.status === 200) {
mapped = storage.mapResponse(response, convert);
// force sync
if (app.storage_dict.property_dict.force_sync) {
//storage.sync(mapped, parcel.storage);
}
return {
"response": mapped,
"pass": parcel.pass
};
}
return {
"response": response,
"pass": parcel.pass
};
});
};
// /**
// * Try fetching data from JIO. Fallback to loading fake data until accessible
// * @method fetchData
// * @param {object} parcel Storage, query options and pass to return
// * @return {object} promise object/pass
// */
// storage.fetch = function (parcel) {
// var method, convert, select_list, hacked_view, pass, skip, query, mapped;
//
// pass = parcel.pass;
// query = parcel.query;
// skip = query && query.limit && query.limit.length === 0 &&
// app.storage_dict.property_dict.skip_total_records;
//
//
// // return here, if skipping total query
// if (skip) {
// return {
// "pass": parcel.pass
// };
// }
//
// select_list = parcel.query && parcel.query.select_list && parcel.query.select_list.length;
//
// // single item query GET
// if (parcel.query._id) {
// // TODO: don't set if don't need...
// delete parcel.query.limit;
// hacked_view = {"_view": parcel.pass.config.view}
// method = "get";
// convert = "single_item";
// }
//
// // query that will return value {} object vs. doc
// if (select_list && parcel.query.include_docs === undefined) {
// convert = "values";
// }
//
// return app.storage_dict[parcel.storage][method || "allDocs"](parcel.query, hacked_view)
// .then(function (response) {
//
// // TODO: best way?
// if (convert !== undefined && response.status === 200) {
// mapped = storage.mapResponse(response, convert);
//
// // force sync
// if (app.storage_dict.property_dict.force_sync) {
// //storage.sync(mapped, parcel.storage);
// }
//
// return {
// "response": mapped,
// "pass": parcel.pass
// };
// }
// return {
// "response": response,
// "pass": parcel.pass
// };
// });
// };
/**
* Load files from disk
......
......@@ -23,11 +23,10 @@
this._url = spec.url;
}
ERP5Storage.prototype._getPrivates = function (site_hal, param, options) {
ERP5Storage.prototype._getFile = function (command, site_hal, param, options) {
var fetch, item = (param || {})._id || (site_hal._links.me || {}).href;
if (!item) {
return command.error(401);
command.error(401);
}
fetch = new URI(item);
return this._getSiteDocument(
......@@ -38,7 +37,6 @@
ERP5Storage.prototype._getSiteDocument = function (traverse, expando) {
var url = UriTemplate.parse(traverse || "").expand(expando || {});
console.log(url);
return jIO.util.ajax({
"type": "GET",
"url": url || this._url,
......@@ -46,29 +44,24 @@
"withCredentials": true
}
}).then(function (response) {
var result = JSON.parse(response.target.responseText);
// result._id = param._id;
return result;
return JSON.parse(response.target.responseText);
});
};
ERP5Storage.prototype._get = function (param, options) {
ERP5Storage.prototype._get = function (command, param, options) {
var that = this;
return that._getSiteDocument()
.then(function (site_hal) {
return that._getPrivates(site_hal, param, options);
return that._getFile(command, site_hal, param, options);
})
.then(function (response) {
console.log("GET, response")
console.log(response)
var result = JSON.parse(response.target.responseText);
result._id = param._id;
return result;
response._id = param._id;
return response;
});
};
ERP5Storage.prototype.get = function (command, param, options) {
this._get(param, options)
this._get(command, param, options)
.then(function (response) {
command.success({"data": response});
})
......@@ -87,7 +80,7 @@
var that = this;
return that._getSiteDocument()
.then(function (site_hal) {
return that._getPrivates(site_hal, undefined, options);
return that._getFile(command, site_hal, undefined, options);
})
.then(function(opts) {
var key, custom_action = opts._actions[options.action],
......@@ -164,28 +157,39 @@
"Unable to call put"
);
});
};
ERP5Storage.prototype.allDocs = function (command, param, options) {
var that = this, search_pointer;
return this._getSiteDocument()
.then(function (site_hal) {
return jIO.util.ajax({
"type": "GET",
"url": UriTemplate.parse(site_hal._links.raw_search.href)
.expand({
query: options.query,
// XXX Force erp5 to return embedded document
select_list: options.select_list || ["title", "reference"],
limit: options.limit
}),
"xhrFields": {
withCredentials: true
}
});
search_pointer = site_hal._links.raw_search.href;
return that._getFile(command, site_hal, undefined, options);
})
.then(function (response) {
return JSON.parse(response.target.responseText);
.then(function (opts) {
var i, len, jump_list, jump;
// HACK: add ERP5 custom jump
if (param._jump && options.query) {
jump_list = opts._links["slapos_jump" || []];
len = jump_list.length;
for (i = 0; i < len; i += 1) {
jump = jump_list[i];
if (jump.name === param._jump) {
options.query = jump._query;
}
}
}
return that._getSiteDocument(
search_pointer,
{
"query": options.query,
// XXX Force erp5 to return embedded document
"select_list": options.select_list || ["title", "reference"],
"limit": options.limit
}
);
})
.then(function (catalog_json) {
var data = catalog_json._embedded.contents,
......
......@@ -251,7 +251,6 @@
var length = promise_list.length;
promise_list = promise_list.slice();
return new Promise(function (resolve, reject, notify) {
var index, trace, conflict_list, count, error_count, tag, doc;
......@@ -344,19 +343,20 @@
sequence([
function () {
// master storage
if (master !== undefined) {
return last(priority_list, master);
}
return {};
},
function (response) {
// slave storages
var method, subindex = 0;
// this is the id issued by the master storage
if (response.id) {
metadata._id = response.id;
method = "put";
} else {
// TODO: error/offline handling
// TODO: master 404/offline handling
}
for (index = 0; index < length; index += 1) {
......@@ -454,7 +454,7 @@
var promise_list = [], index, length = this._storage_list.length;
for (index = 0; index < length; index += 1) {
promise_list[index] =
success(command.storage(this._storage_list[index]).allDocs(option));
success(command.storage(this._storage_list[index]).allDocs(option, param));
}
sequence([function () {
......@@ -463,48 +463,49 @@
var i, j, k, l, record, reply, rows, count, total, base, test, must_add,
len = answers.length;
// loop storage response
// NOTE: every storage may return different records!
for (i = 0; i < len; i += 1) {
reply = answers[i];
total = reply.data.total_rows;
// loop records returned in response
for (j = 0; j < total; j += 1) {
record = reply.data.rows[j];
must_add = undefined;
if (rows === undefined) {
rows = [record];
} else {
count = rows.length;
// loop records already in rows object
for (k = 0; k < count; k += 1) {
base = rows[k];
test = checksum(cleanClone(base));
// record exists, test for coherence
if (base.id === record.id) {
must_add = undefined;
if (test !== checksum(record)) {
if (!base._conflict_list) {
base._conflict_list = [base];
if (reply.result === "success") {
total = reply.data.total_rows;
// loop records returned in response
for (j = 0; j < total; j += 1) {
record = reply.data.rows[j];
must_add = undefined;
if (rows === undefined) {
rows = [record];
} else {
count = rows.length;
// loop records already in rows object
for (k = 0; k < count; k += 1) {
base = rows[k];
test = checksum(cleanClone(base));
// record exists, test for coherence
if (base.id === record.id) {
must_add = undefined;
if (test !== checksum(record)) {
if (!base._conflict_list) {
base._conflict_list = [base];
}
base._conflict_list.push(record);
}
base._conflict_list.push(record);
// record does not exists, must add
} else {
must_add = true;
}
// record does not exists, must add
} else {
must_add = true;
}
}
// add missing records
if (must_add) {
// if on 2+ iteration, this means a 404 on previous storages
if (i > 0) {
record._missing = true;
// add missing records
if (must_add) {
// if on 2+ iteration, this means a 404 on previous storages
if (i > 0) {
record._missing = true;
}
rows.push(record);
}
rows.push(record);
}
}
}
......@@ -517,7 +518,6 @@
rows[l]._missing = true;
}
}
return {"data": {"total_rows": (rows || []).length, "rows": rows || []}};
}, [command.success, command.error]]);
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment