Commit 59a9956a authored by Cédric Le Ninivin's avatar Cédric Le Ninivin Committed by Cédric Le Ninivin

erp5_api_style: Add Gadget to interact with API

erp5_api_style: Add Page to display all API Actions

erp5_api_style: fix http method on json page and add cancel url

erp5_api_style: Fix reenable button after form submit with invalid data

erp5_api_style: Fix Get and provide default get Schema

erp5_api_style: JSON Form gadget now render response
parent 5a6ebec6
<!DOCTYPE html>
<html>
<head>
<!--
data-i18n=Workflows
data-i18n=Actions
data-i18n=Clone
data-i18n=Delete
-->
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<title>ERP5 Page Action</title>
<link rel="http://www.renderjs.org/rel/interface" href="interface_page.html">
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script>
<script src="jiodev.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_global.js" type="text/javascript"></script>
<script src="gadget_erp5_global.js" type="text/javascript"></script>
<script src="gadget_erp5_page_jio_api_action.js" type="text/javascript"></script>
</head>
<body>
</body>
</html>
\ No newline at end of file
/*global window, rJS, RSVP, domsugar, ensureArray, jIO */
/*jslint nomen: true, indent: 2, maxerr: 3 */
(function (window, rJS, RSVP, domsugar, ensureArray, jIO) {
"use strict";
function generateSection(title, icon, view_list) {
var i,
dom_list = [];
for (i = 0; i < view_list.length; i += 1) {
dom_list.push(domsugar('li', [domsugar('a', {
href: view_list[i].link,
text: view_list[i].title
})]));
}
return domsugar(null, [
domsugar('section', {class: 'ui-content-header-plain'}, [
domsugar('h3', [
domsugar('span', {class: 'ui-icon ui-icon-' + icon, html: '&nbsp;'}),
title
])
]),
domsugar('ul', {class: 'document-listview'}, dom_list)
]);
}
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod("getUrlForList", "getUrlForList")
.declareAcquiredMethod("getTranslationList", "getTranslationList")
.declareAcquiredMethod("updateHeader", "updateHeader")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
/** Render only transforms its arguments and passes them to mutex-protected onStateChange
options:
jio_key: {string} currently viewed document (e.g. foo/1)
page: {string} selected page (always "tab" for page_tab)
view: {string} always "view"
selection, history, selection_index
*/
.declareMethod("render", function (options) {
var gadget = this,
action_json_url,
group_list;
action_json_url = rJS.getAbsoluteURL(
"api/jIOWebSection_getAPIJSONHyperSchema",
gadget.__path
)
// Get the whole view as attachment because actions can change based on
// what view we are at. If no view available than fallback to "links".
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
type: "GET",
url: action_json_url,
});
})
.push(function (evt) {
return JSON.parse(evt.target.response);
})
.push(function (api_action_list) {
var get_action_array = [],
put_action_array = [],
post_action_array = [],
allDocs_action_array = [],
jio_type;
for (let i = 0; i < api_action_list.links.length; i++) {
switch (api_action_list.links[i].jio_type) {
case 'get':
get_action_array.push(api_action_list.links[i]);
break;
case 'put':
put_action_array.push(api_action_list.links[i]);
break;
case 'allDocs':
allDocs_action_array.push(api_action_list.links[i]);
break;
case 'post':
post_action_array.push(api_action_list.links[i]);
break;
default:
throw "Unexpected jio type"
}
}
var i,
j,
url_for_kw_list = [];
group_list = [
// Action list, editable, icon
ensureArray(post_action_array), undefined, 'plus',
ensureArray(allDocs_action_array), undefined, 'search',
ensureArray(put_action_array), true, 'pencil',
ensureArray(get_action_array), undefined, 'eye'];
for (i = 0; i < group_list.length; i += 3) {
for (j = 0; j < group_list[i].length; j += 1) {
url_for_kw_list.push({command: 'display_with_history_and_cancel', options: {
page: "json_form_schema_api",
api_url: api_action_list.base + group_list[i][j].href,
schema_url: group_list[i][j].targetSchema
}});
}
}
return RSVP.hash({
url_list: gadget.getUrlForList(url_for_kw_list),
translation_list: gadget.getTranslationList(['Create', 'Search', 'Update', 'View']),
page_title: "API Action List"
});
})
.push(function (result_dict) {
var i,
j,
k = 0,
dom_list = [],
link_list;
for (i = 0; i < group_list.length; i += 3) {
link_list = [];
for (j = 0; j < group_list[i].length; j += 1) {
link_list.push({
title: group_list[i][j].title,
link: result_dict.url_list[k]
});
k += 1;
}
dom_list.push(
generateSection(result_dict.translation_list[i / 3], group_list[i + 2], link_list)
);
}
domsugar(gadget.element, dom_list);
return gadget.updateHeader({
page_title: result_dict.page_title
});
});
})
.declareMethod("triggerSubmit", function () {
return;
});
}(window, rJS, RSVP, domsugar, ensureArray, jIO));
<!DOCTYPE html>
<html>
<head>
<!--
data-i18n=Workflows
data-i18n=Actions
data-i18n=Clone
data-i18n=Delete
-->
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<title>ERP5 Page Action</title>
<link rel="http://www.renderjs.org/rel/interface" href="interface_page.html">
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
<script src="renderjs.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script>
<script src="jiodev.js" type="text/javascript"></script>
<!-- custom script -->
<script src="gadget_global.js" type="text/javascript"></script>
<script src="gadget_erp5_global.js" type="text/javascript"></script>
<script src="gadget_erp5_page_json_form_schema_api.js" type="text/javascript"></script>
</head>
<body>
<div class="form_container"></div>
<div class="dialog_button_container"></div>
<div class="data-response ui-screen-hidden">
<br/>
<h2>Response:</h2>
<br/>
<p><code><pre></pre></code></p>
</div>
</body>
</html>
\ No newline at end of file
/*global window, rJS, RSVP, domsugar, console*/
/*jslint nomen: true, indent: 2, maxerr: 3 */
(function (window, rJS, RSVP, domsugar, jIO) {
"use strict";
function submitDialog(gadget) {
var form_gadget,
button_container =
gadget.element.querySelector('.dialog_button_container'),
submit_input = button_container.querySelector('input');
gadget.element.querySelector('.data-response')
.classList.add("ui-screen-hidden");
if (submit_input !== null) {
submit_input.disabled = true;
}
function enableButton() {
if (submit_input !== null) {
submit_input.disabled = false;
}
}
return gadget.notifySubmitting()
.push(function () {
return gadget.getDeclaredGadget("form_schema");
})
.push(function (result) {
form_gadget = result;
return form_gadget.checkValidity()
.push(function (is_valid) {
if (!is_valid) {
enableButton();
return gadget.notifySubmitted({
"message": "Data is not Valid, please make sure no error is left.",
"status": "failed"
});
}
return form_gadget.getContent()
.push(function (content_dict) {
var json_data = content_dict.my_key,
status,
message;
console.log(json_data);
return sendContent(gadget, json_data)
.push(function (response) {
enableButton();
if (response.status >= 400) {
status = "fail";
message = JSON.parse(response.response).message;
return;
} else {
status = "success";
message = "Success";
return renderAPIResponse(
gadget, response.response
);
}
})
.push(function () {
return gadget.notifySubmitted({
"message": message,
"status": status
});
});
});
});
}, function (error) {
enableButton();
throw error;
});
}
function sendContent(gadget, data) {
var url = gadget.state.api_url,
http_method;
// XXX CLN Hakish
//if (url.endsWith("/get/")) {
// http_method = "GET";
//} else {
http_method = "POST";
//}
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
type: http_method,
url: url,
data: data
});
})
.push(function (evt) {
return evt.target;
}, function (evt) {
if (evt.target.status === 400) {
return evt.target;
}
throw evt;
});
}
function renderAPIResponse(gadget, data) {
var element = gadget.element.querySelector('.data-response'),
queue,
response_gadget,
data_schema,
parsed_data;
parsed_data = JSON.parse(data);
data_schema = parsed_data.$schema;
if (data_schema === undefined) {
domsugar(
gadget.element.querySelector('.data-response'),
[domsugar("p", [domsugar("code", [domsugar("pre", [data])])])]
);
gadget.state.response = false;
gadget.element.querySelector('.data-response')
.classList.remove("ui-screen-hidden");
return;
}
if ((!gadget.state.response)) {
queue = gadget.declareGadget(
rJS.getAbsoluteURL(
"react-jsonschema-form-gadget.html",
gadget.__path
),
{scope: "response_form"}
);
} else {
queue = gadget.getDeclaredGadget("response_form");
}
return queue
.push(function (result) {
response_gadget = result;
return response_gadget.render({
value: data,
key: "my_key",
schema: data_schema,
readonly: true
});
})
.push(function () {
if ((!gadget.state.response)) {
return response_gadget.getElement()
.push(function (fragment) {
// Clear first to DOM, append after to reduce flickering/manip
while (element.firstChild) {
element.removeChild(element.firstChild);
}
element.appendChild(fragment);
gadget.state.response = true;
gadget.element.querySelector('.data-response')
.classList.remove("ui-screen-hidden");
});
}
gadget.element.querySelector('.data-response')
.classList.remove("ui-screen-hidden");
});
}
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.allowPublicAcquisition('notifySubmit', function notifySubmit() {
return this.triggerSubmit();
})
.declareAcquiredMethod("notifySubmitting", "notifySubmitting")
.declareAcquiredMethod("notifySubmitted", "notifySubmitted")
.declareAcquiredMethod("getUrlFor", "getUrlFor")
.declareAcquiredMethod("getUrlForList", "getUrlForList")
.declareAcquiredMethod("updateHeader", "updateHeader")
/////////////////////////////////////////////////////////////////
// declared methods
/////////////////////////////////////////////////////////////////
/** Render only transforms its arguments and passes them to mutex-protected onStateChange
options:
jio_key: {string} currently viewed document (e.g. foo/1)
page: {string} selected page (always "tab" for page_tab)
view: {string} always "view"
selection, history, selection_index
*/
.declareMethod("render", function (options) {
return this.changeState({
schema_url: options.schema_url,
api_url: options.api_url,
response: false
});
})
.onStateChange(function (modification_dict) {
var gadget = this,
options = gadget.state.gadget,
queue,
json_schema_gadget;
if ((!gadget.state.is_refresh)) {
queue = gadget.declareGadget(
rJS.getAbsoluteURL(
"react-jsonschema-form-gadget.html",
gadget.__path
),
{scope: "form_schema"}
);
} else {
queue = gadget.getDeclaredGadget("form_schema");
}
return queue
.push(function (result) {
json_schema_gadget = result;
if (gadget.state.is_refresh) {
// Delete the previous form content when refreshing
// to prevent loosing user modification
delete gadget.state.options.form_content;
}
return json_schema_gadget.render({
value: "{}",
key: "my_key",
schema: gadget.state.schema_url
});
})
.push(function () {
if (true || (!gadget.state.is_refresh)) {
return json_schema_gadget.getElement()
.push(function (fragment) {
var element = gadget.element
.querySelector('.form_container');
// Clear first to DOM, append after to reduce flickering/manip
while (element.firstChild) {
element.removeChild(element.firstChild);
}
element.appendChild(fragment);
});
}
})
.push(function () {
var dom_list = [],
response_display = gadget.element
.querySelector('.data-response');
dom_list.push(
domsugar('input', {name: 'action_confirm',
class: 'dialogconfirm',
type: 'submit',
value: "Send"})
);
domsugar(gadget.element
.querySelector('.dialog_button_container'),
dom_list);
response_display.classList.add("ui-screen-hidden");
return gadget.getUrlFor({command: 'display', options: {
page: "jio_api_action"
}});
})
.push(function (return_url) {
var update_kw = {
page_title: "Send To API"
};
if (return_url !== undefined) {
update_kw.back_url = return_url;
}
return gadget.updateHeader(update_kw);
});
})
.onEvent('click', function click(evt) {
if (evt.target.name === "action_confirm") {
evt.preventDefault();
return submitDialog(this);
}
}, false, false)
.onEvent('submit', function submit() {
return submitDialog(this);
});
}(window, rJS, RSVP, domsugar, jIO));
web_page_module/api-style_alldocs-response-schema.json
\ No newline at end of file
web_page_module/api-style_alldocs-response-schema.json
web_page_module/gadget_erp5_page_jio_api_action_html
web_page_module/gadget_erp5_page_jio_api_action_js
web_page_module/gadget_erp5_page_json_form_schema_api_html
web_page_module/gadget_erp5_page_json_form_schema_api_js
\ No newline at end of file
web_page_module/api-style_alldocs-response-schema.json
\ No newline at end of file
web_page_module/api-style_alldocs-response-schema.json
web_page_module/gadget_erp5_page_jio_api_action_html
web_page_module/gadget_erp5_page_jio_api_action_js
web_page_module/gadget_erp5_page_json_form_schema_api_html
web_page_module/gadget_erp5_page_json_form_schema_api_js
\ No newline at end of file
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