blob: 60a2ddfdde8e6b513b47d1f2fb75b1c602403c06 [file] [log] [blame]
//-
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
include /app/helpers/jade/mixins
mixin form-field__sensitive({ label, modelFilter, modelSensitive, name, placeholder })
.form-field.form-field__sensitive.ignite-form-field
+form-field__label({ label, name })
+form-field__tooltip({ title: 'You can set case sensitive search' })
.form-field__control.form-field__control-group
+form-field__input({ name, model: modelFilter, placeholder })(
type='text'
)
label.btn-ignite.btn-ignite--secondary
+form-field__input({ name: `${ name } + "Sensitive"`, model: modelSensitive, placeholder })(
type='checkbox'
)
span Cs
.form-field__errors(
ng-messages=`$input.$error`
ng-show=`($input.$dirty || $input.$touched || $input.$submitted) && $input.$invalid`
)
mixin btn-toolbar(btn, click, tip, focusId)
i.btn.btn-default.fa(class=btn ng-click=click bs-tooltip='' data-title=tip ignite-on-click-focus=focusId data-trigger='hover' data-placement='bottom')
mixin btn-toolbar-data(btn, kind, tip)
i.btn.btn-default.fa(class=btn ng-click=`setResult(paragraph, '${kind}')` ng-class=`{active: resultEq(paragraph, '${kind}')}` bs-tooltip='' data-title=tip data-trigger='hover' data-placement='bottom')
mixin result-toolbar
.btn-group(ng-model='paragraph.result' ng-click='$event.stopPropagation()' style='left: 50%; margin: 0 0 0 -70px;display: block;')
+btn-toolbar-data('fa-table', 'table', 'Show data in tabular form')
+btn-toolbar-data('fa-bar-chart', 'bar', 'Show bar chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
+btn-toolbar-data('fa-pie-chart', 'pie', 'Show pie chart<br/>By default first column - pie labels, second column - pie values<br/>In case of one column it will be treated as pie values')
+btn-toolbar-data('fa-line-chart', 'line', 'Show line chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
+btn-toolbar-data('fa-area-chart', 'area', 'Show area chart<br/>By default first column - X values, second column - Y values<br/>In case of one column it will be treated as Y values')
mixin chart-settings
.total.row
.col-xs-7
.chart-settings-link(ng-show='paragraph.chart && paragraph.chartColumns.length > 0')
a(title='Click to show chart settings dialog' ng-click='$event.stopPropagation()' bs-popover data-template-url='{{ $ctrl.chartSettingsTemplateUrl }}' data-placement='bottom' data-auto-close='1' data-trigger='click')
i.fa.fa-bars
| Chart settings
div(ng-show='paragraphTimeSpanVisible(paragraph)')
label Show
button.select-manual-caret.btn.btn-default(ng-model='paragraph.timeLineSpan' ng-change='applyChartSettings(paragraph)' bs-options='item for item in timeLineSpans' bs-select data-caret-html='<span class="caret"></span>')
label min
div
label Duration: #[b {{paragraph.duration | duration}}]
label.margin-left-dflt(ng-show='paragraph.localQueryMode') NodeID8: #[b {{paragraph.resNodeId | id8}}]
.col-xs-2
+result-toolbar
mixin query-settings
div
.form-field--inline(
bs-tooltip
data-placement='top'
data-title='Max number of rows to show in query result as one page'
)
+form-field__dropdown({
label: 'Rows per page:',
model: 'paragraph.pageSize',
name: '"pageSize" + paragraph.id',
options: 'pageSizesOptions'
})
.form-field--inline(
bs-tooltip
data-placement='top'
data-title='Limit query max results to specified number of pages'
)
+form-field__dropdown({
label: 'Max pages:',
model: 'paragraph.maxPages',
name: '"maxPages" + paragraph.id',
options: 'maxPages'
})
.form-field--inline(
bs-tooltip
data-placement='bottom'
data-title='Configure periodical execution of last successfully executed query'
)
button.btn-ignite-group(
bs-popover
data-template-url='{{ $ctrl.paragraphRateTemplateUrl }}'
data-placement='bottom-right'
data-auto-close='1'
data-trigger='click'
)
.btn-ignite(
ng-class='{\
"btn-ignite--primary": paragraph.rate && paragraph.rate.installed,\
"btn-ignite--secondary": !(paragraph.rate && paragraph.rate.installed),\
}'
)
svg(ignite-icon='clock')
| &nbsp; {{ rateAsString(paragraph) }}
.btn-ignite(
ng-class='{\
"btn-ignite--primary": paragraph.rate && paragraph.rate.installed,\
"btn-ignite--secondary": !(paragraph.rate && paragraph.rate.installed),\
}'
)
span.icon.fa.fa-caret-down
div
.row(ng-if='nonCollocatedJoinsAvailable(paragraph)')
+form-field__checkbox({
label: 'Allow non-collocated joins',
model: 'paragraph.nonCollocatedJoins',
name: '"nonCollocatedJoins" + paragraph.id',
tip: 'Non-collocated joins is a special mode that allow to join data across cluster without collocation.<br/>\
Nested joins are not supported for now.<br/>\
<b>NOTE</b>: In some cases it may consume more heap memory or may take a long time than collocated joins.',
tipOpts: { placement: 'top' }
})
.row(ng-if='collocatedJoinsAvailable(paragraph)')
+form-field__checkbox({
label: 'Collocated Query',
model: 'paragraph.collocated',
name: '"collocated" + paragraph.id',
tip: 'Used For Optimization Purposes Of Queries With GROUP BY Statements.<br/>\
<b>NOTE:</b> Whenever Ignite executes a distributed query, it sends sub-queries to individual cluster members.<br/>\
If you know in advance that the elements of your query selection are collocated together on the same node\
and you group by collocated key (primary or affinity key), then Ignite can make significant performance and\
network optimizations by grouping data on remote nodes.',
tipOpts: { placement: 'top' }
})
.row(ng-if='enforceJoinOrderAvailable(paragraph)')
+form-field__checkbox({
label: 'Enforce join order',
model: 'paragraph.enforceJoinOrder',
name: '"enforceJoinOrder" + paragraph.id',
tip: 'Enforce join order of tables in the query.<br/>\
If <b>set</b>, then query optimizer will not reorder tables within join.<br/>\
<b>NOTE:</b> It is not recommended to enable this property unless you have verified that\
indexes are not selected in optimal order.',
tipOpts: { placement: 'top' }
})
.row(ng-if='lazyQueryAvailable(paragraph)')
+form-field__checkbox({
label: 'Lazy result set',
model: 'paragraph.lazy',
name: '"lazy" + paragraph.id',
tip: 'By default Ignite attempts to fetch the whole query result set to memory and send it to the client.<br/>\
For small and medium result sets this provides optimal performance and minimize duration of internal database locks, thus increasing concurrency.<br/>\
If result set is too big to fit in available memory this could lead to excessive GC pauses and even OutOfMemoryError.<br/>\
Use this flag as a hint for Ignite to fetch result set lazily, thus minimizing memory consumption at the cost of moderate performance hit.',
tipOpts: { placement: 'top' }
})
mixin query-actions
button.btn-ignite.btn-ignite--primary(ng-disabled='!queryAvailable(paragraph)' ng-click='execute(paragraph)')
span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.executionInProgress(false)')
span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.executionInProgress(false)')
| Execute
button.btn-ignite.btn-ignite--primary(ng-disabled='!queryAvailable(paragraph)' ng-click='execute(paragraph, true)')
span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.executionInProgress(true)')
span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.executionInProgress(true)')
| Execute on selected node
button.btn-ignite.btn-ignite--secondary(ng-disabled='!queryAvailable(paragraph)' ng-click='explain(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{queryTooltip(paragraph, "explain query")}}')
| Explain
button.btn-ignite.btn-ignite--secondary(ng-if='paragraph.executionInProgress(false) || paragraph.executionInProgress(true)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
| Cancel
mixin table-result-heading-query
.total.row
.col-xs-7
grid-column-selector(grid-api='paragraph.gridOptions.api')
.fa.fa-bars.icon
label Page: #[b {{paragraph.page}}]
label.margin-left-dflt Results so far: #[b {{paragraph.rows.length + paragraph.total}}]
label.margin-left-dflt Duration: #[b {{paragraph.duration | duration}}]
label.margin-left-dflt(ng-show='paragraph.localQueryMode') NodeID8: #[b {{paragraph.resNodeId | id8}}]
.col-xs-2
div(ng-if='paragraph.qryType === "query"')
+result-toolbar
.col-xs-3
.pull-right
.btn-ignite-group
button.btn-ignite.btn-ignite--primary(
ng-click='exportCsv(paragraph)'
ng-disabled='paragraph.loading'
bs-tooltip=''
ng-attr-title='{{ queryTooltip(paragraph, "export query results") }}'
data-trigger='hover'
data-placement='bottom'
)
svg(ignite-icon='csv' ng-if='!paragraph.csvIsPreparing')
svg.fa-spin(ignite-icon='refresh' ng-if='paragraph.csvIsPreparing')
| &nbsp; Export
-var options = [{ text: 'Export', click: 'exportCsv(paragraph)' }, { text: 'Export all', click: 'exportCsvAll(paragraph)' }, { divider: true }, { text: '<span title="Copy current result page to clipboard">Copy to clipboard</span>', click: 'exportCsvToClipBoard(paragraph)' }]
button.btn-ignite.btn-ignite--primary(
ng-disabled='paragraph.loading'
bs-dropdown=`${JSON.stringify(options)}`
data-toggle='dropdown'
data-container='body'
data-placement='bottom-right'
data-html='true'
)
span.icon.fa.fa-caret-down
mixin table-result-heading-scan
.total.row
.col-xs-7
grid-column-selector(grid-api='paragraph.gridOptions.api')
.fa.fa-bars.icon
label Page: #[b {{paragraph.page}}]
label.margin-left-dflt Results so far: #[b {{paragraph.rows.length + paragraph.total}}]
label.margin-left-dflt Duration: #[b {{paragraph.duration | duration}}]
label.margin-left-dflt(ng-show='paragraph.localQueryMode') NodeID8: #[b {{paragraph.resNodeId | id8}}]
.col-xs-2
div(ng-if='paragraph.qryType === "query"')
+result-toolbar
.col-xs-3
.pull-right
.btn-group.panel-tip-container
// TODO: replace this logic for exporting under one component
button.btn.btn-primary.btn--with-icon(
ng-click='exportCsv(paragraph)'
ng-disabled='paragraph.loading || paragraph.csvIsPreparing'
bs-tooltip=''
ng-attr-title='{{ scanTooltip(paragraph) }}'
data-trigger='hover'
data-placement='bottom'
)
svg(ignite-icon='csv' ng-if='!paragraph.csvIsPreparing')
i.fa.fa-fw.fa-refresh.fa-spin(ng-if='paragraph.csvIsPreparing')
span Export
-var options = [{ text: "Export", click: 'exportCsv(paragraph)' }, { text: 'Export all', click: 'exportCsvAll(paragraph)' }, { divider: true }, { text: '<span title="Copy current result page to clipboard">Copy to clipboard</span>', click: 'exportCsvToClipBoard(paragraph)' }]
button.btn.dropdown-toggle.btn-primary(
ng-disabled='paragraph.loading || paragraph.csvIsPreparing'
bs-dropdown=`${JSON.stringify(options)}`
data-toggle='dropdown'
data-container='body'
data-placement='bottom-right'
data-html='true'
)
span.caret
mixin table-result-body
.grid(ui-grid='paragraph.gridOptions' ui-grid-resize-columns ui-grid-exporter ui-grid-hovering)
mixin chart-result
div(ng-hide='paragraph.scanExplain()')
+chart-settings
.empty(ng-show='paragraph.chartColumns.length > 0 && !paragraph.chartColumnsConfigured()') Cannot display chart. Please configure axis using #[b Chart settings]
.empty(ng-show='paragraph.chartColumns.length == 0') Cannot display chart. Result set must contain Java build-in type columns. Please change query and execute it again.
div(ng-show='paragraph.chartColumnsConfigured()')
div(ng-show='paragraph.timeLineSupported() || !paragraph.chartTimeLineEnabled()')
div(ng-repeat='chart in paragraph.charts')
nvd3(options='chart.options' data='chart.data' api='chart.api')
.empty(ng-show='!paragraph.timeLineSupported() && paragraph.chartTimeLineEnabled()') Pie chart does not support 'TIME_LINE' column for X-axis. Please use another column for X-axis or switch to another chart.
.empty(ng-show='paragraph.scanExplain()')
.row
.col-xs-4.col-xs-offset-4
+result-toolbar
label.margin-top-dflt Charts do not support #[b Explain] and #[b Scan] query
mixin paragraph-scan
panel-title {{ paragraph.name }}
panel-actions
query-actions-button(actions='$ctrl.scanActions' item='paragraph')
panel-content
.col-sm-12.sql-controls
.col-sm-3
+form-field__dropdown({
label: 'Cache:',
model: 'paragraph.cacheName',
name: '"cache"',
placeholder: 'Choose cache',
options: 'caches'
})
.col-sm-3
+form-field__sensitive({
label: 'Filter:',
modelFilter: 'paragraph.filter',
modelSensitive: 'paragraph.caseSensitive',
name: '"filter"',
placeholder: 'Enter filter'
})
.col-sm-3
+form-field__dropdown({
label: 'Rows per page:',
model: 'paragraph.pageSize',
name: '"pageSize" + paragraph.id',
options: 'pageSizesOptions',
tip: 'Max number of rows to show in query result as one page',
tipOpts: { placement: 'top' }
})
.col-sm-12.sql-controls
div
button.btn-ignite.btn-ignite--primary(ng-disabled='!scanAvailable(paragraph)' ng-click='scan(paragraph)')
span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.checkScanInProgress(false)')
span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.checkScanInProgress(false)')
| Scan
button.btn-ignite.btn-ignite--primary(ng-disabled='!scanAvailable(paragraph)' ng-click='scan(paragraph, true)')
span.icon-left.fa.fa-fw.fa-play(ng-hide='paragraph.checkScanInProgress(true)')
span.icon-left.fa.fa-fw.fa-refresh.fa-spin(ng-show='paragraph.checkScanInProgress(true)')
| Scan on selected node
button.btn-ignite.btn-ignite--secondary(ng-if='paragraph.checkScanInProgress(false) || paragraph.checkScanInProgress(true)' ng-click='cancelQuery(paragraph)' data-placement='bottom' bs-tooltip='' data-title='{{"Cancel query execution"}}')
| Cancel
div
.col-sm-12.sql-result(ng-if='paragraph.queryExecuted() && !paragraph.scanningInProgress' ng-switch='paragraph.resultType()')
.error(ng-switch-when='error') Error: {{paragraph.error.message}}
.empty(ng-switch-when='empty') Result set is empty. Duration: #[b {{paragraph.duration | duration}}]
.table(ng-switch-when='table')
+table-result-heading-scan
+table-result-body
.footer.clearfix()
.pull-left
| Showing results for scan of #[b {{ paragraph.queryArgs.cacheName | defaultName }}]
span(ng-if='paragraph.queryArgs.filter') &nbsp; with filter: #[b {{ paragraph.queryArgs.filter }}]
span(ng-if='paragraph.queryArgs.localNid') &nbsp; on node: #[b {{ paragraph.queryArgs.localNid | limitTo:8 }}]
-var nextVisibleCondition = 'paragraph.resultType() != "error" && !paragraph.loading && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'
.pull-right(ng-show=`${nextVisibleCondition}` ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
i.fa.fa-chevron-circle-right
a Next
mixin paragraph-query
panel-title {{ paragraph.name }}
panel-actions
query-actions-button(actions='$ctrl.queryActions' item='paragraph')
panel-content
.col-sm-12
.col-xs-8.col-sm-9(style='border-right: 1px solid #eee')
.sql-editor(ignite-ace='{onLoad: aceInit(paragraph), theme: "chrome", mode: "sql", require: ["ace/ext/language_tools"],' +
'advanced: {enableSnippets: false, enableBasicAutocompletion: true, enableLiveAutocompletion: true}}'
ng-model='paragraph.query' on-selection-change='paragraph.partialQuery = $event')
.col-xs-4.col-sm-3
div(ng-show='caches.length > 0' style='padding: 5px 10px' st-table='displayedCaches' st-safe-src='caches')
lable.labelField.labelFormField Caches:
i.fa.fa-database.tipField(title='Click to show cache types metadata dialog' bs-popover data-template-url='{{ $ctrl.cacheMetadataTemplateUrl }}' data-placement='bottom-right' data-trigger='click' data-container='#{{ paragraph.id }}')
.input-tip
input.form-control(type='text' st-search='label' placeholder='Filter caches...')
.queries-notebook-displayed-caches
div(ng-repeat='cache in displayedCaches track by cache.value')
+form-field__radio({
label: '{{ cache.label }}',
model: 'paragraph.cacheName',
name: '"cache_" + [paragraph.id, $index].join("_")',
value: 'cache.value'
})
.settings-row
.row(ng-if='ddlAvailable(paragraph)')
+form-field__checkbox({
label: 'Use selected cache as default schema name',
model: 'paragraph.useAsDefaultSchema',
name: '"useAsDefaultSchema" + paragraph.id',
tip: 'Use selected cache as default schema name.<br/>\
This will allow to execute query on specified cache without specify schema name.<br/>\
<b>NOTE:</b> In future version of Ignite this feature will be removed.',
tipOpts: { placement: 'top' }
})
.empty-caches(ng-show='displayedCaches.length == 0 && caches.length != 0')
no-data
label Wrong caches filter
.empty-caches(ng-show='caches.length == 0')
no-data
label No caches
.col-sm-12.sql-controls
div
+query-actions
+query-settings
.col-sm-12.sql-result(ng-if='paragraph.queryExecuted()' ng-switch='paragraph.resultType()')
.error(ng-switch-when='error')
label Error: {{paragraph.error.message}}
br
a(ng-show='paragraph.resultType() === "error"' ng-click='showStackTrace(paragraph)') Show more
.empty(ng-switch-when='empty') Result set is empty. Duration: #[b {{paragraph.duration | duration}}]
.table(ng-switch-when='table')
+table-result-heading-query
+table-result-body
.chart(ng-switch-when='chart')
+chart-result
.footer.clearfix(ng-show='paragraph.resultType() !== "error"')
a.pull-left(ng-click='showResultQuery(paragraph)') Show query
-var nextVisibleCondition = 'paragraph.resultType() !== "error" && !paragraph.loading && paragraph.queryId && paragraph.nonRefresh() && (paragraph.table() || paragraph.chart() && !paragraph.scanExplain())'
.pull-right(ng-show=`${nextVisibleCondition}` ng-class='{disabled: paragraph.loading}' ng-click='!paragraph.loading && nextPage(paragraph)')
i.fa.fa-chevron-circle-right
a Next
div(ng-if='notebook')
.notebooks-top
h1(ng-hide='notebook.edit')
label {{notebook.name}}
.btn-group(ng-if='!demo')
+btn-toolbar('fa-pencil', 'notebook.edit = true;notebook.editName = notebook.name', 'Rename notebook')
h1(ng-show='notebook.edit')
input.form-control(ng-model='notebook.editName' required ignite-on-enter='renameNotebook(notebook.editName)' ignite-on-escape='notebook.edit = false;')
i.btn.fa.fa-floppy-o(ng-show='notebook.editName' ng-click='renameNotebook(notebook.editName)' bs-tooltip data-title='Save notebook name' data-trigger='hover')
cluster-selector
.notebook-top-buttons
a.dropdown-toggle(style='margin-right: 20px' data-toggle='dropdown' bs-dropdown='scrollParagraphs' data-placement='bottom-left') Scroll to query
span.caret
button.btn-ignite.btn-ignite--primary(ng-click='addQuery()' ignite-on-click-focus=focusId)
svg.icon-left(ignite-icon='plus')
| Add query
button.btn-ignite.btn-ignite--primary(ng-click='addScan()' ignite-on-click-focus=focusId)
svg.icon-left(ignite-icon='plus')
| Add scan
div
breadcrumbs
a.link-success(ui-sref='base.sql.tabs') Notebooks
span(ui-sref='.' ui-sref-active) Notebook '{{notebook.name}}'
-var example = `CREATE TABLE Person(ID INTEGER PRIMARY KEY, NAME VARCHAR(100));\nINSERT INTO Person(ID, NAME) VALUES (1, 'Ed'), (2, 'Ann'), (3, 'Emma');\nSELECT * FROM Person;`;
ignite-information(
data-title='With query notebook you can'
style='margin-bottom: 30px'
ng-init=`example = "${example}"`
)
ul
li Create any number of queries
li Execute and explain SQL queries
li Execute scan queries
li View data in tabular form and as charts
li
a(href='https://apacheignite-sql.readme.io/docs/sql-reference-overview' target='_blank') More info
.example
.group
.group-legend
label Examples:
.group-content
.sql-editor(ignite-ace='{\
onLoad: aceInit({}),\
theme: "chrome",\
mode: "sql",\
require: ["ace/ext/language_tools"],\
showGutter: false,\
advanced: {\
enableSnippets: false,\
enableBasicAutocompletion: true,\
enableLiveAutocompletion: true\
}}'
ng-model='example'
readonly='true'
)
.notebook-failed--block(ng-if='notebookLoadFailed')
no-data
h2 Failed to load notebook
label.col-sm-12 Notebook not accessible any more. Go back to notebooks list.
div(ng-if='notebook' ignite-loading='sqlLoading' ignite-loading-text='{{ loadingText }}' ignite-loading-position='top')
.docs-body.paragraphs
.panel-group
.panel-paragraph(ng-repeat='paragraph in notebook.paragraphs' id='{{paragraph.id}}' ng-form='form_{{paragraph.id}}')
panel-collapsible(
ng-if='paragraph.qryType === "scan"'
opened='$ctrl.isParagraphOpened($index)'
on-close='$ctrl.onParagraphClose($index)'
on-open='$ctrl.onParagraphOpen($index)'
)
+paragraph-scan
panel-collapsible(
ng-if='paragraph.qryType === "query"'
opened='$ctrl.isParagraphOpened($index)'
on-close='$ctrl.onParagraphClose($index)'
on-open='$ctrl.onParagraphOpen($index)'
)
+paragraph-query