@operato/data-grist 10.13.0 → 10.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/coverage/lcov-report/index.html +215 -200
- package/coverage/lcov-report/webpack/bootstrap.html +1 -1
- package/coverage/lcov-report/webpack/index.html +1 -1
- package/coverage/lcov-report/webpack/runtime/define property getters.html +1 -1
- package/coverage/lcov-report/webpack/runtime/global.html +1 -1
- package/coverage/lcov-report/webpack/runtime/hasOwnProperty shorthand.html +1 -1
- package/coverage/lcov-report/webpack/runtime/index.html +1 -1
- package/coverage/lcov-report/webpack/runtime/make namespace object.html +1 -1
- package/coverage/lcov.info +31463 -29236
- package/dist/src/data-card/data-card.d.ts +4 -6
- package/dist/src/data-card/data-card.js +5 -10
- package/dist/src/data-card/data-card.js.map +1 -1
- package/dist/src/data-consumer.d.ts +4 -0
- package/dist/src/data-consumer.js.map +1 -1
- package/dist/src/data-grid/data-grid-field.js +5 -4
- package/dist/src/data-grid/data-grid-field.js.map +1 -1
- package/dist/src/data-grid/data-grid.d.ts +4 -6
- package/dist/src/data-grid/data-grid.js +6 -10
- package/dist/src/data-grid/data-grid.js.map +1 -1
- package/dist/src/data-grist.d.ts +9 -0
- package/dist/src/data-grist.js +38 -6
- package/dist/src/data-grist.js.map +1 -1
- package/dist/src/data-list/data-list.d.ts +4 -5
- package/dist/src/data-list/data-list.js +5 -9
- package/dist/src/data-list/data-list.js.map +1 -1
- package/dist/src/data-provider.js +25 -8
- package/dist/src/data-provider.js.map +1 -1
- package/dist/src/data-report.d.ts +1 -0
- package/dist/src/data-report.js +2 -1
- package/dist/src/data-report.js.map +1 -1
- package/dist/src/empty-note-render.d.ts +13 -0
- package/dist/src/empty-note-render.js +14 -0
- package/dist/src/empty-note-render.js.map +1 -0
- package/dist/src/empty-note.d.ts +1 -9
- package/dist/src/empty-note.js +5 -52
- package/dist/src/empty-note.js.map +1 -1
- package/dist/src/filters/filter-styles.js +11 -0
- package/dist/src/filters/filter-styles.js.map +1 -1
- package/dist/src/filters/filters-form.js +2 -1
- package/dist/src/filters/filters-form.js.map +1 -1
- package/dist/test/accumulator-labels.test.d.ts +1 -0
- package/dist/test/accumulator-labels.test.js +32 -0
- package/dist/test/accumulator-labels.test.js.map +1 -0
- package/dist/test/control-heights.test.d.ts +1 -0
- package/dist/test/control-heights.test.js +25 -0
- package/dist/test/control-heights.test.js.map +1 -0
- package/dist/test/fetch-failure-state.test.d.ts +1 -0
- package/dist/test/fetch-failure-state.test.js +111 -0
- package/dist/test/fetch-failure-state.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/test/accumulator-labels.test.ts +36 -0
- package/test/control-heights.test.ts +31 -0
- package/test/fetch-failure-state.test.ts +135 -0
- package/translations/en.json +3 -6
- package/translations/ja.json +3 -6
- package/translations/ko.json +4 -7
- package/translations/ms.json +3 -6
- package/translations/zh.json +3 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@operato/data-grist",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.16.0",
|
|
4
4
|
"description": "User interface for grid (desktop) and list (mobile)",
|
|
5
5
|
"author": "heartyoh",
|
|
6
6
|
"type": "module",
|
|
@@ -70,13 +70,14 @@
|
|
|
70
70
|
"@material/web": "^2.0.0",
|
|
71
71
|
"@operato/headroom": "^10.0.0",
|
|
72
72
|
"@operato/i18n": "^10.11.0",
|
|
73
|
-
"@operato/input": "^10.
|
|
74
|
-
"@operato/
|
|
75
|
-
"@operato/
|
|
73
|
+
"@operato/input": "^10.16.0",
|
|
74
|
+
"@operato/list-state": "^10.16.0",
|
|
75
|
+
"@operato/p13n": "^10.16.0",
|
|
76
|
+
"@operato/popup": "^10.16.0",
|
|
76
77
|
"@operato/pull-to-refresh": "^10.0.0",
|
|
77
|
-
"@operato/styles": "^10.
|
|
78
|
+
"@operato/styles": "^10.16.0",
|
|
78
79
|
"@operato/time-calculator": "^10.0.0",
|
|
79
|
-
"@operato/utils": "^10.
|
|
80
|
+
"@operato/utils": "^10.16.0",
|
|
80
81
|
"i18next": "^24.2.1",
|
|
81
82
|
"json5": "^2.2.0",
|
|
82
83
|
"lit": "^3.1.2",
|
|
@@ -115,5 +116,5 @@
|
|
|
115
116
|
"prettier --write"
|
|
116
117
|
]
|
|
117
118
|
},
|
|
118
|
-
"gitHead": "
|
|
119
|
+
"gitHead": "8a061bd85d68e619b0c6aef699c57c89d3d9052a"
|
|
119
120
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The summary row tags a column with its accumulator's name - `label.accumulator_${type}`.
|
|
5
|
+
*
|
|
6
|
+
* max and min were swapped in all five locales: a column summed with `max` (Math.max) was tagged
|
|
7
|
+
* "min" / 「최소」. The words are written out here per locale, so a swap in any one of them fails.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const EXPECTED: Record<string, { max: string; min: string }> = {
|
|
11
|
+
en: { max: 'max', min: 'min' },
|
|
12
|
+
ko: { max: '최대', min: '최소' },
|
|
13
|
+
ja: { max: '最大', min: '最小' },
|
|
14
|
+
zh: { max: '最大', min: '最小' },
|
|
15
|
+
ms: { max: 'Maksimum', min: 'Minimum' }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function translations(locale: string): Promise<Record<string, string>> {
|
|
19
|
+
const response = await fetch(new URL(`../../translations/${locale}.json`, import.meta.url))
|
|
20
|
+
expect(response.ok, `${locale}.json is served`).to.equal(true)
|
|
21
|
+
return response.json()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe('accumulator labels', () => {
|
|
25
|
+
for (const [locale, words] of Object.entries(EXPECTED)) {
|
|
26
|
+
it(`${locale}: max is the largest, min the smallest`, async () => {
|
|
27
|
+
const t = await translations(locale)
|
|
28
|
+
expect(t['label.accumulator_max']).to.equal(words.max)
|
|
29
|
+
expect(t['label.accumulator_min']).to.equal(words.min)
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
it('ko: count is 개수', async () => {
|
|
34
|
+
expect((await translations('ko'))['label.accumulator_count']).to.equal('개수')
|
|
35
|
+
})
|
|
36
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { expect } from '@open-wc/testing'
|
|
2
|
+
|
|
3
|
+
import { DataGridField } from '../src/data-grid/data-grid-field.js'
|
|
4
|
+
import { FilterStyles } from '../src/filters/filter-styles.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A button inside a grid cell is --cell-action-height (26px by default, ADR-0060 decision 6), for its
|
|
8
|
+
* width as well: a second token for the width could say a different number. It still takes no more
|
|
9
|
+
* than a line of text in the row, so one cell with a button does not make every row taller.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const text = (styles: unknown) =>
|
|
13
|
+
(Array.isArray(styles) ? styles : [styles]).map(s => String((s as { cssText?: string }).cssText ?? s)).join('\n')
|
|
14
|
+
|
|
15
|
+
describe('cell action height', () => {
|
|
16
|
+
it('the icon button in a cell reads the cell token for height and width', () => {
|
|
17
|
+
const css = text(DataGridField.styles)
|
|
18
|
+
const rule = css.slice(css.indexOf(':host > button.icon {'))
|
|
19
|
+
|
|
20
|
+
expect(rule).to.match(/^:host > button\.icon \{[^}]*width: var\(--cell-action-height, 26px\);/)
|
|
21
|
+
expect(rule).to.match(/^:host > button\.icon \{[^}]*height: var\(--cell-action-height, 26px\);/)
|
|
22
|
+
expect(rule).to.contain('margin-top: calc((20px - var(--cell-action-height, 26px)) / 2)')
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('filter bar input height', () => {
|
|
27
|
+
it('a grid filter bar: the suite small height in the operato products, natural height elsewhere', () => {
|
|
28
|
+
const css = text(FilterStyles)
|
|
29
|
+
expect(css).to.match(/box-sizing: border-box;\s*height: var\(--suite-form-element-height-small, auto\);/)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/* Elements are compared by presence, not by value: a failing element comparison makes chai render the DOM and hang the runner. */
|
|
2
|
+
import { expect, fixture } from '@open-wc/testing'
|
|
3
|
+
import { html } from 'lit'
|
|
4
|
+
|
|
5
|
+
import '../src/data-grist.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A failed fetch is not an empty list.
|
|
9
|
+
*
|
|
10
|
+
* The provider wrapped the fetch in try/finally with no catch, so a thrown fetch hid the spinner and
|
|
11
|
+
* nothing else: with no rows the grid said "nothing to show", with rows from before it kept them as if
|
|
12
|
+
* they were the answer. Both are a confident wrong statement about data the grid never saw.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
type Rec = { id: string; name: string }
|
|
16
|
+
|
|
17
|
+
const config = {
|
|
18
|
+
columns: [
|
|
19
|
+
{ type: 'string', name: 'id', hidden: true },
|
|
20
|
+
{ type: 'string', name: 'name', header: 'name' }
|
|
21
|
+
],
|
|
22
|
+
pagination: { pages: [20] }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const settle = (ms = 150) => new Promise(resolve => setTimeout(resolve, ms))
|
|
26
|
+
|
|
27
|
+
async function grist(mode: 'GRID' | 'LIST' | 'CARD', handler: () => Promise<unknown>) {
|
|
28
|
+
const el = (await fixture(html`
|
|
29
|
+
<ox-grist style="height: 300px" mode=${mode} .config=${config} .fetchHandler=${handler}></ox-grist>
|
|
30
|
+
`)) as HTMLElement & { fetch(): Promise<void>; updateComplete: Promise<unknown>; renderRoot: ShadowRoot }
|
|
31
|
+
await el.fetch().catch(() => {})
|
|
32
|
+
await settle()
|
|
33
|
+
await el.updateComplete
|
|
34
|
+
return el
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function emptyNote(el: HTMLElement & { renderRoot: ShadowRoot }): HTMLElement | null {
|
|
38
|
+
const body = el.renderRoot.querySelector('#grist') as (HTMLElement & { renderRoot: ShadowRoot }) | null
|
|
39
|
+
const inBody = body?.renderRoot.querySelector('ox-empty-note') as HTMLElement | null
|
|
40
|
+
if (inBody) return inBody
|
|
41
|
+
/* GRID draws the note inside its body element. */
|
|
42
|
+
const gridBody = body?.renderRoot.querySelector('ox-grid-body') as HTMLElement | null
|
|
43
|
+
return (gridBody?.querySelector('ox-empty-note') as HTMLElement | null) ?? null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe('ox-grist when the fetch fails', () => {
|
|
47
|
+
/*
|
|
48
|
+
* Resizing the grid body inside a fixture trips Chrome's benign "ResizeObserver loop completed"
|
|
49
|
+
* error, which mocha reports as a failure. It says nothing about fetch failures; keep it out.
|
|
50
|
+
*/
|
|
51
|
+
const ignoreResizeLoop = (e: ErrorEvent) => {
|
|
52
|
+
if (String(e.message).includes('ResizeObserver loop')) {
|
|
53
|
+
e.stopImmediatePropagation()
|
|
54
|
+
e.preventDefault()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
let previousOnError: OnErrorEventHandler = null
|
|
58
|
+
before(() => {
|
|
59
|
+
window.addEventListener('error', ignoreResizeLoop, true)
|
|
60
|
+
previousOnError = window.onerror
|
|
61
|
+
window.onerror = (message, ...rest) =>
|
|
62
|
+
String(message).includes('ResizeObserver loop') ? true : previousOnError?.call(window, message, ...rest)
|
|
63
|
+
})
|
|
64
|
+
after(() => {
|
|
65
|
+
window.removeEventListener('error', ignoreResizeLoop, true)
|
|
66
|
+
window.onerror = previousOnError
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
for (const mode of ['GRID', 'LIST', 'CARD'] as const) {
|
|
70
|
+
it(`${mode}: says it could not load, not that there is nothing, and retries`, async () => {
|
|
71
|
+
let calls = 0
|
|
72
|
+
const el = await grist(mode, async () => {
|
|
73
|
+
calls++
|
|
74
|
+
throw new Error('server down')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const note = emptyNote(el)
|
|
78
|
+
expect(note, 'a note is drawn').to.exist
|
|
79
|
+
expect(note!.getAttribute('role')).to.equal('alert')
|
|
80
|
+
expect(note!.getAttribute('title')).to.equal('could not load the list')
|
|
81
|
+
|
|
82
|
+
const retry = note!.querySelector('md-text-button') as HTMLElement
|
|
83
|
+
expect(retry, 'retry').to.exist
|
|
84
|
+
const before = calls
|
|
85
|
+
retry.click()
|
|
86
|
+
await settle()
|
|
87
|
+
expect(calls).to.equal(before + 1)
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
it('an empty answer still says empty, without an alert', async () => {
|
|
92
|
+
const el = await grist('GRID', async () => ({ total: 0, records: [] as Rec[] }))
|
|
93
|
+
|
|
94
|
+
const note = emptyNote(el)
|
|
95
|
+
expect(note, 'a note is drawn').to.exist
|
|
96
|
+
expect(note!.hasAttribute('role')).to.equal(false)
|
|
97
|
+
expect(note!.getAttribute('title')).to.equal('nothing here yet.')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('rows from before stay, with a band saying they are not a fresh result; a good fetch clears it', async () => {
|
|
101
|
+
let fail = false
|
|
102
|
+
const el = await grist('GRID', async () => {
|
|
103
|
+
if (fail) throw new Error('server down')
|
|
104
|
+
return { total: 1, records: [{ id: '1', name: 'first' }] }
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
expect(el.renderRoot.querySelector('ox-list-state') === null, 'absent').to.equal(true)
|
|
108
|
+
|
|
109
|
+
fail = true
|
|
110
|
+
await el.fetch().catch(() => {})
|
|
111
|
+
await settle()
|
|
112
|
+
await el.updateComplete
|
|
113
|
+
|
|
114
|
+
const state = el.renderRoot.querySelector('ox-list-state')!
|
|
115
|
+
expect(state, 'failure band').to.exist
|
|
116
|
+
await state.updateComplete
|
|
117
|
+
expect(state.renderRoot.querySelector('[role="alert"]')?.textContent).to.contain('could not refresh')
|
|
118
|
+
|
|
119
|
+
fail = false
|
|
120
|
+
await el.fetch()
|
|
121
|
+
await settle()
|
|
122
|
+
await el.updateComplete
|
|
123
|
+
expect(el.renderRoot.querySelector('ox-list-state') === null, 'absent').to.equal(true)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('the error still reaches whoever awaited the fetch', async () => {
|
|
127
|
+
const el = (await fixture(html`
|
|
128
|
+
<ox-grist mode="GRID" .config=${config} .fetchHandler=${async () => { throw new Error('server down') }}></ox-grist>
|
|
129
|
+
`)) as HTMLElement & { fetch(): Promise<void> }
|
|
130
|
+
|
|
131
|
+
let caught: unknown
|
|
132
|
+
await el.fetch().catch(e => (caught = e))
|
|
133
|
+
expect((caught as Error)?.message).to.equal('server down')
|
|
134
|
+
})
|
|
135
|
+
})
|
package/translations/en.json
CHANGED
|
@@ -3,19 +3,16 @@
|
|
|
3
3
|
"button.save": "save",
|
|
4
4
|
"label.accumulator_avg": "avg",
|
|
5
5
|
"label.accumulator_count": "cnt",
|
|
6
|
-
"label.accumulator_max": "
|
|
7
|
-
"label.accumulator_min": "
|
|
6
|
+
"label.accumulator_max": "max",
|
|
7
|
+
"label.accumulator_min": "min",
|
|
8
8
|
"label.accumulator_sum": "sum",
|
|
9
9
|
"label.filter": "filter",
|
|
10
10
|
"text.grid-cell-input": "{name} input",
|
|
11
11
|
"text.grid-cell-input-plain": "cell input",
|
|
12
|
-
"text.grid-clear-search": "clear the search or filters to see everything",
|
|
13
12
|
"text.grid-filter-from": "{name} filter, from",
|
|
14
13
|
"text.grid-filter-of": "{name} filter",
|
|
15
14
|
"text.grid-filter-to": "{name} filter, to",
|
|
16
|
-
"text.grid-
|
|
17
|
-
"text.grid-nothing-found": "nothing found",
|
|
18
|
-
"text.grid-open-editor": "press to edit",
|
|
15
|
+
"text.grid-open-editor": "select to edit",
|
|
19
16
|
"text.grid-select-all-records": "select all rows",
|
|
20
17
|
"text.grid-select-record": "select row {row}",
|
|
21
18
|
"text.grid-total-records": "{total} in total",
|
package/translations/ja.json
CHANGED
|
@@ -3,19 +3,16 @@
|
|
|
3
3
|
"button.save": "保存",
|
|
4
4
|
"label.accumulator_avg": "平均",
|
|
5
5
|
"label.accumulator_count": "カウント",
|
|
6
|
-
"label.accumulator_max": "
|
|
7
|
-
"label.accumulator_min": "
|
|
6
|
+
"label.accumulator_max": "最大",
|
|
7
|
+
"label.accumulator_min": "最小",
|
|
8
8
|
"label.accumulator_sum": "合計",
|
|
9
9
|
"label.filter": "フィルター",
|
|
10
10
|
"text.grid-cell-input": "{name} 入力",
|
|
11
11
|
"text.grid-cell-input-plain": "セル入力",
|
|
12
|
-
"text.grid-clear-search": "検索語やフィルターを消すと全体が表示されます",
|
|
13
12
|
"text.grid-filter-from": "{name} フィルター 開始値",
|
|
14
13
|
"text.grid-filter-of": "{name} フィルター",
|
|
15
14
|
"text.grid-filter-to": "{name} フィルター 終了値",
|
|
16
|
-
"text.grid-
|
|
17
|
-
"text.grid-nothing-found": "見つかりませんでした",
|
|
18
|
-
"text.grid-open-editor": "押して編集します",
|
|
15
|
+
"text.grid-open-editor": "選択して編集",
|
|
19
16
|
"text.grid-select-all-records": "すべての行を選択",
|
|
20
17
|
"text.grid-select-record": "{row} 行目を選択",
|
|
21
18
|
"text.grid-total-records": "全 {total} 件",
|
package/translations/ko.json
CHANGED
|
@@ -2,20 +2,17 @@
|
|
|
2
2
|
"button.delete": "삭제",
|
|
3
3
|
"button.save": "저장",
|
|
4
4
|
"label.accumulator_avg": "평균",
|
|
5
|
-
"label.accumulator_count": "
|
|
6
|
-
"label.accumulator_max": "
|
|
7
|
-
"label.accumulator_min": "
|
|
5
|
+
"label.accumulator_count": "개수",
|
|
6
|
+
"label.accumulator_max": "최대",
|
|
7
|
+
"label.accumulator_min": "최소",
|
|
8
8
|
"label.accumulator_sum": "합계",
|
|
9
9
|
"label.filter": "필터",
|
|
10
10
|
"text.grid-cell-input": "{name} 입력",
|
|
11
11
|
"text.grid-cell-input-plain": "칸 입력",
|
|
12
|
-
"text.grid-clear-search": "검색어나 필터를 지우면 전체가 보입니다",
|
|
13
12
|
"text.grid-filter-from": "{name} 필터 시작값",
|
|
14
13
|
"text.grid-filter-of": "{name} 필터",
|
|
15
14
|
"text.grid-filter-to": "{name} 필터 끝값",
|
|
16
|
-
"text.grid-
|
|
17
|
-
"text.grid-nothing-found": "찾는 것이 없습니다",
|
|
18
|
-
"text.grid-open-editor": "눌러서 고칩니다",
|
|
15
|
+
"text.grid-open-editor": "선택해 편집",
|
|
19
16
|
"text.grid-select-all-records": "모든 행 선택",
|
|
20
17
|
"text.grid-select-record": "{row}번째 행 선택",
|
|
21
18
|
"text.grid-total-records": "모두 {total}건",
|
package/translations/ms.json
CHANGED
|
@@ -3,19 +3,16 @@
|
|
|
3
3
|
"button.save": "simpan",
|
|
4
4
|
"label.accumulator_avg": "Purata",
|
|
5
5
|
"label.accumulator_count": "Kiraan",
|
|
6
|
-
"label.accumulator_max": "
|
|
7
|
-
"label.accumulator_min": "
|
|
6
|
+
"label.accumulator_max": "Maksimum",
|
|
7
|
+
"label.accumulator_min": "Minimum",
|
|
8
8
|
"label.accumulator_sum": "Jumlah",
|
|
9
9
|
"label.filter": "penapis",
|
|
10
10
|
"text.grid-cell-input": "input {name}",
|
|
11
11
|
"text.grid-cell-input-plain": "input sel",
|
|
12
|
-
"text.grid-clear-search": "kosongkan carian atau penapis untuk melihat semua",
|
|
13
12
|
"text.grid-filter-from": "penapis {name}, dari",
|
|
14
13
|
"text.grid-filter-of": "penapis {name}",
|
|
15
14
|
"text.grid-filter-to": "penapis {name}, hingga",
|
|
16
|
-
"text.grid-
|
|
17
|
-
"text.grid-nothing-found": "tiada apa-apa dijumpai",
|
|
18
|
-
"text.grid-open-editor": "tekan untuk mengedit",
|
|
15
|
+
"text.grid-open-editor": "pilih untuk menyunting",
|
|
19
16
|
"text.grid-select-all-records": "pilih semua baris",
|
|
20
17
|
"text.grid-select-record": "pilih baris {row}",
|
|
21
18
|
"text.grid-total-records": "{total} kesemuanya",
|
package/translations/zh.json
CHANGED
|
@@ -3,19 +3,16 @@
|
|
|
3
3
|
"button.save": "保存",
|
|
4
4
|
"label.accumulator_avg": "平均",
|
|
5
5
|
"label.accumulator_count": "计数",
|
|
6
|
-
"label.accumulator_max": "
|
|
7
|
-
"label.accumulator_min": "
|
|
6
|
+
"label.accumulator_max": "最大",
|
|
7
|
+
"label.accumulator_min": "最小",
|
|
8
8
|
"label.accumulator_sum": "总和",
|
|
9
9
|
"label.filter": "筛选",
|
|
10
10
|
"text.grid-cell-input": "{name} 输入",
|
|
11
11
|
"text.grid-cell-input-plain": "单元格输入",
|
|
12
|
-
"text.grid-clear-search": "清除搜索或筛选即可查看全部",
|
|
13
12
|
"text.grid-filter-from": "{name} 筛选起始值",
|
|
14
13
|
"text.grid-filter-of": "{name} 筛选",
|
|
15
14
|
"text.grid-filter-to": "{name} 筛选结束值",
|
|
16
|
-
"text.grid-
|
|
17
|
-
"text.grid-nothing-found": "没有找到",
|
|
18
|
-
"text.grid-open-editor": "点击进行编辑",
|
|
15
|
+
"text.grid-open-editor": "选择以编辑",
|
|
19
16
|
"text.grid-select-all-records": "选择所有行",
|
|
20
17
|
"text.grid-select-record": "选择第 {row} 行",
|
|
21
18
|
"text.grid-total-records": "共 {total} 条",
|