Commit 247469b3 authored by Jérome Perrin's avatar Jérome Perrin

erp5_sql_browser: Simple tool to run SQL queries in the browser

parent e2f8c897
master DateTime.equalTo_fix TMP-2to3 UpdateValidationStateFromConsistency UserPropertySheet_backward_compatibility addToDate_implicit_localtime add_boolean_type allow_login_change allow_login_change_wip arnau arnau-RD-Components-CacheTool arnau-RD-Components-ERP5Form-ERP5Report arnau-RD-Components-ERP5Form-SelectionTool-MemcachedTool arnau-RD-Components-ERP5OOo arnau-RD-Components-PreferenceTool-Preference arnau-RD-Components-Products-import-compat arnau-RD-Components-astroid_cache_per_component_reset arnau-RD-Components-erp5_crm arnau-RD-Components-erp5_trade-TODO-Interactor arnau-RD-ERP5ify-portal_workflow-1-seb-merged-with-recent-master arnau-RD-ERP5ify-portal_workflow-2-do-not-rename-erp5_workflow-portal_types arnau-RD-ERP5ify-portal_workflow-BAK arnau-RD-ERP5ify-portal_workflow-WIP arnau-RD-ERP5ify-portal_workflow-WITHOUT-MIGRATION arnau-RD-ERP5ify-portal_workflow-WORKFLOWS-NOT-MIGRATED arnau-RD-py3-master-TM arnau-RD-py3-master-TM-BAK arnau-RD-py3-master-WIP arnau-RD-py3-master-WIP-BAK arnau-RD-py3-master-WIP-bt5-and-tests arnau-RD-zope4py3 arnau-TM-Components-Migrate-PortalTransforms arnau-TM-Components-ModuleSecurityInfo arnau-TM-FEC-output arnau-TM-WIP arnau-TM-isBuildable-with-multiple-BusinessLinks arnau-TM-newContent-temp_object arnau-TM-runUnitTest-clear-previous-execution-catalog arnau-TM-wkhtmltopdf arnau-WIP arnau-kns arnau-kns-without-property-mapping arnau-my2to3 arnau-real-time-inventory-accounting arnau-zope4py2 aurel-zope4py2 auto_extend_select_list bk_erp5ish_actions_tool bk_sqlcatalog bt5_config cache-control-304-response callable-jupyter-storage catalog_filter cedriclen-eos cherry-pick-4a8e045d cleanup_acquisition_base_category cribjs-bootloader delivery_item_barcode douglas_forum drop-ZServer dsn-phase3 e2e-erp5 enhance_scalability_testing eos-dev erp5-component erp5-component-bak erp5-imt erp5-messenger erp5-vifib erp5-vifib-cleanup erp5-vifib-no-Products.DCWorkflowGraph erp5-vifib-py3 erp5_catalog erp5_catalog_final erp5_corporate_identity erp5_drone_simulator erp5_free_subscription erp5_hal_json_style_fix_restricted_access_with_traverse erp5_payslip_migration erp5_workflow erp5testnode_max_timeout feat/coding_style_test feat/dedup_roles_in_pickles feat/dms_implicit_predecessor_successor_fields feat/erp5_ide feat/erp5pt feat/fsum feat/improve_rounding_tool feat/inventory_api_group_by_time_interval_list feat/lxml-html-snapshot feat/mariadb-10.11 feat/mariadb-10.11bis feat/mariadb-10.11ter feat/mariadb-10.5 feat/mariadb-10.6 feat/mariadb-11.4bis feat/mariadb-11.4bis-old feat/mariadb-11.4ter feat/notification-message-ignore-missing feat/olapy feat/python_language_support feat/reindexlastobjects_log feat/round_half_up feat/selenium-unexpected-success feat/slapos_agent_distributor feat/subject_set_query feature/renderjs-ui-no-header fix/GHSA-g5vw-3h65-2q3v fix/TALES_hide_error fix/ZMI_editor_preference fix/accounting-fec-no-line fix/advance_ecommerce_coding_crimes fix/balance-0-asset-price fix/bt-module-uninstall fix/erp5_site_global_id fix/invoice-line-currency-price fix/login_validate_check_consistency fix/mariadb-1927 fix/measure-optional-variation fix/monaco-altClick fix/officejs_support_request_rss_secu fix/state_var fix/support-request-app-empty fix/testnode_proctitle fix/workflow_info fix/workflow_method_security fix_web_illustration for_testrunner_1 for_testrunner_2 for_testrunner_3 gadget-json-value graphic_gadget_js hotfix/rjs-formfields-padding improve_default_caching_policy_manager initsite inventory isDeletable jm/form-action-guard js-ui kns limit_accelerated_http_cache_manager listbox_url lle-bout/metadata-modules macros_fix master_w mic_wind monitoring-graph mr1362 my2to3 no_longer_simulated_state notebook_roque oauth-login-minor-improvement officejs override_cache_control_header_by_caching_policy_manager poc/json-forms-study portal_callables portal_solver_process_security_configuration publish_recursiveReindexObject refactor/base_edit reindex_calendar_after_change_calendar_exception restore-from-trashbin revert-192c2000 revert-38554dbe rfc/activate_default rjs_listbox_sort_icon roque_quick scalability-master scalability-roque scalability-roque-2 scalability-run-command scalability_crash_mariadb shop-box-rebase streaming_fix streaming_fix-0 support_legacy_sftp_server support_relative_url_in_hyperlink_field support_request taskdistribution-xmlrpc-binary test-renderjs-float-field-step test_cmfactivity_isolation_level test_dynamic_methods testnode_software_link timezones tomo_testnode_slap_request translatable_path_master tristan tristan-merge trustable-x-forwarded-for ttrm unify_predicate_edit view-aggregated-amounts without_legacy_workflow workaround_mroonga_14 wsgi wsgi-gevent wsgi_backport_setbody_lock wsgi_medusa_stream_fix zope2 zope2zope4py2 zope4py3 zope4py3-BEFORE-CLEANUP zope4py3-master-rebase 0.4.59.1 0.4.59 test-ui test-rjsacc test-rjs renderjs-test nexedi-erp5-vifib-20201105 erp5.util-0.4.76 erp5.util-0.4.75 erp5.util-0.4.74 erp5.util-0.4.73 erp5.util-0.4.72 erp5.util-0.4.71 erp5.util-0.4.69 erp5.util-0.4.68 erp5.util-0.4.67 erp5.util-0.4.66 erp5.util-0.4.65 erp5.util-0.4.64 erp5.util-0.4.63 erp5.util-0.4.62 erp5.util-0.4.61 erp5.util-0.4.60 erp5.util-0.4.59.1 erp5.util-0.4.59 erp5.util-0.4.58 erp5.util-0.4.57 erp5.util-0.4.56 erp5.util-0.4.55 erp5.util-0.4.54 erp5.util-0.4.53 erp5.util-0.4.52 erp5.util-0.4.49 erp5.util-0.4.46 erp5.util-0.4.44 erp5.util-0.4.43 erp5-vifib-20240326 erp5-vifib-20230331 erp5-vifib-20230201 erp5-vifib-20220526 erp5-vifib-20220302 erp5-vifib-20210707 erp5-vifib-20201229 erp5-vifib-20200129
No related merge requests found
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>erp5_sql_browser</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>import datetime\n
import json\n
from DateTime import DateTime\n
\n
response = container.REQUEST.RESPONSE\n
\n
try:\n
results = context.manage_test(query)\n
data = [ results.names() ]\n
data.extend(results.tuples())\n
except Exception, e:\n
response.setStatus(500)\n
try:\n
response.write(str(e[1]))\n
except Exception, _:\n
response.write(str(e))\n
return\n
\n
# handle non JSON serializable data\n
new_data = [data[0]]\n
for line in data[1:]:\n
new_line = []\n
for v in line:\n
if isinstance(v, DateTime):\n
v = v.ISO()\n
if isinstance(v, datetime.datetime):\n
v = v.isoformat()\n
new_line.append(v)\n
new_data.append(new_line)\n
\n
response.setHeader(\'Content-Type\', \'application/json\')\n
return json.dumps(new_data, indent=2)\n
\n
\n
\n
\n
\n
\n
import datetime\n
import json\n
from DateTime import DateTime\n
\n
response = container.REQUEST.RESPONSE\n
\n
try:\n
results = context.manage_test(query)\n
data = [ results.names() ]\n
data.extend(results.dictionaries())\n
except Exception, e:\n
response.setStatus(500)\n
try:\n
response.write(str(e[1]))\n
except Exception, _:\n
response.write(str(e))\n
return\n
\n
# handle non JSON serializable data\n
new_data = [data[0]]\n
for line in data[1:]:\n
new_line = {}\n
for k, v in line.items():\n
if isinstance(v, DateTime):\n
v = v.ISO()\n
if isinstance(v, datetime.datetime):\n
v = v.isoformat()\n
line[k] = v#new_line.append(v)\n
new_data.append(line)\n
\n
response.setHeader(\'Content-Type\', \'application/json\')\n
return json.dumps(new_data, indent=2)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string>query=""</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ZMySQLDAConnection_getQueryResultAsJSON</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>from json import dumps\n
table_dict = {}\n
\n
connection = context\n
\n
# make sure connection is open\n
connection()\n
\n
for table in connection.manage_test("SHOW TABLES"):\n
table_dict[table[0]] = []\n
for column in connection.manage_test("SHOW COLUMNS FROM `%s`" % table[0]):\n
table_dict[table[0]].append(column[0])\n
table_dict[table[0]].append("`%s`" % column[0])\n
\n
container.REQUEST.RESPONSE.setHeader(\'content-type\', \'application/json\')\n
return dumps(table_dict)\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ZMySQLDAConnection_getSchemaAsJSON</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34503950.54</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>ZMySQLDAConnection_viewQueryBrowser</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
<!DOCTYPE html>\n
<html>\n
<head>\n
<title>SQL Browser</title>\n
\n
<script type="text/javascript" src="jquery/core/jquery-1.9.min.js"></script>\n
<script type="text/javascript" src="jquery/ui/js/jquery-ui.min.js"></script>\n
\n
<!-- "local" handsontable TODO make a bt ? -->\n
<script src="sql_browser/handsontable.full.js"></script>\n
<link rel="stylesheet" media="screen" href="sql_browser/handsontable.full.css">\n
\n
<!-- "local" jquery noty -->\n
<script type="text/javascript" src="sql_browser/jquery.noty.packaged.js"></script>\n
\n
<!-- "local" c3.js (0.4.10) and d3.js (3.5.5) -->\n
<link rel="stylesheet" type="text/css" href="sql_browser/c3.min.css">\n
<script type="text/javascript" src="sql_browser/d3.min.js"></script>\n
<script type="text/javascript" src="sql_browser/c3.min.js"></script>\n
\n
<!-- PivotTable.js libs from erp5_pivot_table -->\n
<link rel="stylesheet" type="text/css" href="pivottable/pivot.css">\n
<script type="text/javascript" src="pivottable/pivot.js"></script>\n
<script type="text/javascript" src="pivottable/gchart_renderers.js"></script>\n
<script type="text/javascript" src="pivottable/c3_renderers.js"></script>\n
\n
\n
<!-- code mirror from erp5_code_mirror bt5 -->\n
<script type="text/javascript" src="codemirror/lib/codemirror.js"></script>\n
<link rel="stylesheet" href="codemirror/lib/codemirror.css">\n
<script type="text/javascript" src="codemirror/mode/sql/sql.js"></script>\n
<script type="text/javascript" src="codemirror/addon/cm_edit/matchbrackets.js"></script>\n
<link rel="stylesheet" href="codemirror/addon/dialog/dialog.css">\n
<script type="text/javascript" src="codemirror/addon/dialog/dialog.js"></script>\n
<script type="text/javascript" src="codemirror/addon/search/searchcursor.js"></script>\n
<script type="text/javascript" src="codemirror/addon/search/search.js"></script>\n
<link rel="stylesheet" href="codemirror/addon/hint/show-hint.css">\n
<script src="codemirror/addon/hint/show-hint.js"></script>\n
<script src="codemirror/addon/hint/anyword-hint.js"></script>\n
<script src="codemirror/addon/hint/sql-hint.js"></script>\n
\n
\n
<style>\n
.CodeMirror {height: 80px;}\n
body {font-family: Verdana;}\n
.c3-line {stroke-width: 3px;}\n
.c3 circle {stroke: white;}\n
.c3 text { font-size: 12px;}\n
.c3 text { font-size: 12px;}\n
.tick line {stroke: white;}\n
</style>\n
</head>\n
\n
<body>\n
<script type="text/javascript">\n
$(function() {\n
var editor,\n
ht = new Handsontable(document.getElementById(\'table_container\'), { data: [[0]], rowHeaders: true, colHeaders: true}),\n
redraw = function(){\n
\n
var derivers = $.pivotUtilities.derivers;\n
var renderers = $.extend($.pivotUtilities.renderers,\n
$.pivotUtilities.c3_renderers);\n
var dateFormat = $.pivotUtilities.derivers.dateFormat;\n
var sortAs = $.pivotUtilities.sortAs;\n
var tpl = $.pivotUtilities.aggregatorTemplates;\n
var sum = $.pivotUtilities.aggregatorTemplates.sum;\n
var numberFormat = $.pivotUtilities.numberFormat;\n
var intFormat = numberFormat({digitsAfterDecimal: 0});\n
var notification = noty({type: "info", text: "Refreshing data", layout: "bottom"});\n
\n
$.getJSON("ZMySQLDAConnection_getQueryResultAsJSON", {query: editor.getValue()}, function(mps) {\n
\n
ht.clear();\n
if (mps.length > 1) {\n
ht.updateSettings({\n
data: mps.slice(1),\n
colHeaders: mps[0]\n
});\n
} else {\n
ht.updateSettings({ data: [[0]], colHeaders: true})\n
}\n
\n
\n
$("#output").pivotUI(mps, {\n
renderers: renderers,\n
\n
hiddenAttributes: [],\n
\n
onRefresh: function(config) {\n
// TODO save properties\n
var config_copy = JSON.parse(JSON.stringify(config));\n
//delete some values which are functions\n
delete config_copy["aggregators"];\n
delete config_copy["renderers"];\n
delete config_copy["derivedAttributes"];\n
//delete some bulky default values\n
delete config_copy["rendererOptions"];\n
delete config_copy["localeStrings"];\n
$("#config_json").text(JSON.stringify(config_copy, undefined, 2));\n
}\n
});\n
notification.close();\n
}\n
).fail(function(jqXHR, textStatus, errorThrown) {\n
notification.close();\n
noty({type: "error", text: jqXHR.responseText, timeout: 5000, layout: "bottom" });\n
});\n
};\n
\n
$(function() {\n
editor = CodeMirror.fromTextArea(document.getElementById("query"), {\n
lineNumbers: true,\n
viewportMargin: Infinity,\n
extraKeys: {"Ctrl-Space": "autocomplete", "Ctrl-Enter": redraw, "Alt-Space": redraw},\n
mode: "text/x-mariadb"\n
});\n
$.getJSON("ZMySQLDAConnection_getSchemaAsJSON").then(\n
function(schema) {\n
CodeMirror.commands.autocomplete = function(cm) {\n
CodeMirror.showHint(cm, CodeMirror.hint.sql, {\n
tables: schema\n
} );\n
}\n
});\n
\n
$(\'button[name="Query"]\').click(redraw);\n
\n
// TODO: save presets in JIO\n
// ( also include pivot table config in preset )\n
$(\'button[name="Save"]\').click(function(){alert("TODO");});\n
\n
$(\'#presets\')\n
.append($(\'<option>\', {\n
value: "select * from message_queue where processing_node = -2",\n
text: \'Select failed message_queue activities\'\n
}))\n
.append($(\'<option>\', {\n
value: "update message_queue set processing_node=-1\\n where processing_node=-2\\ and method_id=\'XXX\'",\n
text: \'Restart message_queue\'\n
})).change(function(){editor.setValue($("#presets").val()); redraw();});\n
\n
redraw();\n
});\n
});\n
</script>\n
\n
Presets: <select id="presets"><option selected="selected" value=""></option></select>\n
<button name="Save">Save Preset</button>\n
<br/>\n
<textarea name="query" id="query"></textarea>\n
<button name="Query">Run Query</button>\n
\n
\n
<div id="table_container" style="margin: 10px; height: 300px; overflow: hidden"></div>\n
<div id="output" style="margin: 10px;"></div>\n
\n
<!-- TODO: debug saved configuration -->\n
<div style="display: none">\n
<pre id="config_json"></pre>\n
</div>\n
\n
</body>\n
\n
</html>\n
]]></string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>6813</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>sql_browser</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_EtagSupport__etag</string> </key>
<value> <string>ts34437759.35</string> </value>
</item>
<item>
<key> <string>__name__</string> </key>
<value> <string>c3.min.css</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/css</string> </value>
</item>
<item>
<key> <string>data</string> </key>
<value> <string encoding="cdata"><![CDATA[
.c3 svg{font:10px sans-serif}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
]]></string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>size</string> </key>
<value> <int>1972</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
erp5_jquery
erp5_pivot_table
erp5_code_mirror
\ No newline at end of file
"Quick and dirty" web interface to run queries on a ZMySQLDA Connection.
Control + Enter to run query and Control + Space to complete.
\ No newline at end of file
1
\ No newline at end of file
erp5_sql_browser
\ No newline at end of file
erp5_sql_browser
\ 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