@kodaris/krubble-components 1.0.52 → 1.0.53
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/custom-elements.json +1811 -192
- package/dist/button/button.js +1 -1
- package/dist/form/select-field/select-field.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/krubble-components.bundled.js +3749 -1866
- package/dist/krubble-components.bundled.js.map +1 -1
- package/dist/krubble-components.bundled.min.js +874 -396
- package/dist/krubble-components.bundled.min.js.map +1 -1
- package/dist/krubble-components.umd.js +4564 -2678
- package/dist/krubble-components.umd.js.map +1 -1
- package/dist/krubble-components.umd.min.js +876 -398
- package/dist/krubble-components.umd.min.js.map +1 -1
- package/dist/table/query.d.ts +63 -0
- package/dist/table/query.d.ts.map +1 -0
- package/dist/table/query.js +1015 -0
- package/dist/table/query.js.map +1 -0
- package/dist/table/table.d.ts +63 -10
- package/dist/table/table.d.ts.map +1 -1
- package/dist/table/table.js +986 -113
- package/dist/table/table.js.map +1 -1
- package/package.json +1 -1
package/custom-elements.json
CHANGED
|
@@ -103,6 +103,30 @@
|
|
|
103
103
|
"module": "./table/table.js"
|
|
104
104
|
}
|
|
105
105
|
},
|
|
106
|
+
{
|
|
107
|
+
"kind": "js",
|
|
108
|
+
"name": "KRQuery",
|
|
109
|
+
"declaration": {
|
|
110
|
+
"name": "KRQuery",
|
|
111
|
+
"module": "./table/query.js"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"kind": "js",
|
|
116
|
+
"name": "KR_OPERATORS",
|
|
117
|
+
"declaration": {
|
|
118
|
+
"name": "KR_OPERATORS",
|
|
119
|
+
"module": "./table/query.js"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"kind": "js",
|
|
124
|
+
"name": "getOperatorsForType",
|
|
125
|
+
"declaration": {
|
|
126
|
+
"name": "getOperatorsForType",
|
|
127
|
+
"module": "./table/query.js"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
106
130
|
{
|
|
107
131
|
"kind": "js",
|
|
108
132
|
"name": "KRSpinner",
|
|
@@ -309,10 +333,239 @@
|
|
|
309
333
|
"default": "class KRTab extends i$2 { constructor() { super(...arguments); /** * Unique identifier for the tab */ this.id = ''; /** * Display label for the tab */ this.label = ''; /** * Badge text displayed next to label (e.g. notification count) */ this.badge = ''; /** * Badge background color */ this.badgeBackground = ''; /** * Badge text color */ this.badgeColor = ''; /** * Whether the tab is disabled */ this.disabled = false; /** * Whether the tab can be dismissed/closed */ this.dismissible = false; /** * Whether this tab is currently active (set by parent) */ this.active = false; } /** * Gets the icon element from the icon slot (if any) */ getIconElement() { return this.querySelector('[slot=\"icon\"]'); } render() { console.log('tab render'); return b `<slot></slot>`; } }",
|
|
310
334
|
"description": "A tab for the kr-tab-group component."
|
|
311
335
|
},
|
|
336
|
+
{
|
|
337
|
+
"kind": "variable",
|
|
338
|
+
"name": "KRSelectField",
|
|
339
|
+
"default": "class KRSelectField extends i$2 { constructor() { super(); /** * The select label text */ this.label = ''; /** * The input name for form submission */ this.name = ''; /** * The currently selected value */ this.value = ''; /** * Placeholder text when no option is selected */ this.placeholder = 'Select an option'; /** * Whether the select is disabled */ this.disabled = false; /** * Whether the field is required */ this.required = false; /** * Whether the field is readonly */ this.readonly = false; /** * Helper text shown below the select */ this.hint = ''; this._isOpen = false; this._highlightedIndex = -1; this._touched = false; this._handleInvalid = (e) => { e.preventDefault(); this._touched = true; }; this._handleOutsideClick = (e) => { if (!e.composedPath().includes(this)) { this._close(); } }; this._handleKeyDown = (e) => { if (!this._isOpen) return; const options = Array.from(this.querySelectorAll('kr-select-option')); switch (e.key) { case 'Escape': this._close(); this._triggerElement?.focus(); break; case 'ArrowDown': e.preventDefault(); if (options.some(o => !o.disabled)) { let newIndex = this._highlightedIndex + 1; while (newIndex < options.length && options[newIndex]?.disabled) newIndex++; if (newIndex < options.length) this._highlightedIndex = newIndex; } break; case 'ArrowUp': e.preventDefault(); { let newIndex = this._highlightedIndex - 1; while (newIndex >= 0 && options[newIndex]?.disabled) newIndex--; if (newIndex >= 0) this._highlightedIndex = newIndex; } break; case 'Enter': e.preventDefault(); if (this._highlightedIndex >= 0 && this._highlightedIndex < options.length) { this._selectOption(options[this._highlightedIndex]); } break; } }; this._internals = this.attachInternals(); } // Form-associated custom element callbacks get form() { return this._internals.form; } get validity() { return this._internals.validity; } get validationMessage() { return this._internals.validationMessage; } get willValidate() { return this._internals.willValidate; } checkValidity() { return this._internals.checkValidity(); } reportValidity() { return this._internals.reportValidity(); } formResetCallback() { this.value = ''; this._touched = false; this._internals.setFormValue(''); this._internals.setValidity({}); } formStateRestoreCallback(state) { this.value = state; } connectedCallback() { super.connectedCallback(); document.addEventListener('click', this._handleOutsideClick); document.addEventListener('keydown', this._handleKeyDown); this.addEventListener('invalid', this._handleInvalid); } firstUpdated() { this._updateValidity(); } updated(changedProperties) { if (changedProperties.has('required') || changedProperties.has('value')) { this._updateValidity(); } } disconnectedCallback() { super.disconnectedCallback(); document.removeEventListener('click', this._handleOutsideClick); document.removeEventListener('keydown', this._handleKeyDown); this.removeEventListener('invalid', this._handleInvalid); } _toggle() { if (this.disabled || this.readonly) return; if (this._isOpen) { this._close(); } else { this._isOpen = true; const options = Array.from(this.querySelectorAll('kr-select-option')); this._highlightedIndex = options.findIndex(o => o.value === this.value); // Position the fixed dropdown relative to the trigger requestAnimationFrame(() => { const dropdown = this.shadowRoot?.querySelector('.select-dropdown'); if (dropdown) { const triggerRect = this._triggerElement.getBoundingClientRect(); const spaceBelow = window.innerHeight - triggerRect.bottom - 4 - 8; dropdown.style.top = triggerRect.bottom + 4 + 'px'; dropdown.style.left = triggerRect.left + 'px'; dropdown.style.width = triggerRect.width + 'px'; dropdown.style.maxHeight = spaceBelow + 'px'; } }); } } _close() { this._isOpen = false; this._highlightedIndex = -1; } _selectOption(option) { if (option.disabled) return; this.value = option.value; this._internals.setFormValue(this.value); this._updateValidity(); this.dispatchEvent(new Event('change', { bubbles: true, composed: true })); this._close(); this._triggerElement?.focus(); } _handleBlur() { this._touched = true; this._updateValidity(); } _updateValidity() { if (this.required && !this.value) { this._internals.setValidity({ valueMissing: true }, 'Please select an option', this._triggerElement); } else { this._internals.setValidity({}); } } render() { const options = Array.from(this.querySelectorAll('kr-select-option')); const selectedLabel = options.find(o => o.value === this.value)?.label; return b ` <div class=\"wrapper\"> ${this.label ? b ` <label> ${this.label} ${this.required ? b `<span class=\"required\" aria-hidden=\"true\">*</span>` : ''} </label> ` : A} <div class=\"select-wrapper\"> <button class=${e$1({ 'select-trigger': true, 'select-trigger--open': this._isOpen, 'select-trigger--invalid': this._touched && this.required && !this.value, })} type=\"button\" ?disabled=${this.disabled} aria-haspopup=\"listbox\" aria-expanded=${this._isOpen} @click=${this._toggle} @blur=${this._handleBlur} > <span class=${e$1({ 'select-value': true, 'select-placeholder': !selectedLabel })}> ${selectedLabel || this.placeholder} </span> <svg class=${e$1({ 'chevron-icon': true, 'select-icon': true, 'select-icon--open': this._isOpen })} viewBox=\"0 0 24 24\" fill=\"currentColor\" > <path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z\"/> </svg> </button> <div class=${e$1({ 'select-dropdown': true, 'hidden': !this._isOpen })} role=\"listbox\"> <div class=\"select-options\"> ${options.length === 0 ? b `<div class=\"select-empty\">No options available</div>` : options.map((option, idx) => { const isSelected = option.value === this.value; return b ` <div class=${e$1({ 'select-option': true, 'select-option--selected': isSelected, 'select-option--disabled': option.disabled, 'select-option--highlighted': idx === this._highlightedIndex, })} role=\"option\" aria-selected=${isSelected} @click=${() => this._selectOption(option)} @mouseenter=${() => (this._highlightedIndex = idx)} > ${option.label} </div> `; })} </div> </div> </div> ${this._touched && this.required && !this.value ? b `<div class=\"validation-message\">Please select an option</div>` : this.hint ? b `<div class=\"hint\">${this.hint}</div>` : ''} </div> <div class=\"options-slot\"> <slot @slotchange=${() => this.requestUpdate()}></slot> </div> `; } // Public methods for programmatic control focus() { this._triggerElement?.focus(); } blur() { this._triggerElement?.blur(); } }",
|
|
340
|
+
"description": "A select dropdown component that works with native browser forms.\n\nUses ElementInternals for form association, allowing the component\nto participate in form submission, validation, and reset."
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
"kind": "variable",
|
|
344
|
+
"name": "KRSelectOption",
|
|
345
|
+
"default": "class KRSelectOption extends i$2 { constructor() { super(...arguments); /** * The option value */ this.value = ''; /** * Whether the option is disabled */ this.disabled = false; } /** Gets the label text from the slot */ get label() { return this.textContent?.trim() || ''; } render() { return b `<slot></slot>`; } }",
|
|
346
|
+
"description": "An option for the kr-select-field component."
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"kind": "variable",
|
|
350
|
+
"name": "KR_OPERATORS",
|
|
351
|
+
"type": {
|
|
352
|
+
"text": "object"
|
|
353
|
+
},
|
|
354
|
+
"default": "{ equals: { key: 'equals', type: 'comparison', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Equals' }, n_equals: { key: 'n_equals', type: 'comparison', dataTypes: ['string', 'number', 'date', 'boolean'], label: \"Doesn't equal\" }, contains: { key: 'contains', type: 'comparison', dataTypes: ['string'], label: 'Contains' }, n_contains: { key: 'n_contains', type: 'comparison', dataTypes: ['string'], label: \"Doesn't contain\" }, starts_with: { key: 'starts_with', type: 'comparison', dataTypes: ['string'], label: 'Starts with' }, ends_with: { key: 'ends_with', type: 'comparison', dataTypes: ['string'], label: 'Ends with' }, less_than: { key: 'less_than', type: 'comparison', dataTypes: ['number', 'date'], label: 'Less than' }, less_than_equal: { key: 'less_than_equal', type: 'comparison', dataTypes: ['number', 'date'], label: 'Less than or equal' }, greater_than: { key: 'greater_than', type: 'comparison', dataTypes: ['number', 'date'], label: 'Greater than' }, greater_than_equal: { key: 'greater_than_equal', type: 'comparison', dataTypes: ['number', 'date'], label: 'Greater than or equal' }, between: { key: 'between', type: 'range', dataTypes: ['number', 'date'], label: 'Between' }, in: { key: 'in', type: 'list', dataTypes: ['string', 'number'], label: 'In' }, empty: { key: 'empty', type: 'nil', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Empty' }, n_empty: { key: 'n_empty', type: 'nil', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Not empty' }, }",
|
|
355
|
+
"description": "Data-driven operator metadata map"
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"kind": "function",
|
|
359
|
+
"name": "getOperatorsForType",
|
|
360
|
+
"parameters": [
|
|
361
|
+
{
|
|
362
|
+
"name": "columnType"
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
"description": "Returns the list of operators available for a given column type"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"kind": "class",
|
|
369
|
+
"description": "",
|
|
370
|
+
"name": "KRQuery",
|
|
371
|
+
"members": [
|
|
372
|
+
{
|
|
373
|
+
"kind": "method",
|
|
374
|
+
"name": "setKql",
|
|
375
|
+
"parameters": [
|
|
376
|
+
{
|
|
377
|
+
"name": "kql"
|
|
378
|
+
}
|
|
379
|
+
],
|
|
380
|
+
"description": "Parse a KQL text string and populate operator/value/values"
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"kind": "method",
|
|
384
|
+
"name": "setOperator",
|
|
385
|
+
"parameters": [
|
|
386
|
+
{
|
|
387
|
+
"name": "operator"
|
|
388
|
+
}
|
|
389
|
+
]
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"kind": "method",
|
|
393
|
+
"name": "setValue",
|
|
394
|
+
"parameters": [
|
|
395
|
+
{
|
|
396
|
+
"name": "value"
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"name": "specificity"
|
|
400
|
+
}
|
|
401
|
+
]
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"kind": "method",
|
|
405
|
+
"name": "setStart",
|
|
406
|
+
"parameters": [
|
|
407
|
+
{
|
|
408
|
+
"name": "value"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"name": "specificity"
|
|
412
|
+
}
|
|
413
|
+
]
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"kind": "method",
|
|
417
|
+
"name": "setEnd",
|
|
418
|
+
"parameters": [
|
|
419
|
+
{
|
|
420
|
+
"name": "value"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"name": "specificity"
|
|
424
|
+
}
|
|
425
|
+
]
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"kind": "method",
|
|
429
|
+
"name": "clear"
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"kind": "method",
|
|
433
|
+
"name": "isEmpty"
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"kind": "method",
|
|
437
|
+
"name": "has",
|
|
438
|
+
"parameters": [
|
|
439
|
+
{
|
|
440
|
+
"name": "val"
|
|
441
|
+
}
|
|
442
|
+
],
|
|
443
|
+
"description": "Returns true if the value array contains the given value. Only applies to 'in' operator."
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"kind": "method",
|
|
447
|
+
"name": "toggle",
|
|
448
|
+
"parameters": [
|
|
449
|
+
{
|
|
450
|
+
"name": "val"
|
|
451
|
+
}
|
|
452
|
+
],
|
|
453
|
+
"description": "Adds or removes a value from the 'in' list and rebuilds text/kql."
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"kind": "method",
|
|
457
|
+
"name": "isValid"
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"kind": "method",
|
|
461
|
+
"name": "toSolrData",
|
|
462
|
+
"description": "Converts this filter to a Solr filter field object, or null if invalid"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
"kind": "method",
|
|
466
|
+
"name": "toDbParams",
|
|
467
|
+
"description": "Converts this filter to a DB filter field object, or null if invalid"
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
"kind": "method",
|
|
471
|
+
"name": "_buildText"
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
"kind": "method",
|
|
475
|
+
"name": "_format",
|
|
476
|
+
"parameters": [
|
|
477
|
+
{
|
|
478
|
+
"name": "value"
|
|
479
|
+
}
|
|
480
|
+
]
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
"kind": "method",
|
|
484
|
+
"name": "_parse",
|
|
485
|
+
"parameters": [
|
|
486
|
+
{
|
|
487
|
+
"name": "text"
|
|
488
|
+
}
|
|
489
|
+
],
|
|
490
|
+
"description": "Parse a text value according to this query's type"
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"kind": "method",
|
|
494
|
+
"name": "_parseDate",
|
|
495
|
+
"parameters": [
|
|
496
|
+
{
|
|
497
|
+
"name": "input"
|
|
498
|
+
}
|
|
499
|
+
],
|
|
500
|
+
"description": "Parse a date string into a UTC Date"
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
"kind": "method",
|
|
504
|
+
"name": "_buildKql",
|
|
505
|
+
"description": "Build a KQL display string from current operator/value state"
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
"kind": "field",
|
|
509
|
+
"name": "field",
|
|
510
|
+
"type": {
|
|
511
|
+
"text": "string"
|
|
512
|
+
},
|
|
513
|
+
"default": "''"
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
"kind": "field",
|
|
517
|
+
"name": "operator",
|
|
518
|
+
"type": {
|
|
519
|
+
"text": "string"
|
|
520
|
+
},
|
|
521
|
+
"default": "'equals'"
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
"kind": "field",
|
|
525
|
+
"name": "value",
|
|
526
|
+
"type": {
|
|
527
|
+
"text": "null"
|
|
528
|
+
},
|
|
529
|
+
"default": "null"
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
"kind": "field",
|
|
533
|
+
"name": "kql",
|
|
534
|
+
"type": {
|
|
535
|
+
"text": "string"
|
|
536
|
+
},
|
|
537
|
+
"default": "''"
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
"kind": "field",
|
|
541
|
+
"name": "text",
|
|
542
|
+
"type": {
|
|
543
|
+
"text": "string"
|
|
544
|
+
},
|
|
545
|
+
"default": "''"
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"kind": "field",
|
|
549
|
+
"name": "type",
|
|
550
|
+
"type": {
|
|
551
|
+
"text": "string"
|
|
552
|
+
},
|
|
553
|
+
"default": "''"
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
"kind": "field",
|
|
557
|
+
"name": "specificity",
|
|
558
|
+
"type": {
|
|
559
|
+
"text": "array"
|
|
560
|
+
},
|
|
561
|
+
"default": "[]"
|
|
562
|
+
}
|
|
563
|
+
]
|
|
564
|
+
},
|
|
312
565
|
{
|
|
313
566
|
"kind": "variable",
|
|
314
567
|
"name": "KRTable",
|
|
315
|
-
"default": "class KRTable extends i$2 { constructor() { super(...arguments); /** * Internal flag to switch between scroll edge modes: * - 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge) * - 'edge': Padding scrolls with content, allowing table to reach edges when scrolling */ this._scrollStyle = 'overlay'; this._data = []; this._dataState = 'idle'; this._page = 1; this._pageSize = 50; this._totalItems = 0; this._totalPages = 0; this._searchQuery = ''; this._canScrollLeft = false; this._canScrollRight = false; this._canScrollHorizontal = false; this._columnPickerOpen = false; this._displayedColumns = []; this._resizing = null; this._resizeObserver = null; this._searchPositionLocked = false; this._def = { columns: [] }; this.def = { columns: [] }; this._handleClickOutsideColumnPicker = (e) => { if (!this._columnPickerOpen) return; const path = e.composedPath(); const picker = this.shadowRoot?.querySelector('.column-picker-wrapper'); if (picker && !path.includes(picker)) { this._columnPickerOpen = false; } }; this._handleResizeMove = (e) => { if (!this._resizing) return; const col = this._def.columns.find(c => c.id === this._resizing.columnId); if (col) { const newWidth = this._resizing.startWidth + (e.clientX - this._resizing.startX); col.width = `${Math.min(900, Math.max(50, newWidth))}px`; this.requestUpdate(); } }; this._handleResizeEnd = () => { this._resizing = null; document.removeEventListener('mousemove', this._handleResizeMove); document.removeEventListener('mouseup', this._handleResizeEnd); }; } connectedCallback() { super.connectedCallback(); this.classList.toggle('kr-table--scroll-overlay', this._scrollStyle === 'overlay'); this.classList.toggle('kr-table--scroll-edge', this._scrollStyle === 'edge'); this._fetch(); this._initRefresh(); document.addEventListener('click', this._handleClickOutsideColumnPicker); this._resizeObserver = new ResizeObserver(() => { // Unlock and recalculate on resize since layout changes this._searchPositionLocked = false; this._updateSearchPosition(); }); this._resizeObserver.observe(this); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._refreshTimer); document.removeEventListener('click', this._handleClickOutsideColumnPicker); this._resizeObserver?.disconnect(); } willUpdate(changedProperties) { if (changedProperties.has('def')) { // Copy user's def and normalize action columns this._def = { ...this.def, columns: this.def.columns.map(col => { if (col.type === 'actions') { return { ...col, label: col.label ?? '', sticky: 'right', resizable: false }; } return { ...col }; }) }; this._displayedColumns = this._def.displayedColumns || this._def.columns.map(c => c.id); this._fetch(); this._initRefresh(); } } updated(changedProperties) { this._updateScrollFlags(); this._syncSlottedContent(); } /** Syncs light DOM content for cells with custom render functions */ _syncSlottedContent() { const columns = this.getDisplayedColumns().filter(col => col.render); if (!columns.length) return; // Clear old slotted content this.querySelectorAll('[slot^=\"cell-\"]').forEach(el => el.remove()); // Create new slotted content this._data.forEach((row, rowIndex) => { columns.forEach(col => { const result = col.render(row); if (!result) return; const el = document.createElement('span'); el.slot = `cell-${rowIndex}-${col.id}`; if (col.type === 'actions') { el.style.display = 'flex'; el.style.gap = '8px'; } if (typeof result === 'string') { el.innerHTML = result; } else { D(result, el); } this.appendChild(el); }); }); } // ---------------------------------------------------------------------------- // Public Interface // ---------------------------------------------------------------------------- refresh() { this._fetch(); } goToPrevPage() { if (this._page > 1) { this._page--; this._fetch(); } } goToNextPage() { if (this._page < this._totalPages) { this._page++; this._fetch(); } } goToPage(page) { if (page >= 1 && page <= this._totalPages) { this._page = page; this._fetch(); } } // ---------------------------------------------------------------------------- // Data Fetching // ---------------------------------------------------------------------------- /** * Fetches data from the API and updates the table. * Shows a loading spinner while fetching, then displays rows on success * or an error snackbar on failure. * Request/response format depends on dataSource.mode (solr, opensearch, db). */ _fetch() { if (!this._def.dataSource) return; this._dataState = 'loading'; // Build request based on mode let request; switch (this._def.dataSource.mode) { case 'opensearch': throw Error('Opensearch not supported yet'); case 'db': request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; if (this._searchQuery?.trim().length) { this._def.columns.filter(col => col.searchable).forEach(col => { request.queryFields.push({ name: col.id, operation: 'CONTAINS', value: this._searchQuery, and: false }); }); } break; default: // solr request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; if (this._searchQuery?.trim().length) { request.queryFields.push({ name: '_text_', operation: 'IS', value: escapeSolrQuery(this._searchQuery) }); } } this._def.dataSource.fetch(request) .then(response => { // Parse response based on mode switch (this._def.dataSource?.mode) { case 'opensearch': { throw Error('Opensearch not supported yet'); } case 'db': { const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; break; } default: { // solr const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; } } this._dataState = 'success'; this._updateSearchPosition(); }) .catch(err => { this._dataState = 'error'; KRSnackbar.show({ message: err instanceof Error ? err.message : 'Failed to load data', type: 'error' }); }); } /** * Sets up auto-refresh so the table automatically fetches fresh data * at a regular interval (useful for dashboards, monitoring views). * Configured via def.refreshInterval in milliseconds. */ _initRefresh() { clearInterval(this._refreshTimer); if (this._def.refreshInterval && this._def.refreshInterval > 0) { this._refreshTimer = window.setInterval(() => { this._fetch(); }, this._def.refreshInterval); } } _handleSearch(e) { const input = e.target; this._searchQuery = input.value; this._page = 1; this._fetch(); } _getGridTemplateColumns() { const cols = this.getDisplayedColumns(); return cols.map((col) => { // If column has explicit width, use it if (col.width) { return col.width; } // Actions columns: fit content without minimum if (col.type === 'actions') { return 'max-content'; } // No width specified - use content-based sizing with minimum return 'minmax(80px, auto)'; }).join(' '); } /** * Updates search position to be centered with equal gaps from title and tools. * On first call: resets to flex centering, measures position, then locks with fixed margin. * Subsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize). */ _updateSearchPosition() { // Skip if already locked (prevents shifts on pagination changes) if (this._searchPositionLocked) return; const search = this.shadowRoot?.querySelector('.search'); const searchField = search?.querySelector('.search-field'); if (!search || !searchField) return; // Reset to flex centering search.style.justifyContent = 'center'; searchField.style.marginLeft = ''; requestAnimationFrame(() => { const searchRect = search.getBoundingClientRect(); const fieldRect = searchField.getBoundingClientRect(); // Calculate how far from the left of search container the field currently is const currentOffset = fieldRect.left - searchRect.left; // Lock position: switch to flex-start and use fixed margin search.style.justifyContent = 'flex-start'; searchField.style.marginLeft = `${currentOffset}px`; // Mark as locked so pagination changes don't shift the search this._searchPositionLocked = true; }); } // ---------------------------------------------------------------------------- // Columns // ---------------------------------------------------------------------------- _toggleColumnPicker() { this._columnPickerOpen = !this._columnPickerOpen; } _toggleColumn(columnId) { if (this._displayedColumns.includes(columnId)) { this._displayedColumns = this._displayedColumns.filter(id => id !== columnId); } else { this._displayedColumns = [...this._displayedColumns, columnId]; } } // Clear any existing text selection on mousedown so we only detect // selections made during this click gesture, not stale selections from elsewhere _handleRowMouseDown() { if (!this._def.rowClickable) { return; } window.getSelection()?.removeAllRanges(); } _handleRowClick(row, rowIndex) { if (!this._def.rowClickable) { return; } const selection = window.getSelection(); if (selection && selection.toString().length > 0) { return; } this.dispatchEvent(new CustomEvent('row-click', { detail: { row, rowIndex }, bubbles: true, composed: true })); } // When a user toggles a column on via the column picker, it gets appended // to _displayedColumns. By mapping over _displayedColumns (not def.columns), // the new column appears at the right edge of the table instead of jumping // back to its original position in the column definition. // Actions columns are always moved to the end. getDisplayedColumns() { return this._displayedColumns .map(id => this._def.columns.find(col => col.id === id)) .sort((a, b) => { if (a.type === 'actions' && b.type !== 'actions') return 1; if (a.type !== 'actions' && b.type === 'actions') return -1; return 0; }); } // ---------------------------------------------------------------------------- // Scrolling // ---------------------------------------------------------------------------- /** * Scroll event handler that updates scroll flags in real-time as user scrolls. * Updates shadow indicators to show if more content exists left/right. */ _handleScroll(e) { const container = e.target; this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollLeft < container.scrollWidth - container.clientWidth - 1; } /** * Updates scroll state flags for the table content container. * - _canScrollLeft: true if scrolled right (can scroll back left) * - _canScrollRight: true if more content exists to the right * - _canScrollHorizontal: true if content is wider than container * These flags control scroll shadow indicators and CSS classes. */ _updateScrollFlags() { const container = this.shadowRoot?.querySelector('.content'); if (container) { this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollWidth > container.clientWidth && container.scrollLeft < container.scrollWidth - container.clientWidth - 1; this._canScrollHorizontal = container.scrollWidth > container.clientWidth; } this.classList.toggle('kr-table--scroll-left-available', this._canScrollLeft); this.classList.toggle('kr-table--scroll-right-available', this._canScrollRight); this.classList.toggle('kr-table--scroll-horizontal-available', this._canScrollHorizontal); this.classList.toggle('kr-table--sticky-left', this.getDisplayedColumns().some(c => c.sticky === 'left')); this.classList.toggle('kr-table--sticky-right', this.getDisplayedColumns().some(c => c.sticky === 'right')); } // ---------------------------------------------------------------------------- // Column Resizing // ---------------------------------------------------------------------------- _handleResizeStart(e, columnId) { e.preventDefault(); const headerCell = this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${columnId}\"]`); this._resizing = { columnId, startX: e.clientX, startWidth: headerCell?.offsetWidth || 200 }; document.addEventListener('mousemove', this._handleResizeMove); document.addEventListener('mouseup', this._handleResizeEnd); } // ---------------------------------------------------------------------------- // Header // ---------------------------------------------------------------------------- _handleAction(action) { if (action.href) { return; } this.dispatchEvent(new CustomEvent('action', { detail: { action: action.id }, bubbles: true, composed: true })); } // ---------------------------------------------------------------------------- // Rendering // ---------------------------------------------------------------------------- _renderCellContent(column, row, rowIndex) { const value = row[column.id]; if (column.render) { // Use slot to project content from light DOM so external styles apply return b `<slot name=\"cell-${rowIndex}-${column.id}\"></slot>`; } if (value === null || value === undefined) { return ''; } switch (column.type) { case 'number': return typeof value === 'number' ? value.toLocaleString() : String(value); case 'currency': return typeof value === 'number' ? value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }) : String(value); case 'date': { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(value)) { // MySQL datetime format (UTC): \"2026-01-28 01:33:44:517\" // Replace last colon before ms with dot, append Z for UTC const isoString = value.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/, '$1.$2').replace(' ', 'T') + 'Z'; date = new Date(isoString); } else { date = new Date(value); } // Show date and time for datetime values return date.toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }); } case 'boolean': if (value === true) return 'Yes'; if (value === false) return 'No'; return ''; default: return String(value); } } /** * Returns CSS classes for a header cell based on column config. */ _getHeaderCellClasses(column, index) { return { 'header-cell': true, 'header-cell--align-center': column.align === 'center', 'header-cell--align-right': column.align === 'right', 'header-cell--sticky-left': column.sticky === 'left', 'header-cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'header-cell--sticky-right': column.sticky === 'right', 'header-cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns CSS classes for a table cell based on column config: * - Alignment (center, right) * - Sticky positioning (left, right) * - Border classes for the last left-sticky or first right-sticky column */ _getCellClasses(column, index) { return { 'cell': true, 'cell--actions': column.type === 'actions', 'cell--align-center': column.align === 'center', 'cell--align-right': column.align === 'right', 'cell--sticky-left': column.sticky === 'left', 'cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'cell--sticky-right': column.sticky === 'right', 'cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns inline styles for a table cell: * - Width (from column config or default 150px) * - Min-width (if specified) * - Left/right offset for sticky columns (calculated from widths of preceding sticky columns) */ _getCellStyle(column, index) { const styles = {}; if (column.sticky === 'left') { let leftOffset = 0; for (let i = 0; i < index; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'left') { leftOffset += parseInt(col.width || '0', 10); } } styles.left = `${leftOffset}px`; } if (column.sticky === 'right') { let rightOffset = 0; for (let i = index + 1; i < this.getDisplayedColumns().length; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'right') { rightOffset += parseInt(col.width || '0', 10); } } styles.right = `${rightOffset}px`; } return styles; } /** * Renders the pagination controls: * - Previous page arrow (disabled on first page) * - Range text showing \"1-50 of 150\" format * - Next page arrow (disabled on last page) * * Hidden when there's no data or all data fits on one page. */ _renderPagination() { const start = (this._page - 1) * this._pageSize + 1; const end = Math.min(this._page * this._pageSize, this._totalItems); return b ` <div class=\"pagination\"> <span class=\"pagination-icon ${this._page === 1 ? 'pagination-icon--disabled' : ''}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${start}-${end} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page === this._totalPages ? 'pagination-icon--disabled' : ''}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `; } /** * Renders the header toolbar containing: * - Title (left) * - Search bar with view selector dropdown (center) * - Tools (right): page navigation, refresh button, column visibility picker, actions dropdown * * Hidden when there's no title, no actions, and data fits on one page. */ _renderHeader() { if (!this._def.title && !this._def.actions?.length && this._totalPages <= 1) { return A; } return b ` <div class=\"header\"> <div class=\"title\">${this._def.title ?? ''}</div> ${this._def.dataSource?.mode === 'db' && !this._def.columns.some(col => col.searchable) ? b `<div class=\"search\"></div>` : b ` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${() => this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen ? 'open' : ''}\"> ${[...this._def.columns].filter(col => col.type !== 'actions').sort((a, b) => (a.label ?? a.id).localeCompare(b.label ?? b.id)).map(col => b ` <div class=\"column-picker-item\" @click=${() => this._toggleColumn(col.id)}> <div class=\"column-picker-checkbox ${this._displayedColumns.includes(col.id) ? 'checked' : ''}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${col.label ?? col.id}</span> </div> `)} </div> </div> ${this._def.actions?.length === 1 ? b ` <kr-button class=\"actions\" .href=${this._def.actions[0].href} .target=${this._def.actions[0].target} @click=${() => this._handleAction(this._def.actions[0])} > ${this._def.actions[0].label} </kr-button> ` : this._def.actions?.length ? b ` <kr-button class=\"actions\" .options=${this._def.actions.map(a => ({ id: a.id, label: a.label }))} @option-select=${(e) => this._handleAction({ id: e.detail.id, label: e.detail.label })} > Actions </kr-button> ` : A} </div> </div> `; } /** Renders status message (loading, error, empty) */ _renderStatus() { if (this._dataState === 'loading' && this._data.length === 0) { return b `<div class=\"status\">Loading...</div>`; } if (this._dataState === 'error' && this._data.length === 0) { return b `<div class=\"status status--error\">Error loading data</div>`; } if (this._data.length === 0) { return b `<div class=\"status\">No data available</div>`; } return A; } /** Renders the scrollable data grid with column headers and rows. */ _renderTable() { return b ` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getHeaderCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} >${col.label ?? col.id}${col.resizable !== false ? b `<div class=\"header-cell__resize\" @mousedown=${(e) => this._handleResizeStart(e, col.id)} ></div>` : A}</div> `)} </div> ${this._data.map((row, rowIndex) => { const cells = this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} > ${this._renderCellContent(col, row, rowIndex)} </div> `); if (this._def.rowHref) { return b ` <a href=${this._def.rowHref(row)} class=${e$1({ 'row': true, 'row--clickable': true, 'row--link': true })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</a> `; } return b ` <div class=${e$1({ 'row': true, 'row--clickable': !!this._def.rowClickable })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</div> `; })} </div> </div> </div> `; } /** * Renders a data table with: * - Header bar with title, search input with view selector, and tools (pagination, refresh, column visibility, actions dropdown) * - Scrollable grid with sticky header row and optional sticky left/right columns * - Loading, error message, or empty state when no data */ render() { if (!this._def.columns.length) { return b `<slot></slot>`; } return b ` ${this._renderHeader()} ${this._renderTable()} `; } }"
|
|
568
|
+
"default": "class KRTable extends i$2 { constructor() { super(...arguments); /** * Internal flag to switch between scroll edge modes: * - 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge) * - 'edge': Padding scrolls with content, allowing table to reach edges when scrolling */ this._scrollStyle = 'overlay'; this._data = []; this._dataState = 'idle'; this._page = 1; this._pageSize = 50; this._totalItems = 0; this._totalPages = 0; this._searchQuery = ''; this._canScrollLeft = false; this._canScrollRight = false; this._canScrollHorizontal = false; this._columnPickerOpen = false; this._filterPanelOpened = null; this._filterPanelTab = 'filter'; this._buckets = new Map(); this._filterPanelPos = { top: 0, left: 0 }; this._resizing = null; this._resizeObserver = null; this._searchPositionLocked = false; this._model = new KRTableModel(); this.def = { columns: [] }; this._handleClickOutside = (e) => { const path = e.composedPath(); if (this._columnPickerOpen) { const picker = this.shadowRoot?.querySelector('.column-picker-wrapper'); if (picker && !path.includes(picker)) { this._columnPickerOpen = false; } } if (this._filterPanelOpened) { if (!path.some((el) => el.classList?.contains('filter-panel'))) { this._handleFilterApply(); } } }; this._handleResizeMove = (e) => { if (!this._resizing) return; const col = this._model.columns.find(c => c.id === this._resizing.columnId); if (col) { const newWidth = this._resizing.startWidth + (e.clientX - this._resizing.startX); col.width = `${Math.min(900, Math.max(50, newWidth))}px`; this.requestUpdate(); } }; this._handleResizeEnd = () => { this._resizing = null; document.removeEventListener('mousemove', this._handleResizeMove); document.removeEventListener('mouseup', this._handleResizeEnd); }; } connectedCallback() { super.connectedCallback(); this.classList.toggle('kr-table--scroll-overlay', this._scrollStyle === 'overlay'); this.classList.toggle('kr-table--scroll-edge', this._scrollStyle === 'edge'); this._fetch(); this._initRefresh(); document.addEventListener('click', this._handleClickOutside); this._resizeObserver = new ResizeObserver(() => { // Unlock and recalculate on resize since layout changes this._searchPositionLocked = false; this._updateSearchPosition(); }); this._resizeObserver.observe(this); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._refreshTimer); document.removeEventListener('click', this._handleClickOutside); this._resizeObserver?.disconnect(); } willUpdate(changedProperties) { if (changedProperties.has('def')) { // Build internal model from user-provided def this._model = new KRTableModel(); if (this.def.title) { this._model.title = this.def.title; } if (this.def.actions) { this._model.actions = this.def.actions; } if (this.def.data) { this._model.data = this.def.data; } if (this.def.dataSource) { this._model.dataSource = this.def.dataSource; } if (typeof this.def.refreshInterval === 'number') { this._model.refreshInterval = this.def.refreshInterval; } if (typeof this.def.pageSize === 'number') { this._model.pageSize = this.def.pageSize; } if (this.def.rowClickable) { this._model.rowClickable = this.def.rowClickable; } if (this.def.rowHref) { this._model.rowHref = this.def.rowHref; } this._model.columns = this.def.columns.map(col => { const column = { ...col, filter: null }; if (!column.type) { column.type = 'string'; } if (column.type === 'actions') { column.label = col.label ?? ''; column.sticky = 'right'; column.resizable = false; return column; } if (col.filterable || col.facetable) { column.filter = new KRQuery(); column.filter.field = col.id; column.filter.type = column.type; if (col.facetable && !col.filterable) { column.filter.operator = 'in'; column.filter.value = []; } else if (column.filter.type === 'string') { column.filter.operator = 'contains'; } } return column; }); if (this.def.displayedColumns) { this._model.displayedColumns = this.def.displayedColumns; } else { this._model.displayedColumns = this._model.columns.map(c => c.id); } this._fetch(); this._initRefresh(); } } updated(changedProperties) { this._updateScrollFlags(); this._syncSlottedContent(); } /** Syncs light DOM content for cells with custom render functions */ _syncSlottedContent() { const columns = this.getDisplayedColumns().filter(col => col.render); if (!columns.length) return; // Clear old slotted content this.querySelectorAll('[slot^=\"cell-\"]').forEach(el => el.remove()); // Create new slotted content this._data.forEach((row, rowIndex) => { columns.forEach(col => { const result = col.render(row); if (!result) return; const el = document.createElement('span'); el.slot = `cell-${rowIndex}-${col.id}`; if (col.type === 'actions') { el.style.display = 'flex'; el.style.gap = '8px'; } if (typeof result === 'string') { el.innerHTML = result; } else { D(result, el); } this.appendChild(el); }); }); } // ---------------------------------------------------------------------------- // Public Interface // ---------------------------------------------------------------------------- refresh() { this._fetch(); } goToPrevPage() { if (this._page > 1) { this._page--; this._fetch(); } } goToNextPage() { if (this._page < this._totalPages) { this._page++; this._fetch(); } } goToPage(page) { if (page >= 1 && page <= this._totalPages) { this._page = page; this._fetch(); } } // ---------------------------------------------------------------------------- // Data Fetching // ---------------------------------------------------------------------------- _toSolrData() { const request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } const filterData = col.filter.toSolrData(); if (col.facetable && col.filter.operator === 'in') { filterData.tagged = true; } request.filterFields.push(filterData); } for (const col of this._model.columns) { if (!col.facetable) { continue; } request.facetFields.push({ name: col.id, type: 'FIELD', limit: 100, sort: 'count', minimumCount: 1 }); } if (this._searchQuery?.trim().length) { request.queryFields.push({ name: '_text_', operation: 'IS', value: termify(this._searchQuery, false) }); } return request; } _toDbParams() { const request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } request.filterFields.push(col.filter.toDbParams()); } if (this._searchQuery?.trim().length) { this._model.columns.filter(col => col.searchable).forEach(col => { request.queryFields.push({ name: col.id, operation: 'CONTAINS', value: this._searchQuery, and: false }); }); } return request; } /** * Fetches data from the API and updates the table. * Shows a loading spinner while fetching, then displays rows on success * or an error snackbar on failure. * Request/response format depends on dataSource.mode (solr, opensearch, db). */ _fetch() { if (this._model.data) { this._data = this._model.data; this._totalItems = this._model.data.length; this._totalPages = Math.ceil(this._model.data.length / this._pageSize); this._dataState = 'success'; return; } if (!this._model.dataSource) return; this._dataState = 'loading'; let request; if (this._model.dataSource.mode === 'db') { request = this._toDbParams(); } else { request = this._toSolrData(); } this._model.dataSource.fetch(request) .then(response => { // Parse response based on mode switch (this._model.dataSource?.mode) { case 'opensearch': { throw Error('Opensearch not supported yet'); } case 'db': { const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; break; } default: { // solr const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; this._parseFacetResults(res); } } this._dataState = 'success'; this._updateSearchPosition(); }) .catch(err => { this._dataState = 'error'; KRSnackbar.show({ message: err instanceof Error ? err.message : 'Failed to load data', type: 'error' }); }); } _parseFacetResults(response) { if (!response.data.facetFields) { return; } for (const col of this._model.columns) { if (!col.facetable) { continue; } const rawBuckets = response.data.facetFields[col.id]; if (!rawBuckets) { this._buckets.set(col.id, []); continue; } const buckets = []; for (const raw of rawBuckets) { // Solr returns boolean facet values as strings — coerce to actual booleans // so they match the filter values stored by toggle(). let val = raw.name; if (col.type === 'boolean' && typeof raw.name === 'string') { if (raw.name === 'true') { val = true; } else if (raw.name === 'false') { val = false; } } if (raw.name === null && raw.count > 0) { buckets.unshift({ val: null, count: raw.count }); } if (raw.name !== null) { buckets.push({ val: val, count: raw.count }); } } // Bucket sync: ensure selected values appear even with 0 results if (col.filter && col.filter.operator === 'in' && Array.isArray(col.filter.value)) { for (const selectedVal of col.filter.value) { if (!buckets.some(b => b.val === selectedVal)) { buckets.push({ val: selectedVal, count: 0 }); } } } this._buckets.set(col.id, buckets); } // Trigger re-render since Map mutation doesn't trigger Lit updates this._buckets = new Map(this._buckets); } /** * Sets up auto-refresh so the table automatically fetches fresh data * at a regular interval (useful for dashboards, monitoring views). * Configured via def.refreshInterval in milliseconds. */ _initRefresh() { clearInterval(this._refreshTimer); if (this._model.refreshInterval && this._model.refreshInterval > 0) { this._refreshTimer = window.setInterval(() => { this._fetch(); }, this._model.refreshInterval); } } _handleSearch(e) { const input = e.target; this._searchQuery = input.value; this._page = 1; this._fetch(); } _getGridTemplateColumns() { const cols = this.getDisplayedColumns(); return cols.map((col) => { // If column has explicit width, use it if (col.width) { return col.width; } // Actions columns: fit content without minimum if (col.type === 'actions') { return 'max-content'; } // No width specified - use content-based sizing with minimum return 'minmax(80px, auto)'; }).join(' '); } /** * Updates search position to be centered with equal gaps from title and tools. * On first call: resets to flex centering, measures position, then locks with fixed margin. * Subsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize). */ _updateSearchPosition() { // Skip if already locked (prevents shifts on pagination changes) if (this._searchPositionLocked) return; const search = this.shadowRoot?.querySelector('.search'); const searchField = search?.querySelector('.search-field'); if (!search || !searchField) return; // Reset to flex centering search.style.justifyContent = 'center'; searchField.style.marginLeft = ''; requestAnimationFrame(() => { const searchRect = search.getBoundingClientRect(); const fieldRect = searchField.getBoundingClientRect(); // Calculate how far from the left of search container the field currently is const currentOffset = fieldRect.left - searchRect.left; // Lock position: switch to flex-start and use fixed margin search.style.justifyContent = 'flex-start'; searchField.style.marginLeft = `${currentOffset}px`; // Mark as locked so pagination changes don't shift the search this._searchPositionLocked = true; }); } // ---------------------------------------------------------------------------- // Columns // ---------------------------------------------------------------------------- _toggleColumnPicker() { this._columnPickerOpen = !this._columnPickerOpen; } _toggleColumn(columnId) { if (this._model.displayedColumns.includes(columnId)) { this._model.displayedColumns = this._model.displayedColumns.filter(id => id !== columnId); } else { this._model.displayedColumns = [...this._model.displayedColumns, columnId]; } } // Clear any existing text selection on mousedown so we only detect // selections made during this click gesture, not stale selections from elsewhere _handleRowMouseDown() { if (!this._model.rowClickable) { return; } window.getSelection()?.removeAllRanges(); } _handleRowClick(row, rowIndex) { if (!this._model.rowClickable) { return; } const selection = window.getSelection(); if (selection && selection.toString().length > 0) { return; } this.dispatchEvent(new CustomEvent('row-click', { detail: { row, rowIndex }, bubbles: true, composed: true })); } // When a user toggles a column on via the column picker, it gets appended // to _displayedColumns. By mapping over _displayedColumns (not def.columns), // the new column appears at the right edge of the table instead of jumping // back to its original position in the column definition. // Actions columns are always moved to the end. getDisplayedColumns() { return this._model.displayedColumns .map(id => this._model.columns.find(col => col.id === id)) .sort((a, b) => { if (a.type === 'actions' && b.type !== 'actions') return 1; if (a.type !== 'actions' && b.type === 'actions') return -1; return 0; }); } // ---------------------------------------------------------------------------- // Scrolling // ---------------------------------------------------------------------------- /** * Scroll event handler that updates scroll flags in real-time as user scrolls. * Updates shadow indicators to show if more content exists left/right. */ _handleScroll(e) { const container = e.target; this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollLeft < container.scrollWidth - container.clientWidth - 1; } /** * Updates scroll state flags for the table content container. * - _canScrollLeft: true if scrolled right (can scroll back left) * - _canScrollRight: true if more content exists to the right * - _canScrollHorizontal: true if content is wider than container * These flags control scroll shadow indicators and CSS classes. */ _updateScrollFlags() { const container = this.shadowRoot?.querySelector('.content'); if (container) { this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollWidth > container.clientWidth && container.scrollLeft < container.scrollWidth - container.clientWidth - 1; this._canScrollHorizontal = container.scrollWidth > container.clientWidth; } this.classList.toggle('kr-table--scroll-left-available', this._canScrollLeft); this.classList.toggle('kr-table--scroll-right-available', this._canScrollRight); this.classList.toggle('kr-table--scroll-horizontal-available', this._canScrollHorizontal); this.classList.toggle('kr-table--sticky-left', this.getDisplayedColumns().some(c => c.sticky === 'left')); this.classList.toggle('kr-table--sticky-right', this.getDisplayedColumns().some(c => c.sticky === 'right')); } // ---------------------------------------------------------------------------- // Column Resizing // ---------------------------------------------------------------------------- _handleResizeStart(e, columnId) { e.preventDefault(); const headerCell = this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${columnId}\"]`); this._resizing = { columnId, startX: e.clientX, startWidth: headerCell?.offsetWidth || 200 }; document.addEventListener('mousemove', this._handleResizeMove); document.addEventListener('mouseup', this._handleResizeEnd); } // ---------------------------------------------------------------------------- // Header // ---------------------------------------------------------------------------- _handleAction(action) { if (action.href) { return; } this.dispatchEvent(new CustomEvent('action', { detail: { action: action.id }, bubbles: true, composed: true })); } // ---------------------------------------------------------------------------- // Filter Handlers // ---------------------------------------------------------------------------- _handleKqlChange(e, column) { const kql = e.target.value.trim(); if (!kql) { column.filter.clear(); this.requestUpdate(); } else { column.filter.setKql(kql); this.requestUpdate(); if (!column.filter.isValid()) { return; } } this._page = 1; this._fetch(); } _handleFilterPanelToggle(e, column) { e.stopPropagation(); if (this._filterPanelOpened === column.id) { this._filterPanelOpened = null; } else { const rect = e.currentTarget.getBoundingClientRect(); this._filterPanelPos = { top: rect.bottom + 4, left: rect.left }; this._filterPanelOpened = column.id; if (column.facetable) { this._filterPanelTab = 'counts'; } else { this._filterPanelTab = 'filter'; } } } _handleKqlClear(column) { column.filter.clear(); this._page = 1; this._fetch(); } _handleFilterClear() { const column = this._model.columns.find(c => c.id === this._filterPanelOpened); if (column) { column.filter.clear(); if (column.facetable && !column.filterable) { column.filter.operator = 'in'; column.filter.value = []; } } this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterTextKeydown(e, column) { if (e.key === 'Enter') { e.preventDefault(); this._handleFilterApply(); } } _handleOperatorChange(e, column) { column.filter.setOperator(e.target.value); this.requestUpdate(); } _handleFilterStringChange(e, column) { column.filter.setValue(e.target.value); this.requestUpdate(); } _handleFilterNumberChange(e, column) { column.filter.setValue(Number(e.target.value)); this.requestUpdate(); } _handleFilterDateChange(e, column) { column.filter.setValue(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterBooleanChange(e, column) { column.filter.setValue(e.target.value === 'true'); this.requestUpdate(); } _handleFilterDateStartChange(e, column) { column.filter.setStart(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterDateEndChange(e, column) { column.filter.setEnd(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterNumberStartChange(e, column) { column.filter.setStart(Number(e.target.value)); this.requestUpdate(); } _handleFilterNumberEndChange(e, column) { column.filter.setEnd(Number(e.target.value)); this.requestUpdate(); } _handleFilterListChange(e, column) { const items = e.target.value.split(',').map((v) => v.trim()).filter((v) => v !== ''); if (column.type === 'number') { column.filter.setValue(items.map((v) => Number(v))); } else { column.filter.setValue(items); } this.requestUpdate(); } _handleFilterApply() { this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterPanelTabChange(e) { this._filterPanelTab = e.detail.activeTabId; } _handleBucketToggle(e, column, bucket) { column.filter.toggle(bucket.val); this._page = 1; this._fetch(); } // ---------------------------------------------------------------------------- // Rendering // ---------------------------------------------------------------------------- _renderCellContent(column, row, rowIndex) { const value = row[column.id]; if (column.render) { // Use slot to project content from light DOM so external styles apply return b `<slot name=\"cell-${rowIndex}-${column.id}\"></slot>`; } if (value === null || value === undefined) { return ''; } switch (column.type) { case 'number': if (column.format === 'currency' && typeof value === 'number') { return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); } return String(value); case 'date': { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(value)) { // MySQL datetime format (UTC): \"2026-01-28 01:33:44:517\" // Replace last colon before ms with dot, append Z for UTC const isoString = value.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/, '$1.$2').replace(' ', 'T') + 'Z'; date = new Date(isoString); } else { date = new Date(value); } // Show date and time for datetime values in UTC return date.toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZone: 'UTC' }); } case 'boolean': if (value === true) return 'Yes'; if (value === false) return 'No'; return ''; default: return String(value); } } /** * Returns CSS classes for a header cell based on column config. */ _getHeaderCellClasses(column, index) { return { 'header-cell': true, 'header-cell--align-center': column.align === 'center', 'header-cell--align-right': column.align === 'right', 'header-cell--sticky-left': column.sticky === 'left', 'header-cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'header-cell--sticky-right': column.sticky === 'right', 'header-cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns CSS classes for a table cell based on column config: * - Alignment (center, right) * - Sticky positioning (left, right) * - Border classes for the last left-sticky or first right-sticky column */ _getCellClasses(column, index) { return { 'cell': true, 'cell--actions': column.type === 'actions', 'cell--align-center': column.align === 'center', 'cell--align-right': column.align === 'right', 'cell--sticky-left': column.sticky === 'left', 'cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'cell--sticky-right': column.sticky === 'right', 'cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns inline styles for a table cell: * - Width (from column config or default 150px) * - Min-width (if specified) * - Left/right offset for sticky columns (calculated from widths of preceding sticky columns) */ _getCellStyle(column, index) { const styles = {}; if (column.sticky === 'left') { let leftOffset = 0; for (let i = 0; i < index; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'left') { leftOffset += parseInt(col.width || '0', 10); } } styles.left = `${leftOffset}px`; } if (column.sticky === 'right') { let rightOffset = 0; for (let i = index + 1; i < this.getDisplayedColumns().length; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'right') { rightOffset += parseInt(col.width || '0', 10); } } styles.right = `${rightOffset}px`; } return styles; } /** * Renders the pagination controls: * - Previous page arrow (disabled on first page) * - Range text showing \"1-50 of 150\" format * - Next page arrow (disabled on last page) * * Hidden when there's no data or all data fits on one page. */ _renderPagination() { const start = (this._page - 1) * this._pageSize + 1; const end = Math.min(this._page * this._pageSize, this._totalItems); return b ` <div class=\"pagination\"> <span class=\"pagination-icon ${this._page === 1 ? 'pagination-icon--disabled' : ''}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${start}-${end} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page === this._totalPages ? 'pagination-icon--disabled' : ''}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `; } /** * Renders the header toolbar containing: * - Title (left) * - Search bar with view selector dropdown (center) * - Tools (right): page navigation, refresh button, column visibility picker, actions dropdown * * Hidden when there's no title, no actions, and data fits on one page. */ _renderHeader() { if (!this._model.title && !this._model.actions?.length && this._totalPages <= 1) { return A; } return b ` <div class=\"header\"> <div class=\"title\">${this._model.title ?? ''}</div> ${this._model.dataSource?.mode === 'db' && !this._model.columns.some(col => col.searchable) ? b `<div class=\"search\"></div>` : b ` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${() => this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen ? 'open' : ''}\"> ${[...this._model.columns].filter(col => col.type !== 'actions').sort((a, b) => (a.label ?? a.id).localeCompare(b.label ?? b.id)).map(col => b ` <div class=\"column-picker-item\" @click=${() => this._toggleColumn(col.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(col.id) ? 'checked' : ''}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${col.label ?? col.id}</span> </div> `)} </div> </div> ${this._model.actions?.length === 1 ? b ` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${() => this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> ` : this._model.actions?.length ? b ` <kr-button class=\"actions\" .options=${this._model.actions.map(a => ({ id: a.id, label: a.label }))} @option-select=${(e) => this._handleAction({ id: e.detail.id, label: e.detail.label })} > Actions </kr-button> ` : A} </div> </div> `; } /** Renders status message (loading, error, empty) */ _renderStatus() { if (this._dataState === 'loading' && this._data.length === 0) { return b `<div class=\"status\">Loading...</div>`; } if (this._dataState === 'error' && this._data.length === 0) { return b `<div class=\"status status--error\">Error loading data</div>`; } if (this._data.length === 0) { return b `<div class=\"status\">No data available</div>`; } return A; } _renderFilterPanel() { if (!this._filterPanelOpened) { return A; } const column = this._model.columns.find(c => c.id === this._filterPanelOpened); // Build filter content (operator + value input) let valueInput = b ``; if (column.filter.operator === 'empty' || column.filter.operator === 'n_empty') { valueInput = b ` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${column.filter.text} /> `; } else if (column.filter.operator === 'between' && column.type === 'date') { valueInput = b ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.start ?? null} @change=${(e) => this._handleFilterDateStartChange(e, column)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.end ?? null} @change=${(e) => this._handleFilterDateEndChange(e, column)} /> `; } else if (column.filter.operator === 'between' && column.type === 'number') { valueInput = b ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${column.filter.value?.start ?? ''} @input=${(e) => this._handleFilterNumberStartChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${column.filter.value?.end ?? ''} @input=${(e) => this._handleFilterNumberEndChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else if (column.filter.operator === 'in') { valueInput = b ` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${column.filter.text} @input=${(e) => this._handleFilterListChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} ></textarea> `; } else if (column.type === 'boolean') { valueInput = b ` <kr-select-field placeholder=\"Value\" .value=${String(column.filter.value ?? '')} @change=${(e) => this._handleFilterBooleanChange(e, column)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `; } else if (column.type === 'date') { valueInput = b ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value} @change=${(e) => this._handleFilterDateChange(e, column)} /> `; } else if (column.type === 'number') { valueInput = b ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${column.filter.text} @input=${(e) => this._handleFilterNumberChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else { valueInput = b ` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${column.filter.text} @input=${(e) => this._handleFilterStringChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } const filterContent = b ` <div class=\"filter-panel__content\"> <kr-select-field .value=${column.filter.operator} @change=${(e) => this._handleOperatorChange(e, column)} > ${getOperatorsForType(column.type).map(op => b ` <kr-select-option value=${op.key}>${op.label}</kr-select-option> `)} </kr-select-field> ${valueInput} </div> `; // Build bucket list content const buckets = this._buckets.get(column.id) || []; let bucketContent; if (!buckets.length) { bucketContent = b `<div class=\"bucket-empty\">No data</div>`; } else { bucketContent = b ` <div class=\"buckets\"> ${buckets.map(bucket => { let bucketLabel = '(Empty)'; if (bucket.val !== null && bucket.val !== undefined) { if (column.type === 'boolean') { if (bucket.val === true || bucket.val === 'true') { bucketLabel = 'Yes'; } else { bucketLabel = 'No'; } } else { bucketLabel = String(bucket.val); } } let checkIcon = A; if (column.filter.has(bucket.val)) { checkIcon = b ` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `; } return b ` <div class=\"bucket\" @click=${(e) => this._handleBucketToggle(e, column, bucket)} > <div class=${e$1({ 'bucket__checkbox': true, 'bucket__checkbox--checked': column.filter.has(bucket.val) })}> ${checkIcon} </div> <span class=\"bucket__label\">${bucketLabel}</span> <span class=\"bucket__count\">${bucket.count}</span> </div> `; })} </div> `; } // Build panel body — tabs if both filterable+facetable, otherwise just the relevant content let panelBody; if (column.facetable && column.filterable) { panelBody = b ` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${(e) => this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${filterContent} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${bucketContent} </kr-tab> </kr-tab-group> `; } else if (column.facetable) { panelBody = bucketContent; } else { panelBody = filterContent; } return b ` <div class=\"filter-panel\" style=${o$1({ top: this._filterPanelPos.top + 'px', left: this._filterPanelPos.left + 'px' })} > ${panelBody} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `; } /** * Renders filter row below column headers. * Only displays for columns with filterable: true. */ _renderFilterRow() { const columns = this.getDisplayedColumns(); if (!columns.some(col => col.filterable || col.facetable)) { return A; } return b ` <div class=\"filter-row\"> ${columns.map((col, i) => { if (!col.filterable && !col.facetable) { return b `<div class=${e$1({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${o$1(this._getCellStyle(col, i))} ></div>`; } return b ` <div class=${e$1({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${o$1(this._getCellStyle(col, i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${e$1({ 'filter-cell__input': true, 'filter-cell__input--invalid': !col.filter.isValid() })} .value=${col.filter.kql} @change=${(e) => this._handleKqlChange(e, col)} /> ${col.filter?.kql?.length > 0 ? b ` <button class=\"filter-cell__clear\" @click=${() => this._handleKqlClear(col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> ` : A} <button class=${e$1({ 'filter-cell__advanced': true, 'filter-cell__advanced--opened': this._filterPanelOpened === col.id })} @click=${(e) => this._handleFilterPanelToggle(e, col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `; })} </div> `; } /** Renders the scrollable data grid with column headers and rows. */ _renderTable() { return b ` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getHeaderCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} >${col.label ?? col.id}${col.resizable !== false ? b `<div class=\"header-cell__resize\" @mousedown=${(e) => this._handleResizeStart(e, col.id)} ></div>` : A}</div> `)} </div> ${this._renderFilterRow()} ${this._data.map((row, rowIndex) => { const cells = this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} > ${this._renderCellContent(col, row, rowIndex)} </div> `); if (this._model.rowHref) { return b ` <a href=${this._model.rowHref(row)} class=${e$1({ 'row': true, 'row--clickable': true, 'row--link': true })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</a> `; } return b ` <div class=${e$1({ 'row': true, 'row--clickable': !!this._model.rowClickable })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</div> `; })} </div> </div> </div> `; } /** * Renders a data table with: * - Header bar with title, search input with view selector, and tools (pagination, refresh, column visibility, actions dropdown) * - Scrollable grid with sticky header row and optional sticky left/right columns * - Loading, error message, or empty state when no data */ render() { if (!this._model.columns.length) { return b `<slot></slot>`; } return b ` ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `; } }"
|
|
316
569
|
},
|
|
317
570
|
{
|
|
318
571
|
"kind": "variable",
|
|
@@ -343,18 +596,6 @@
|
|
|
343
596
|
"default": "class KRTextField extends i$2 { constructor() { super(); /** * The input label text */ this.label = ''; /** * The input name for form submission */ this.name = ''; /** * The current value */ this.value = ''; /** * Placeholder text */ this.placeholder = ''; /** * Input type (text, email, password, tel, url, search) */ this.type = 'text'; /** * Whether the field is required */ this.required = false; /** * Whether the field is disabled */ this.disabled = false; /** * Whether the field is readonly */ this.readonly = false; /** * Autocomplete attribute value */ this.autocomplete = ''; /** * Helper text shown below the input */ this.hint = ''; this._touched = false; this._dirty = false; this._handleInvalid = (e) => { e.preventDefault(); this._touched = true; }; this._internals = this.attachInternals(); } // Form-associated custom element callbacks get form() { return this._internals.form; } get validity() { return this._internals.validity; } get validationMessage() { return this._internals.validationMessage; } get willValidate() { return this._internals.willValidate; } checkValidity() { return this._internals.checkValidity(); } reportValidity() { return this._internals.reportValidity(); } formResetCallback() { this.value = ''; this._touched = false; this._dirty = false; this._internals.setFormValue(''); this._internals.setValidity({}); } formStateRestoreCallback(state) { this.value = state; } connectedCallback() { super.connectedCallback(); this.addEventListener('invalid', this._handleInvalid); } disconnectedCallback() { super.disconnectedCallback(); this.removeEventListener('invalid', this._handleInvalid); } firstUpdated() { this._updateValidity(); } updated(changedProperties) { if (changedProperties.has('required') || changedProperties.has('value')) { this._updateValidity(); } } _updateValidity() { if (this._input) { this._internals.setValidity(this._input.validity, this._input.validationMessage); } } _handleInput(e) { this.value = e.target.value; this._dirty = true; this._internals.setFormValue(this.value); this._internals.setValidity(this._input.validity, this._input.validationMessage); } _handleChange(e) { this.value = e.target.value; this._internals.setFormValue(this.value); } _handleBlur() { this._touched = true; this._internals.setValidity(this._input.validity, this._input.validationMessage); } render() { let validationMessage = ''; if (this._touched && this._input && !this._input.validity.valid) { validationMessage = this._input.validationMessage; } return b ` <div class=\"wrapper\"> ${this.label ? b ` <label for=\"input\"> ${this.label} ${this.required ? b `<span class=\"required\" aria-hidden=\"true\">*</span>` : ''} </label> ` : ''} <input id=\"input\" class=${e$1({ 'input--invalid': this._touched && this._input && !this._input.validity.valid })} type=${this.type} name=${this.name} .value=${l(this.value)} placeholder=${this.placeholder} ?required=${this.required} ?disabled=${this.disabled} ?readonly=${this.readonly} minlength=${o(this.minlength)} maxlength=${o(this.maxlength)} pattern=${o(this.pattern)} autocomplete=${o(this.autocomplete || undefined)} @input=${this._handleInput} @change=${this._handleChange} @blur=${this._handleBlur} /> ${validationMessage ? b `<div class=\"validation-message\">${validationMessage}</div>` : this.hint ? b `<div class=\"hint\">${this.hint}</div>` : ''} </div> `; } // Public methods for programmatic control focus() { this._input?.focus(); } blur() { this._input?.blur(); } select() { this._input?.select(); } }",
|
|
344
597
|
"description": "A text field component that works with native browser forms.\n\nUses ElementInternals for form association, allowing the component\nto participate in form submission, validation, and reset.\n\nNative input and change events bubble up from the inner input element."
|
|
345
598
|
},
|
|
346
|
-
{
|
|
347
|
-
"kind": "variable",
|
|
348
|
-
"name": "KRSelectField",
|
|
349
|
-
"default": "class KRSelectField extends i$2 { constructor() { super(); /** * The select label text */ this.label = ''; /** * The input name for form submission */ this.name = ''; /** * The currently selected value */ this.value = ''; /** * Placeholder text when no option is selected */ this.placeholder = 'Select an option'; /** * Whether the select is disabled */ this.disabled = false; /** * Whether the field is required */ this.required = false; /** * Whether the field is readonly */ this.readonly = false; /** * Helper text shown below the select */ this.hint = ''; this._isOpen = false; this._highlightedIndex = -1; this._touched = false; this._handleInvalid = (e) => { e.preventDefault(); this._touched = true; }; this._handleOutsideClick = (e) => { if (!e.composedPath().includes(this)) { this._close(); } }; this._handleKeyDown = (e) => { if (!this._isOpen) return; const options = Array.from(this.querySelectorAll('kr-select-option')); switch (e.key) { case 'Escape': this._close(); this._triggerElement?.focus(); break; case 'ArrowDown': e.preventDefault(); if (options.some(o => !o.disabled)) { let newIndex = this._highlightedIndex + 1; while (newIndex < options.length && options[newIndex]?.disabled) newIndex++; if (newIndex < options.length) this._highlightedIndex = newIndex; } break; case 'ArrowUp': e.preventDefault(); { let newIndex = this._highlightedIndex - 1; while (newIndex >= 0 && options[newIndex]?.disabled) newIndex--; if (newIndex >= 0) this._highlightedIndex = newIndex; } break; case 'Enter': e.preventDefault(); if (this._highlightedIndex >= 0 && this._highlightedIndex < options.length) { this._selectOption(options[this._highlightedIndex]); } break; } }; this._internals = this.attachInternals(); } // Form-associated custom element callbacks get form() { return this._internals.form; } get validity() { return this._internals.validity; } get validationMessage() { return this._internals.validationMessage; } get willValidate() { return this._internals.willValidate; } checkValidity() { return this._internals.checkValidity(); } reportValidity() { return this._internals.reportValidity(); } formResetCallback() { this.value = ''; this._touched = false; this._internals.setFormValue(''); this._internals.setValidity({}); } formStateRestoreCallback(state) { this.value = state; } connectedCallback() { super.connectedCallback(); document.addEventListener('click', this._handleOutsideClick); document.addEventListener('keydown', this._handleKeyDown); this.addEventListener('invalid', this._handleInvalid); } firstUpdated() { this._updateValidity(); } updated(changedProperties) { if (changedProperties.has('required') || changedProperties.has('value')) { this._updateValidity(); } } disconnectedCallback() { super.disconnectedCallback(); document.removeEventListener('click', this._handleOutsideClick); document.removeEventListener('keydown', this._handleKeyDown); this.removeEventListener('invalid', this._handleInvalid); } _toggle() { if (this.disabled || this.readonly) return; if (this._isOpen) { this._close(); } else { this._isOpen = true; const options = Array.from(this.querySelectorAll('kr-select-option')); this._highlightedIndex = options.findIndex(o => o.value === this.value); // Position the fixed dropdown relative to the trigger requestAnimationFrame(() => { const dropdown = this.shadowRoot?.querySelector('.select-dropdown'); if (dropdown) { const triggerRect = this._triggerElement.getBoundingClientRect(); const spaceBelow = window.innerHeight - triggerRect.bottom - 4 - 8; dropdown.style.top = triggerRect.bottom + 4 + 'px'; dropdown.style.left = triggerRect.left + 'px'; dropdown.style.width = triggerRect.width + 'px'; dropdown.style.maxHeight = spaceBelow + 'px'; } }); } } _close() { this._isOpen = false; this._highlightedIndex = -1; } _selectOption(option) { if (option.disabled) return; this.value = option.value; this._internals.setFormValue(this.value); this._updateValidity(); this.dispatchEvent(new Event('change', { bubbles: true, composed: true })); this._close(); this._triggerElement?.focus(); } _handleBlur() { this._touched = true; this._updateValidity(); } _updateValidity() { if (this.required && !this.value) { this._internals.setValidity({ valueMissing: true }, 'Please select an option', this._triggerElement); } else { this._internals.setValidity({}); } } render() { const options = Array.from(this.querySelectorAll('kr-select-option')); const selectedLabel = options.find(o => o.value === this.value)?.label; return b ` <div class=\"wrapper\"> ${this.label ? b ` <label> ${this.label} ${this.required ? b `<span class=\"required\" aria-hidden=\"true\">*</span>` : ''} </label> ` : A} <div class=\"select-wrapper\"> <button class=${e$1({ 'select-trigger': true, 'select-trigger--open': this._isOpen, 'select-trigger--invalid': this._touched && this.required && !this.value, })} type=\"button\" ?disabled=${this.disabled} aria-haspopup=\"listbox\" aria-expanded=${this._isOpen} @click=${this._toggle} @blur=${this._handleBlur} > <span class=${e$1({ 'select-value': true, 'select-placeholder': !selectedLabel })}> ${selectedLabel || this.placeholder} </span> <svg class=${e$1({ 'chevron-icon': true, 'select-icon': true, 'select-icon--open': this._isOpen })} viewBox=\"0 0 24 24\" fill=\"currentColor\" > <path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z\"/> </svg> </button> <div class=${e$1({ 'select-dropdown': true, 'hidden': !this._isOpen })} role=\"listbox\"> <div class=\"select-options\"> ${options.length === 0 ? b `<div class=\"select-empty\">No options available</div>` : options.map((option, idx) => { const isSelected = option.value === this.value; return b ` <div class=${e$1({ 'select-option': true, 'select-option--selected': isSelected, 'select-option--disabled': option.disabled, 'select-option--highlighted': idx === this._highlightedIndex, })} role=\"option\" aria-selected=${isSelected} @click=${() => this._selectOption(option)} @mouseenter=${() => (this._highlightedIndex = idx)} > ${option.label} </div> `; })} </div> </div> </div> ${this._touched && this.required && !this.value ? b `<div class=\"validation-message\">Please select an option</div>` : this.hint ? b `<div class=\"hint\">${this.hint}</div>` : ''} </div> <div class=\"options-slot\"> <slot @slotchange=${() => this.requestUpdate()}></slot> </div> `; } // Public methods for programmatic control focus() { this._triggerElement?.focus(); } blur() { this._triggerElement?.blur(); } }",
|
|
350
|
-
"description": "A select dropdown component that works with native browser forms.\n\nUses ElementInternals for form association, allowing the component\nto participate in form submission, validation, and reset."
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
"kind": "variable",
|
|
354
|
-
"name": "KRSelectOption",
|
|
355
|
-
"default": "class KRSelectOption extends i$2 { constructor() { super(...arguments); /** * The option value */ this.value = ''; /** * Whether the option is disabled */ this.disabled = false; } /** Gets the label text from the slot */ get label() { return this.textContent?.trim() || ''; } render() { return b `<slot></slot>`; } }",
|
|
356
|
-
"description": "An option for the kr-select-field component."
|
|
357
|
-
},
|
|
358
599
|
{
|
|
359
600
|
"kind": "variable",
|
|
360
601
|
"name": "KRTextareaField",
|
|
@@ -472,6 +713,14 @@
|
|
|
472
713
|
"module": "dist/krubble-components.bundled.js"
|
|
473
714
|
}
|
|
474
715
|
},
|
|
716
|
+
{
|
|
717
|
+
"kind": "js",
|
|
718
|
+
"name": "KRQuery",
|
|
719
|
+
"declaration": {
|
|
720
|
+
"name": "KRQuery",
|
|
721
|
+
"module": "dist/krubble-components.bundled.js"
|
|
722
|
+
}
|
|
723
|
+
},
|
|
475
724
|
{
|
|
476
725
|
"kind": "js",
|
|
477
726
|
"name": "KRSelectField",
|
|
@@ -544,6 +793,22 @@
|
|
|
544
793
|
"module": "dist/krubble-components.bundled.js"
|
|
545
794
|
}
|
|
546
795
|
},
|
|
796
|
+
{
|
|
797
|
+
"kind": "js",
|
|
798
|
+
"name": "KR_OPERATORS",
|
|
799
|
+
"declaration": {
|
|
800
|
+
"name": "KR_OPERATORS",
|
|
801
|
+
"module": "dist/krubble-components.bundled.js"
|
|
802
|
+
}
|
|
803
|
+
},
|
|
804
|
+
{
|
|
805
|
+
"kind": "js",
|
|
806
|
+
"name": "getOperatorsForType",
|
|
807
|
+
"declaration": {
|
|
808
|
+
"name": "getOperatorsForType",
|
|
809
|
+
"module": "dist/krubble-components.bundled.js"
|
|
810
|
+
}
|
|
811
|
+
},
|
|
547
812
|
{
|
|
548
813
|
"kind": "js",
|
|
549
814
|
"name": "krBaseCSS",
|
|
@@ -569,38 +834,38 @@
|
|
|
569
834
|
},
|
|
570
835
|
{
|
|
571
836
|
"kind": "variable",
|
|
572
|
-
"name": "
|
|
837
|
+
"name": "ne",
|
|
573
838
|
"default": "r` :host, *, *::before, *::after { box-sizing: border-box; } :host { /* Primary */ --kr-primary: rgb(22, 48, 82); --kr-primary-hover: rgb(16, 36, 62); --kr-primary-text: #ffffff; /* Accent */ --kr-accent: #BEEA4E; --kr-accent-hover: #a8d43a; --kr-accent-text: #000000; /* Text */ --kr-text: #000000; --kr-text-muted: #4b5563; --kr-text-disabled: #9ca3af; /* Borders */ --kr-border: #e5e7eb; } `"
|
|
574
839
|
},
|
|
575
840
|
{
|
|
576
841
|
"kind": "variable",
|
|
577
842
|
"name": "ve",
|
|
578
|
-
"default": "class extends
|
|
843
|
+
"default": "class extends ae{constructor(){super(...arguments),this.header=\"\",this.expanded=!1}toggle(){this.expanded=!this.expanded}render(){return V` <div class=\"header\" @click=${this.toggle}> <span class=\"header__title\">${this.header}</span> <svg class=\"header__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M6 9l6 6 6-6\"/> </svg> </div> <div class=\"content\"> <div class=\"content__inner\"> <div class=\"content__body\"> <slot></slot> </div> </div> </div> `}}"
|
|
579
844
|
},
|
|
580
845
|
{
|
|
581
846
|
"kind": "variable",
|
|
582
847
|
"name": "Ce",
|
|
583
|
-
"default": "class extends
|
|
848
|
+
"default": "class extends ae{constructor(){super(...arguments),this.type=\"info\",this.title=\"\",this.dismissible=!1,this.visible=!0}_handleDismiss(){this.visible=!1,this.dispatchEvent(new CustomEvent(\"dismiss\",{bubbles:!0,composed:!0}))}render(){const e={info:V`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\"/></svg>`,success:V`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\"/></svg>`,warning:V`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\"/></svg>`,error:V`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\"/></svg>`};return V` <div class=${we({alert:!0,[\"alert--\"+this.type]:!0,\"alert--has-header\":!!this.title,\"alert--hidden\":!this.visible})} role=\"alert\" > ${e[this.type]} <div class=\"content\"> ${this.title?V`<h4 class=\"header\">${this.title}</h4>`:B} <div class=\"message\"> <slot></slot> </div> </div> ${this.dismissible?V` <button class=\"dismiss\" type=\"button\" aria-label=\"Dismiss alert\" @click=${this._handleDismiss} > <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" width=\"16\" height=\"16\"> <path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\"/> </svg> </button> `:B} </div> `}}"
|
|
584
849
|
},
|
|
585
850
|
{
|
|
586
851
|
"kind": "variable",
|
|
587
|
-
"name": "
|
|
588
|
-
"default": "class extends
|
|
852
|
+
"name": "Ee",
|
|
853
|
+
"default": "class extends ae{constructor(){super(...arguments),this.variant=\"flat\",this.color=\"primary\",this.size=\"medium\",this.disabled=!1,this.options=[],this.iconPosition=\"left\",this._state=\"idle\",this._stateText=\"\",this._dropdownOpened=!1,this._handleHostClick=e=>{this.options.length&&(e.stopPropagation(),this._toggleDropdown())},this._handleKeydown=e=>{\"Enter\"!==e.key&&\" \"!==e.key||(e.preventDefault(),this.options.length?this._toggleDropdown():this.click()),\"Escape\"===e.key&&this._dropdownOpened&&(this._dropdownOpened=!1)},this._handleClickOutside=e=>{this._dropdownOpened&&!this.contains(e.target)&&(this._dropdownOpened=!1)}}connectedCallback(){super.connectedCallback(),this.setAttribute(\"role\",this.href?\"link\":\"button\"),this.setAttribute(\"tabindex\",\"0\"),this.addEventListener(\"keydown\",this._handleKeydown),this.addEventListener(\"click\",this._handleHostClick),document.addEventListener(\"click\",this._handleClickOutside)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"keydown\",this._handleKeydown),this.removeEventListener(\"click\",this._handleHostClick),document.removeEventListener(\"click\",this._handleClickOutside)}_toggleDropdown(){this._dropdownOpened=!this._dropdownOpened,this._dropdownOpened&&requestAnimationFrame((()=>{const e=this.shadowRoot?.querySelector(\".dropdown\");if(e){const t=this.getBoundingClientRect();e.style.top=t.bottom+4+\"px\",e.style.bottom=\"\",e.style.left=t.left+\"px\",e.style.right=\"\",e.style.minWidth=t.width+\"px\",e.style.transformOrigin=\"top left\";const i=e.getBoundingClientRect();i.bottom>window.innerHeight?(e.style.top=\"\",e.style.bottom=window.innerHeight-t.top+4+\"px\",e.style.transformOrigin=\"bottom left\",e.classList.add(\"dropdown--above\")):e.classList.remove(\"dropdown--above\"),i.right>window.innerWidth&&(e.style.left=\"\",e.style.right=window.innerWidth-t.right+\"px\",i.bottom>window.innerHeight?e.style.transformOrigin=\"bottom right\":e.style.transformOrigin=\"top right\")}}))}_handleOptionClick(e,t){t.stopPropagation(),this._dropdownOpened=!1,this.dispatchEvent(new CustomEvent(\"option-select\",{detail:{id:e.id,label:e.label},bubbles:!0,composed:!0}))}showLoading(){this._clearStateTimeout(),this._state=\"loading\",this._stateText=\"\"}showSuccess(e=\"Success\",t=2e3){this._clearStateTimeout(),this._state=\"success\",this._stateText=e,t>0&&(this._stateTimeout=window.setTimeout((()=>this.reset()),t))}showError(e=\"Error\",t=2e3){this._clearStateTimeout(),this._state=\"error\",this._stateText=e,t>0&&(this._stateTimeout=window.setTimeout((()=>this.reset()),t))}isLoading(){return\"loading\"===this._state}reset(){this._clearStateTimeout(),this._state=\"idle\",this._stateText=\"\"}_clearStateTimeout(){this._stateTimeout&&(clearTimeout(this._stateTimeout),this._stateTimeout=void 0)}updated(e){this.classList.toggle(\"kr-button--loading\",\"loading\"===this._state),this.classList.toggle(\"kr-button--success\",\"success\"===this._state),this.classList.toggle(\"kr-button--error\",\"error\"===this._state),this.classList.toggle(`kr-button--${this.variant}`,!0),this.classList.toggle(`kr-button--${this.color}`,!0),this.classList.toggle(\"kr-button--small\",\"small\"===this.size),this.classList.toggle(\"kr-button--large\",\"large\"===this.size)}render(){const e=V` <span class=\"content\"> <slot name=\"icon\"></slot> <slot></slot> </span> ${this.options.length?V`<svg class=\"caret\" xmlns=\"http://www.w3.org/2000/svg\" height=\"20\" width=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg>`:B} ${\"idle\"!==this._state?V`<span class=\"state-overlay\"> ${\"loading\"===this._state?V`<span class=\"spinner\"></span>`:this._stateText} </span>`:B} ${this.options.length?V` <div class=\"dropdown ${this._dropdownOpened?\"dropdown--opened\":\"\"}\"> ${this.options.map((e=>V` <button class=\"dropdown-item\" @click=${t=>this._handleOptionClick(e,t)} >${e.label}</button> `))} </div> `:B} `;return this.href?V`<a class=\"link\" href=${this.href} target=${this.target||B}>${e}</a>`:e}}"
|
|
589
854
|
},
|
|
590
855
|
{
|
|
591
856
|
"kind": "variable",
|
|
592
|
-
"name": "
|
|
593
|
-
"default": "class extends
|
|
857
|
+
"name": "Pe",
|
|
858
|
+
"default": "class extends ae{constructor(){super(...arguments),this.language=\"html\",this.code=\"\",this.activeTab=\"preview\",this.copied=!1,this.highlightedCode=\"\"}connectedCallback(){super.connectedCallback(),requestAnimationFrame((()=>{this.code||(this.code=this.innerHTML.trim().replace(/=\"\"(?=[\\s>])/g,\"\")),this.querySelectorAll(\"script\").forEach((e=>{const t=document.createElement(\"script\");t.textContent=e.textContent,e.replaceWith(t)})),this.code&&window.hljs&&window.hljs.getLanguage(this.language)?this.highlightedCode=window.hljs.highlight(this.code,{language:this.language}).value:this.highlightedCode=this.code.replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\")}))}activateTab(e){this.activeTab=e}copyCode(){this.code&&navigator.clipboard.writeText(this.code).then((()=>{this.copied=!0,setTimeout((()=>{this.copied=!1}),2e3)}))}render(){return V` <div class=\"tabs\"> <button class=${we({tab:!0,\"tab--active\":\"preview\"===this.activeTab})} @click=${()=>this.activateTab(\"preview\")} > Preview </button> <button class=${we({tab:!0,\"tab--active\":\"code\"===this.activeTab})} @click=${()=>this.activateTab(\"code\")} > Code </button> <button class=${we({copy:!0,\"copy--success\":this.copied})} @click=${this.copyCode} title=${this.copied?\"Copied!\":\"Copy code\"} > ${this.copied?V`<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>`:V`<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg>`} </button> </div> <div class=${we({panel:!0,\"panel--active\":\"preview\"===this.activeTab,\"panel--preview\":!0})}> <slot></slot> </div> <div class=${we({panel:!0,\"panel--active\":\"code\"===this.activeTab,\"panel--code\":!0})}> <pre class=\"code\"><code>${Te(this.highlightedCode)}</code></pre> </div> `}}"
|
|
594
859
|
},
|
|
595
860
|
{
|
|
596
861
|
"kind": "variable",
|
|
597
|
-
"name": "
|
|
598
|
-
"default": "class extends
|
|
862
|
+
"name": "De",
|
|
863
|
+
"default": "class extends ae{constructor(){super(...arguments),this.items=[],this.resolvePromise=null,this.boundHandleOutsideClick=this.handleOutsideClick.bind(this),this.boundHandleKeyDown=this.handleKeyDown.bind(this)}static async open(e){const t=document.querySelector(\"kr-context-menu\");t&&t.remove();const i=document.createElement(\"kr-context-menu\");return document.body.appendChild(i),i.show(e)}async show(e){this.items=e.items,this.style.left=`${e.x}px`,this.style.top=`${e.y}px`,await this.updateComplete;const t=this.getBoundingClientRect();return t.right>window.innerWidth&&(this.style.left=e.x-t.width+\"px\"),t.bottom>window.innerHeight&&(this.style.top=e.y-t.height+\"px\"),requestAnimationFrame((()=>{document.addEventListener(\"click\",this.boundHandleOutsideClick),document.addEventListener(\"contextmenu\",this.boundHandleOutsideClick),document.addEventListener(\"keydown\",this.boundHandleKeyDown)})),new Promise((e=>{this.resolvePromise=e}))}handleOutsideClick(e){this.contains(e.target)||this.close(null)}handleKeyDown(e){\"Escape\"===e.key&&this.close(null)}handleItemClick(e){e.disabled||e.divider||this.close(e)}close(e){document.removeEventListener(\"click\",this.boundHandleOutsideClick),document.removeEventListener(\"contextmenu\",this.boundHandleOutsideClick),document.removeEventListener(\"keydown\",this.boundHandleKeyDown),this.resolvePromise&&(this.resolvePromise(e),this.resolvePromise=null),this.remove()}render(){return V` <div class=\"menu\"> ${this.items.map((e=>e.divider?V`<div class=\"menu__divider\"></div>`:V` <button class=\"menu__item\" ?disabled=${e.disabled} @click=${()=>this.handleItemClick(e)} > ${e.icon?V`<span class=\"menu__item-icon\">${e.icon}</span>`:null} ${e.label} </button> `))} </div> `}}"
|
|
599
864
|
},
|
|
600
865
|
{
|
|
601
866
|
"kind": "class",
|
|
602
867
|
"description": "",
|
|
603
|
-
"name": "
|
|
868
|
+
"name": "Ve",
|
|
604
869
|
"members": [
|
|
605
870
|
{
|
|
606
871
|
"kind": "method",
|
|
@@ -649,8 +914,8 @@
|
|
|
649
914
|
},
|
|
650
915
|
{
|
|
651
916
|
"kind": "variable",
|
|
652
|
-
"name": "
|
|
653
|
-
"default": "class extends
|
|
917
|
+
"name": "Ue",
|
|
918
|
+
"default": "class extends ae{constructor(){super(...arguments),this._dialogRef=null,this._contentElement=null,this.opened=!1,this.label=\"\",this.width=\"560px\",this._handleDocumentKeyDown=e=>{\"Escape\"===e.key&&this.close()}}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"keydown\",this._handleDocumentKeyDown)}updated(e){super.updated(e),e.has(\"opened\")&&(this.opened?document.addEventListener(\"keydown\",this._handleDocumentKeyDown):document.removeEventListener(\"keydown\",this._handleDocumentKeyDown))}open(){this.opened=!0}close(){this._dialogRef?this._dialogRef.close(void 0):(this.opened=!1,this.dispatchEvent(new CustomEvent(\"close\",{bubbles:!0,composed:!0})))}static open(e,t){document.querySelectorAll(\"kr-dialog\").forEach((e=>{e._dialogRef&&e.remove()}));const i=new Ve,s=document.createElement(\"kr-dialog\");i.setDialogElement(s),s._dialogRef=i;const o=new e;return o.dialogRef=i,t?.data&&(o.data=t.data),t?.label&&(s.label=t.label),t?.width&&(s.width=t.width),s._contentElement=o,s.opened=!0,document.body.appendChild(s),i}_handleBackdropClick(e){e.target.classList.contains(\"backdrop\")&&this.close()}render(){return V` <div class=\"backdrop\" @click=${this._handleBackdropClick}></div> <div class=\"dialog\" style=${Ie({width:this.width})}> ${this.label?V`<div class=\"dialog__header\"><div class=\"dialog__header-label\">${this.label}</div></div>`:\"\"} ${this._contentElement?this._contentElement:V`<slot></slot>`} </div> `}}"
|
|
654
919
|
},
|
|
655
920
|
{
|
|
656
921
|
"kind": "variable",
|
|
@@ -658,71 +923,278 @@
|
|
|
658
923
|
},
|
|
659
924
|
{
|
|
660
925
|
"kind": "variable",
|
|
661
|
-
"name": "
|
|
662
|
-
"default": "class extends
|
|
926
|
+
"name": "We",
|
|
927
|
+
"default": "class extends ae{constructor(){super(...arguments),this.justified=!1,this.size=\"medium\"}updated(e){e.has(\"activeTabId\")&&this._updateActiveTab()}firstUpdated(){this._updateActiveTab()}_getTabs(){return Array.from(this.querySelectorAll(\"kr-tab\"))}_updateActiveTab(){const e=this._getTabs();0!==e.length&&(this.activeTabId||(this.activeTabId=e[0]?.id),e.forEach((e=>{e.active=e.id===this.activeTabId})),this.requestUpdate())}_handleTabClick(e){e.disabled||(this.activeTabId=e.id,this.dispatchEvent(new CustomEvent(\"tab-change\",{detail:{activeTabId:e.id},bubbles:!0,composed:!0})))}_handleTabDismiss(e,t){t.stopPropagation(),this.dispatchEvent(new CustomEvent(\"tab-dismiss\",{detail:{tabId:e.id},bubbles:!0,composed:!0}))}_handleKeyDown(e){const t=this._getTabs().filter((e=>!e.disabled)),i=t.findIndex((e=>e.id===this.activeTabId));let s=-1;switch(e.key){case\"ArrowLeft\":s=i>0?i-1:t.length-1;break;case\"ArrowRight\":s=i<t.length-1?i+1:0;break;case\"Home\":s=0;break;case\"End\":s=t.length-1}if(s>=0){e.preventDefault();const i=t[s];this.activeTabId=i.id,this.dispatchEvent(new CustomEvent(\"tab-change\",{detail:{activeTabId:i.id},bubbles:!0,composed:!0}));const o=this.shadowRoot?.querySelectorAll(\".label\"),r=Array.from(o||[]).find((e=>e.getAttribute(\"data-tab-id\")===i.id));r?.focus()}}_renderTabIcon(e){const t=e.getIconElement();if(!t)return B;const i=t.cloneNode(!0);return i.removeAttribute(\"slot\"),V`<span class=\"label-icon\">${i}</span>`}render(){return V` <div class=\"header\" role=\"tablist\" @keydown=${this._handleKeyDown}> ${this._getTabs().map((e=>V` <button class=${we({label:!0,\"label--active\":e.id===this.activeTabId,\"label--justified\":this.justified})} role=\"tab\" data-tab-id=${e.id} aria-selected=${e.id===this.activeTabId} aria-controls=${`panel-${e.id}`} tabindex=${e.id===this.activeTabId?0:-1} ?disabled=${e.disabled} @click=${()=>this._handleTabClick(e)} > ${this._renderTabIcon(e)} <span>${e.label}</span> ${e.badge?V`<span class=\"label-badge\" style=${Ie({backgroundColor:e.badgeBackground,color:e.badgeColor})}>${e.badge}</span>`:B} ${e.dismissible?V` <button class=\"label-dismiss\" type=\"button\" aria-label=\"Close tab\" @click=${t=>this._handleTabDismiss(e,t)} > <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" width=\"12\" height=\"12\"><path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\"/></svg> </button> `:B} </button> `))} </div> <div class=\"content\" role=\"tabpanel\" aria-labelledby=${this.activeTabId||\"\"}> <slot @slotchange=${this._updateActiveTab}></slot> </div> `}}"
|
|
663
928
|
},
|
|
664
929
|
{
|
|
665
930
|
"kind": "variable",
|
|
666
931
|
"name": "Ye",
|
|
667
|
-
"default": "class extends
|
|
932
|
+
"default": "class extends ae{constructor(){super(...arguments),this.id=\"\",this.label=\"\",this.badge=\"\",this.badgeBackground=\"\",this.badgeColor=\"\",this.disabled=!1,this.dismissible=!1,this.active=!1}getIconElement(){return this.querySelector('[slot=\"icon\"]')}render(){return console.log(\"tab render\"),V`<slot></slot>`}}"
|
|
668
933
|
},
|
|
669
934
|
{
|
|
670
935
|
"kind": "variable",
|
|
671
|
-
"name": "
|
|
672
|
-
"default": "class extends ne{constructor(){super(...arguments),this._scrollStyle=\"overlay\",this._data=[],this._dataState=\"idle\",this._page=1,this._pageSize=50,this._totalItems=0,this._totalPages=0,this._searchQuery=\"\",this._canScrollLeft=!1,this._canScrollRight=!1,this._canScrollHorizontal=!1,this._columnPickerOpen=!1,this._displayedColumns=[],this._resizing=null,this._resizeObserver=null,this._searchPositionLocked=!1,this._def={columns:[]},this.def={columns:[]},this._handleClickOutsideColumnPicker=e=>{if(!this._columnPickerOpen)return;const t=e.composedPath(),i=this.shadowRoot?.querySelector(\".column-picker-wrapper\");i&&!t.includes(i)&&(this._columnPickerOpen=!1)},this._handleResizeMove=e=>{if(!this._resizing)return;const t=this._def.columns.find((e=>e.id===this._resizing.columnId));if(t){const i=this._resizing.startWidth+(e.clientX-this._resizing.startX);t.width=`${Math.min(900,Math.max(50,i))}px`,this.requestUpdate()}},this._handleResizeEnd=()=>{this._resizing=null,document.removeEventListener(\"mousemove\",this._handleResizeMove),document.removeEventListener(\"mouseup\",this._handleResizeEnd)}}connectedCallback(){super.connectedCallback(),this.classList.toggle(\"kr-table--scroll-overlay\",\"overlay\"===this._scrollStyle),this.classList.toggle(\"kr-table--scroll-edge\",\"edge\"===this._scrollStyle),this._fetch(),this._initRefresh(),document.addEventListener(\"click\",this._handleClickOutsideColumnPicker),this._resizeObserver=new ResizeObserver((()=>{this._searchPositionLocked=!1,this._updateSearchPosition()})),this._resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),clearInterval(this._refreshTimer),document.removeEventListener(\"click\",this._handleClickOutsideColumnPicker),this._resizeObserver?.disconnect()}willUpdate(e){e.has(\"def\")&&(this._def={...this.def,columns:this.def.columns.map((e=>\"actions\"===e.type?{...e,label:e.label??\"\",sticky:\"right\",resizable:!1}:{...e}))},this._displayedColumns=this._def.displayedColumns||this._def.columns.map((e=>e.id)),this._fetch(),this._initRefresh())}updated(e){this._updateScrollFlags(),this._syncSlottedContent()}_syncSlottedContent(){const e=this.getDisplayedColumns().filter((e=>e.render));e.length&&(this.querySelectorAll('[slot^=\"cell-\"]').forEach((e=>e.remove())),this._data.forEach(((t,i)=>{e.forEach((e=>{const o=e.render(t);if(!o)return;const s=document.createElement(\"span\");s.slot=`cell-${i}-${e.id}`,\"actions\"===e.type&&(s.style.display=\"flex\",s.style.gap=\"8px\"),\"string\"==typeof o?s.innerHTML=o:se(o,s),this.appendChild(s)}))})))}refresh(){this._fetch()}goToPrevPage(){this._page>1&&(this._page--,this._fetch())}goToNextPage(){this._page<this._totalPages&&(this._page++,this._fetch())}goToPage(e){e>=1&&e<=this._totalPages&&(this._page=e,this._fetch())}_fetch(){if(!this._def.dataSource)return;let e;switch(this._dataState=\"loading\",this._def.dataSource.mode){case\"opensearch\":throw Error(\"Opensearch not supported yet\");case\"db\":e={page:this._page-1,size:this._pageSize,sorts:[],filterFields:[],queryFields:[],facetFields:[]},this._searchQuery?.trim().length&&this._def.columns.filter((e=>e.searchable)).forEach((t=>{e.queryFields.push({name:t.id,operation:\"CONTAINS\",value:this._searchQuery,and:!1})}));break;default:e={page:this._page-1,size:this._pageSize,sorts:[],filterFields:[],queryFields:[],facetFields:[]},this._searchQuery?.trim().length&&e.queryFields.push({name:\"_text_\",operation:\"IS\",value:Je(this._searchQuery)})}this._def.dataSource.fetch(e).then((e=>{switch(this._def.dataSource?.mode){case\"opensearch\":throw Error(\"Opensearch not supported yet\");case\"db\":{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size;break}default:{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size}}this._dataState=\"success\",this._updateSearchPosition()})).catch((e=>{this._dataState=\"error\",Fe.show({message:e instanceof Error?e.message:\"Failed to load data\",type:\"error\"})}))}_initRefresh(){clearInterval(this._refreshTimer),this._def.refreshInterval&&this._def.refreshInterval>0&&(this._refreshTimer=window.setInterval((()=>{this._fetch()}),this._def.refreshInterval))}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._page=1,this._fetch()}_getGridTemplateColumns(){return this.getDisplayedColumns().map((e=>e.width?e.width:\"actions\"===e.type?\"max-content\":\"minmax(80px, auto)\")).join(\" \")}_updateSearchPosition(){if(this._searchPositionLocked)return;const e=this.shadowRoot?.querySelector(\".search\"),t=e?.querySelector(\".search-field\");e&&t&&(e.style.justifyContent=\"center\",t.style.marginLeft=\"\",requestAnimationFrame((()=>{const i=e.getBoundingClientRect(),o=t.getBoundingClientRect().left-i.left;e.style.justifyContent=\"flex-start\",t.style.marginLeft=`${o}px`,this._searchPositionLocked=!0})))}_toggleColumnPicker(){this._columnPickerOpen=!this._columnPickerOpen}_toggleColumn(e){this._displayedColumns.includes(e)?this._displayedColumns=this._displayedColumns.filter((t=>t!==e)):this._displayedColumns=[...this._displayedColumns,e]}_handleRowMouseDown(){this._def.rowClickable&&window.getSelection()?.removeAllRanges()}_handleRowClick(e,t){if(!this._def.rowClickable)return;const i=window.getSelection();i&&i.toString().length>0||this.dispatchEvent(new CustomEvent(\"row-click\",{detail:{row:e,rowIndex:t},bubbles:!0,composed:!0}))}getDisplayedColumns(){return this._displayedColumns.map((e=>this._def.columns.find((t=>t.id===e)))).sort(((e,t)=>\"actions\"===e.type&&\"actions\"!==t.type?1:\"actions\"!==e.type&&\"actions\"===t.type?-1:0))}_handleScroll(e){const t=e.target;this._canScrollLeft=t.scrollLeft>0,this._canScrollRight=t.scrollLeft<t.scrollWidth-t.clientWidth-1}_updateScrollFlags(){const e=this.shadowRoot?.querySelector(\".content\");e&&(this._canScrollLeft=e.scrollLeft>0,this._canScrollRight=e.scrollWidth>e.clientWidth&&e.scrollLeft<e.scrollWidth-e.clientWidth-1,this._canScrollHorizontal=e.scrollWidth>e.clientWidth),this.classList.toggle(\"kr-table--scroll-left-available\",this._canScrollLeft),this.classList.toggle(\"kr-table--scroll-right-available\",this._canScrollRight),this.classList.toggle(\"kr-table--scroll-horizontal-available\",this._canScrollHorizontal),this.classList.toggle(\"kr-table--sticky-left\",this.getDisplayedColumns().some((e=>\"left\"===e.sticky))),this.classList.toggle(\"kr-table--sticky-right\",this.getDisplayedColumns().some((e=>\"right\"===e.sticky)))}_handleResizeStart(e,t){e.preventDefault();const i=this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${t}\"]`);this._resizing={columnId:t,startX:e.clientX,startWidth:i?.offsetWidth||200},document.addEventListener(\"mousemove\",this._handleResizeMove),document.addEventListener(\"mouseup\",this._handleResizeEnd)}_handleAction(e){e.href||this.dispatchEvent(new CustomEvent(\"action\",{detail:{action:e.id},bubbles:!0,composed:!0}))}_renderCellContent(e,t,i){const o=t[e.id];if(e.render)return B`<slot name=\"cell-${i}-${e.id}\"></slot>`;if(null==o)return\"\";switch(e.type){case\"number\":return\"number\"==typeof o?o.toLocaleString():String(o);case\"currency\":return\"number\"==typeof o?o.toLocaleString(\"en-US\",{style:\"currency\",currency:\"USD\"}):String(o);case\"date\":{let e;if(o instanceof Date)e=o;else if(\"string\"==typeof o&&/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(o)){const t=o.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/,\"$1.$2\").replace(\" \",\"T\")+\"Z\";e=new Date(t)}else e=new Date(o);return e.toLocaleString(void 0,{year:\"numeric\",month:\"short\",day:\"numeric\",hour:\"numeric\",minute:\"2-digit\"})}case\"boolean\":return!0===o?\"Yes\":!1===o?\"No\":\"\";default:return String(o)}}_getHeaderCellClasses(e,t){return{\"header-cell\":!0,\"header-cell--align-center\":\"center\"===e.align,\"header-cell--align-right\":\"right\"===e.align,\"header-cell--sticky-left\":\"left\"===e.sticky,\"header-cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"header-cell--sticky-right\":\"right\"===e.sticky,\"header-cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellClasses(e,t){return{cell:!0,\"cell--actions\":\"actions\"===e.type,\"cell--align-center\":\"center\"===e.align,\"cell--align-right\":\"right\"===e.align,\"cell--sticky-left\":\"left\"===e.sticky,\"cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"cell--sticky-right\":\"right\"===e.sticky,\"cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellStyle(e,t){const i={};if(\"left\"===e.sticky){let e=0;for(let i=0;i<t;i++){const t=this.getDisplayedColumns()[i];\"left\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.left=`${e}px`}if(\"right\"===e.sticky){let e=0;for(let i=t+1;i<this.getDisplayedColumns().length;i++){const t=this.getDisplayedColumns()[i];\"right\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.right=`${e}px`}return i}_renderPagination(){const e=(this._page-1)*this._pageSize+1,t=Math.min(this._page*this._pageSize,this._totalItems);return B` <div class=\"pagination\"> <span class=\"pagination-icon ${1===this._page?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${e}-${t} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page===this._totalPages?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `}_renderHeader(){return!this._def.title&&!this._def.actions?.length&&this._totalPages<=1?U:B` <div class=\"header\"> <div class=\"title\">${this._def.title??\"\"}</div> ${\"db\"!==this._def.dataSource?.mode||this._def.columns.some((e=>e.searchable))?B` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `:B`<div class=\"search\"></div>`} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${()=>this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen?\"open\":\"\"}\"> ${[...this._def.columns].filter((e=>\"actions\"!==e.type)).sort(((e,t)=>(e.label??e.id).localeCompare(t.label??t.id))).map((e=>B` <div class=\"column-picker-item\" @click=${()=>this._toggleColumn(e.id)}> <div class=\"column-picker-checkbox ${this._displayedColumns.includes(e.id)?\"checked\":\"\"}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${e.label??e.id}</span> </div> `))} </div> </div> ${1===this._def.actions?.length?B` <kr-button class=\"actions\" .href=${this._def.actions[0].href} .target=${this._def.actions[0].target} @click=${()=>this._handleAction(this._def.actions[0])} > ${this._def.actions[0].label} </kr-button> `:this._def.actions?.length?B` <kr-button class=\"actions\" .options=${this._def.actions.map((e=>({id:e.id,label:e.label})))} @option-select=${e=>this._handleAction({id:e.detail.id,label:e.detail.label})} > Actions </kr-button> `:U} </div> </div> `}_renderStatus(){return\"loading\"===this._dataState&&0===this._data.length?B`<div class=\"status\">Loading...</div>`:\"error\"===this._dataState&&0===this._data.length?B`<div class=\"status status--error\">Error loading data</div>`:0===this._data.length?B`<div class=\"status\">No data available</div>`:U}_renderTable(){return B` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map(((e,t)=>B` <div class=${we(this._getHeaderCellClasses(e,t))} style=${Me(this._getCellStyle(e,t))} data-column-id=${e.id} >${e.label??e.id}${!1!==e.resizable?B`<div class=\"header-cell__resize\" @mousedown=${t=>this._handleResizeStart(t,e.id)} ></div>`:U}</div> `))} </div> ${this._data.map(((e,t)=>{const i=this.getDisplayedColumns().map(((i,o)=>B` <div class=${we(this._getCellClasses(i,o))} style=${Me(this._getCellStyle(i,o))} data-column-id=${i.id} > ${this._renderCellContent(i,e,t)} </div> `));return this._def.rowHref?B` <a href=${this._def.rowHref(e)} class=${we({row:!0,\"row--clickable\":!0,\"row--link\":!0})} @mousedown=${()=>this._handleRowMouseDown()} @click=${()=>this._handleRowClick(e,t)} >${i}</a> `:B` <div class=${we({row:!0,\"row--clickable\":!!this._def.rowClickable})} @mousedown=${()=>this._handleRowMouseDown()} @click=${()=>this._handleRowClick(e,t)} >${i}</div> `}))} </div> </div> </div> `}render(){return this._def.columns.length?B` ${this._renderHeader()} ${this._renderTable()} `:B`<slot></slot>`}}"
|
|
936
|
+
"name": "Qe",
|
|
937
|
+
"default": "class extends ae{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"Select an option\",this.disabled=!1,this.required=!1,this.readonly=!1,this.hint=\"\",this._isOpen=!1,this._highlightedIndex=-1,this._touched=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._handleOutsideClick=e=>{e.composedPath().includes(this)||this._close()},this._handleKeyDown=e=>{if(!this._isOpen)return;const t=Array.from(this.querySelectorAll(\"kr-select-option\"));switch(e.key){case\"Escape\":this._close(),this._triggerElement?.focus();break;case\"ArrowDown\":if(e.preventDefault(),t.some((e=>!e.disabled))){let e=this._highlightedIndex+1;for(;e<t.length&&t[e]?.disabled;)e++;e<t.length&&(this._highlightedIndex=e)}break;case\"ArrowUp\":e.preventDefault();{let e=this._highlightedIndex-1;for(;e>=0&&t[e]?.disabled;)e--;e>=0&&(this._highlightedIndex=e)}break;case\"Enter\":e.preventDefault(),this._highlightedIndex>=0&&this._highlightedIndex<t.length&&this._selectOption(t[this._highlightedIndex])}},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}connectedCallback(){super.connectedCallback(),document.addEventListener(\"click\",this._handleOutsideClick),document.addEventListener(\"keydown\",this._handleKeyDown),this.addEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity()}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"click\",this._handleOutsideClick),document.removeEventListener(\"keydown\",this._handleKeyDown),this.removeEventListener(\"invalid\",this._handleInvalid)}_toggle(){if(!this.disabled&&!this.readonly)if(this._isOpen)this._close();else{this._isOpen=!0;const e=Array.from(this.querySelectorAll(\"kr-select-option\"));this._highlightedIndex=e.findIndex((e=>e.value===this.value)),requestAnimationFrame((()=>{const e=this.shadowRoot?.querySelector(\".select-dropdown\");if(e){const t=this._triggerElement.getBoundingClientRect(),i=window.innerHeight-t.bottom-4-8;e.style.top=t.bottom+4+\"px\",e.style.left=t.left+\"px\",e.style.width=t.width+\"px\",e.style.maxHeight=i+\"px\"}}))}}_close(){this._isOpen=!1,this._highlightedIndex=-1}_selectOption(e){e.disabled||(this.value=e.value,this._internals.setFormValue(this.value),this._updateValidity(),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})),this._close(),this._triggerElement?.focus())}_handleBlur(){this._touched=!0,this._updateValidity()}_updateValidity(){this.required&&!this.value?this._internals.setValidity({valueMissing:!0},\"Please select an option\",this._triggerElement):this._internals.setValidity({})}render(){const e=Array.from(this.querySelectorAll(\"kr-select-option\")),t=e.find((e=>e.value===this.value))?.label;return V` <div class=\"wrapper\"> ${this.label?V` <label> ${this.label} ${this.required?V`<span class=\"required\" aria-hidden=\"true\">*</span>`:\"\"} </label> `:B} <div class=\"select-wrapper\"> <button class=${we({\"select-trigger\":!0,\"select-trigger--open\":this._isOpen,\"select-trigger--invalid\":this._touched&&this.required&&!this.value})} type=\"button\" ?disabled=${this.disabled} aria-haspopup=\"listbox\" aria-expanded=${this._isOpen} @click=${this._toggle} @blur=${this._handleBlur} > <span class=${we({\"select-value\":!0,\"select-placeholder\":!t})}> ${t||this.placeholder} </span> <svg class=${we({\"chevron-icon\":!0,\"select-icon\":!0,\"select-icon--open\":this._isOpen})} viewBox=\"0 0 24 24\" fill=\"currentColor\" > <path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z\"/> </svg> </button> <div class=${we({\"select-dropdown\":!0,hidden:!this._isOpen})} role=\"listbox\"> <div class=\"select-options\"> ${0===e.length?V`<div class=\"select-empty\">No options available</div>`:e.map(((e,t)=>{const i=e.value===this.value;return V` <div class=${we({\"select-option\":!0,\"select-option--selected\":i,\"select-option--disabled\":e.disabled,\"select-option--highlighted\":t===this._highlightedIndex})} role=\"option\" aria-selected=${i} @click=${()=>this._selectOption(e)} @mouseenter=${()=>this._highlightedIndex=t} > ${e.label} </div> `}))} </div> </div> </div> ${this._touched&&this.required&&!this.value?V`<div class=\"validation-message\">Please select an option</div>`:this.hint?V`<div class=\"hint\">${this.hint}</div>`:\"\"} </div> <div class=\"options-slot\"> <slot @slotchange=${()=>this.requestUpdate()}></slot> </div> `}focus(){this._triggerElement?.focus()}blur(){this._triggerElement?.blur()}}"
|
|
673
938
|
},
|
|
674
939
|
{
|
|
675
940
|
"kind": "variable",
|
|
676
|
-
"name": "
|
|
677
|
-
"default": "class extends
|
|
941
|
+
"name": "Je",
|
|
942
|
+
"default": "class extends ae{constructor(){super(...arguments),this.value=\"\",this.disabled=!1}get label(){return this.textContent?.trim()||\"\"}render(){return V`<slot></slot>`}}"
|
|
678
943
|
},
|
|
679
944
|
{
|
|
680
945
|
"kind": "variable",
|
|
681
|
-
"name": "
|
|
682
|
-
"
|
|
946
|
+
"name": "et",
|
|
947
|
+
"type": {
|
|
948
|
+
"text": "object"
|
|
949
|
+
},
|
|
950
|
+
"default": "{equals:{key:\"equals\",type:\"comparison\",dataTypes:[\"string\",\"number\",\"date\",\"boolean\"],label:\"Equals\"},n_equals:{key:\"n_equals\",type:\"comparison\",dataTypes:[\"string\",\"number\",\"date\",\"boolean\"],label:\"Doesn't equal\"},contains:{key:\"contains\",type:\"comparison\",dataTypes:[\"string\"],label:\"Contains\"},n_contains:{key:\"n_contains\",type:\"comparison\",dataTypes:[\"string\"],label:\"Doesn't contain\"},starts_with:{key:\"starts_with\",type:\"comparison\",dataTypes:[\"string\"],label:\"Starts with\"},ends_with:{key:\"ends_with\",type:\"comparison\",dataTypes:[\"string\"],label:\"Ends with\"},less_than:{key:\"less_than\",type:\"comparison\",dataTypes:[\"number\",\"date\"],label:\"Less than\"},less_than_equal:{key:\"less_than_equal\",type:\"comparison\",dataTypes:[\"number\",\"date\"],label:\"Less than or equal\"},greater_than:{key:\"greater_than\",type:\"comparison\",dataTypes:[\"number\",\"date\"],label:\"Greater than\"},greater_than_equal:{key:\"greater_than_equal\",type:\"comparison\",dataTypes:[\"number\",\"date\"],label:\"Greater than or equal\"},between:{key:\"between\",type:\"range\",dataTypes:[\"number\",\"date\"],label:\"Between\"},in:{key:\"in\",type:\"list\",dataTypes:[\"string\",\"number\"],label:\"In\"},empty:{key:\"empty\",type:\"nil\",dataTypes:[\"string\",\"number\",\"date\",\"boolean\"],label:\"Empty\"},n_empty:{key:\"n_empty\",type:\"nil\",dataTypes:[\"string\",\"number\",\"date\",\"boolean\"],label:\"Not empty\"}}"
|
|
683
951
|
},
|
|
684
952
|
{
|
|
685
|
-
"kind": "
|
|
686
|
-
"name": "
|
|
953
|
+
"kind": "function",
|
|
954
|
+
"name": "tt",
|
|
955
|
+
"parameters": [
|
|
956
|
+
{
|
|
957
|
+
"name": "e"
|
|
958
|
+
}
|
|
959
|
+
]
|
|
687
960
|
},
|
|
688
961
|
{
|
|
689
|
-
"kind": "
|
|
962
|
+
"kind": "class",
|
|
963
|
+
"description": "",
|
|
690
964
|
"name": "dt",
|
|
691
|
-
"
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
965
|
+
"members": [
|
|
966
|
+
{
|
|
967
|
+
"kind": "method",
|
|
968
|
+
"name": "setKql",
|
|
969
|
+
"parameters": [
|
|
970
|
+
{
|
|
971
|
+
"name": "e"
|
|
972
|
+
}
|
|
973
|
+
]
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
"kind": "method",
|
|
977
|
+
"name": "setOperator",
|
|
978
|
+
"parameters": [
|
|
979
|
+
{
|
|
980
|
+
"name": "e"
|
|
981
|
+
}
|
|
982
|
+
]
|
|
983
|
+
},
|
|
984
|
+
{
|
|
985
|
+
"kind": "method",
|
|
986
|
+
"name": "setValue",
|
|
987
|
+
"parameters": [
|
|
988
|
+
{
|
|
989
|
+
"name": "e"
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
"name": "t"
|
|
993
|
+
}
|
|
994
|
+
]
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
"kind": "method",
|
|
998
|
+
"name": "setStart",
|
|
999
|
+
"parameters": [
|
|
1000
|
+
{
|
|
1001
|
+
"name": "e"
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
"name": "t"
|
|
1005
|
+
}
|
|
1006
|
+
]
|
|
1007
|
+
},
|
|
1008
|
+
{
|
|
1009
|
+
"kind": "method",
|
|
1010
|
+
"name": "setEnd",
|
|
1011
|
+
"parameters": [
|
|
1012
|
+
{
|
|
1013
|
+
"name": "e"
|
|
1014
|
+
},
|
|
1015
|
+
{
|
|
1016
|
+
"name": "t"
|
|
1017
|
+
}
|
|
1018
|
+
]
|
|
1019
|
+
},
|
|
1020
|
+
{
|
|
1021
|
+
"kind": "method",
|
|
1022
|
+
"name": "clear"
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
"kind": "method",
|
|
1026
|
+
"name": "isEmpty"
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
"kind": "method",
|
|
1030
|
+
"name": "has",
|
|
1031
|
+
"parameters": [
|
|
1032
|
+
{
|
|
1033
|
+
"name": "e"
|
|
1034
|
+
}
|
|
1035
|
+
]
|
|
1036
|
+
},
|
|
1037
|
+
{
|
|
1038
|
+
"kind": "method",
|
|
1039
|
+
"name": "toggle",
|
|
1040
|
+
"parameters": [
|
|
1041
|
+
{
|
|
1042
|
+
"name": "e"
|
|
1043
|
+
}
|
|
1044
|
+
]
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
"kind": "method",
|
|
1048
|
+
"name": "isValid"
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
"kind": "method",
|
|
1052
|
+
"name": "toSolrData"
|
|
1053
|
+
},
|
|
1054
|
+
{
|
|
1055
|
+
"kind": "method",
|
|
1056
|
+
"name": "toDbParams"
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
"kind": "method",
|
|
1060
|
+
"name": "_buildText"
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
"kind": "method",
|
|
1064
|
+
"name": "_format",
|
|
1065
|
+
"parameters": [
|
|
1066
|
+
{
|
|
1067
|
+
"name": "e"
|
|
1068
|
+
}
|
|
1069
|
+
]
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
"kind": "method",
|
|
1073
|
+
"name": "_parse",
|
|
1074
|
+
"parameters": [
|
|
1075
|
+
{
|
|
1076
|
+
"name": "e"
|
|
1077
|
+
}
|
|
1078
|
+
]
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
"kind": "method",
|
|
1082
|
+
"name": "_parseDate",
|
|
1083
|
+
"parameters": [
|
|
1084
|
+
{
|
|
1085
|
+
"name": "e"
|
|
1086
|
+
}
|
|
1087
|
+
]
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
"kind": "method",
|
|
1091
|
+
"name": "_buildKql"
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
"kind": "field",
|
|
1095
|
+
"name": "field",
|
|
1096
|
+
"type": {
|
|
1097
|
+
"text": "string"
|
|
1098
|
+
},
|
|
1099
|
+
"default": "\"\""
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
"kind": "field",
|
|
1103
|
+
"name": "operator",
|
|
1104
|
+
"type": {
|
|
1105
|
+
"text": "string"
|
|
1106
|
+
},
|
|
1107
|
+
"default": "\"equals\""
|
|
1108
|
+
},
|
|
1109
|
+
{
|
|
1110
|
+
"kind": "field",
|
|
1111
|
+
"name": "value",
|
|
1112
|
+
"type": {
|
|
1113
|
+
"text": "null"
|
|
1114
|
+
},
|
|
1115
|
+
"default": "null"
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
"kind": "field",
|
|
1119
|
+
"name": "kql",
|
|
1120
|
+
"type": {
|
|
1121
|
+
"text": "string"
|
|
1122
|
+
},
|
|
1123
|
+
"default": "\"\""
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
"kind": "field",
|
|
1127
|
+
"name": "text",
|
|
1128
|
+
"type": {
|
|
1129
|
+
"text": "string"
|
|
1130
|
+
},
|
|
1131
|
+
"default": "\"\""
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
"kind": "field",
|
|
1135
|
+
"name": "type",
|
|
1136
|
+
"type": {
|
|
1137
|
+
"text": "string"
|
|
1138
|
+
},
|
|
1139
|
+
"default": "\"\""
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
"kind": "field",
|
|
1143
|
+
"name": "specificity",
|
|
1144
|
+
"type": {
|
|
1145
|
+
"text": "array"
|
|
1146
|
+
},
|
|
1147
|
+
"default": "[]"
|
|
1148
|
+
}
|
|
1149
|
+
]
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
"kind": "variable",
|
|
1153
|
+
"name": "pt",
|
|
1154
|
+
"default": "class extends ae{constructor(){super(...arguments),this._scrollStyle=\"overlay\",this._data=[],this._dataState=\"idle\",this._page=1,this._pageSize=50,this._totalItems=0,this._totalPages=0,this._searchQuery=\"\",this._canScrollLeft=!1,this._canScrollRight=!1,this._canScrollHorizontal=!1,this._columnPickerOpen=!1,this._filterPanelOpened=null,this._filterPanelTab=\"filter\",this._buckets=new Map,this._filterPanelPos={top:0,left:0},this._resizing=null,this._resizeObserver=null,this._searchPositionLocked=!1,this._model=new ht,this.def={columns:[]},this._handleClickOutside=e=>{const t=e.composedPath();if(this._columnPickerOpen){const e=this.shadowRoot?.querySelector(\".column-picker-wrapper\");e&&!t.includes(e)&&(this._columnPickerOpen=!1)}this._filterPanelOpened&&(t.some((e=>e.classList?.contains(\"filter-panel\")))||this._handleFilterApply())},this._handleResizeMove=e=>{if(!this._resizing)return;const t=this._model.columns.find((e=>e.id===this._resizing.columnId));if(t){const i=this._resizing.startWidth+(e.clientX-this._resizing.startX);t.width=`${Math.min(900,Math.max(50,i))}px`,this.requestUpdate()}},this._handleResizeEnd=()=>{this._resizing=null,document.removeEventListener(\"mousemove\",this._handleResizeMove),document.removeEventListener(\"mouseup\",this._handleResizeEnd)}}connectedCallback(){super.connectedCallback(),this.classList.toggle(\"kr-table--scroll-overlay\",\"overlay\"===this._scrollStyle),this.classList.toggle(\"kr-table--scroll-edge\",\"edge\"===this._scrollStyle),this._fetch(),this._initRefresh(),document.addEventListener(\"click\",this._handleClickOutside),this._resizeObserver=new ResizeObserver((()=>{this._searchPositionLocked=!1,this._updateSearchPosition()})),this._resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),clearInterval(this._refreshTimer),document.removeEventListener(\"click\",this._handleClickOutside),this._resizeObserver?.disconnect()}willUpdate(e){e.has(\"def\")&&(this._model=new ht,this.def.title&&(this._model.title=this.def.title),this.def.actions&&(this._model.actions=this.def.actions),this.def.data&&(this._model.data=this.def.data),this.def.dataSource&&(this._model.dataSource=this.def.dataSource),\"number\"==typeof this.def.refreshInterval&&(this._model.refreshInterval=this.def.refreshInterval),\"number\"==typeof this.def.pageSize&&(this._model.pageSize=this.def.pageSize),this.def.rowClickable&&(this._model.rowClickable=this.def.rowClickable),this.def.rowHref&&(this._model.rowHref=this.def.rowHref),this._model.columns=this.def.columns.map((e=>{const t={...e,filter:null};return t.type||(t.type=\"string\"),\"actions\"===t.type?(t.label=e.label??\"\",t.sticky=\"right\",t.resizable=!1,t):((e.filterable||e.facetable)&&(t.filter=new dt,t.filter.field=e.id,t.filter.type=t.type,e.facetable&&!e.filterable?(t.filter.operator=\"in\",t.filter.value=[]):\"string\"===t.filter.type&&(t.filter.operator=\"contains\")),t)})),this.def.displayedColumns?this._model.displayedColumns=this.def.displayedColumns:this._model.displayedColumns=this._model.columns.map((e=>e.id)),this._fetch(),this._initRefresh())}updated(e){this._updateScrollFlags(),this._syncSlottedContent()}_syncSlottedContent(){const e=this.getDisplayedColumns().filter((e=>e.render));e.length&&(this.querySelectorAll('[slot^=\"cell-\"]').forEach((e=>e.remove())),this._data.forEach(((t,i)=>{e.forEach((e=>{const s=e.render(t);if(!s)return;const o=document.createElement(\"span\");o.slot=`cell-${i}-${e.id}`,\"actions\"===e.type&&(o.style.display=\"flex\",o.style.gap=\"8px\"),\"string\"==typeof s?o.innerHTML=s:oe(s,o),this.appendChild(o)}))})))}refresh(){this._fetch()}goToPrevPage(){this._page>1&&(this._page--,this._fetch())}goToNextPage(){this._page<this._totalPages&&(this._page++,this._fetch())}goToPage(e){e>=1&&e<=this._totalPages&&(this._page=e,this._fetch())}_toSolrData(){const e={page:this._page-1,size:this._pageSize,sorts:[],filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns){if(!t.filter||t.filter.isEmpty()||!t.filter.isValid())continue;const i=t.filter.toSolrData();t.facetable&&\"in\"===t.filter.operator&&(i.tagged=!0),e.filterFields.push(i)}for(const t of this._model.columns)t.facetable&&e.facetFields.push({name:t.id,type:\"FIELD\",limit:100,sort:\"count\",minimumCount:1});return this._searchQuery?.trim().length&&e.queryFields.push({name:\"_text_\",operation:\"IS\",value:ot(this._searchQuery,!1)}),e}_toDbParams(){const e={page:this._page-1,size:this._pageSize,sorts:[],filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns)t.filter&&!t.filter.isEmpty()&&t.filter.isValid()&&e.filterFields.push(t.filter.toDbParams());return this._searchQuery?.trim().length&&this._model.columns.filter((e=>e.searchable)).forEach((t=>{e.queryFields.push({name:t.id,operation:\"CONTAINS\",value:this._searchQuery,and:!1})})),e}_fetch(){if(this._model.data)return this._data=this._model.data,this._totalItems=this._model.data.length,this._totalPages=Math.ceil(this._model.data.length/this._pageSize),void(this._dataState=\"success\");if(!this._model.dataSource)return;let e;this._dataState=\"loading\",e=\"db\"===this._model.dataSource.mode?this._toDbParams():this._toSolrData(),this._model.dataSource.fetch(e).then((e=>{switch(this._model.dataSource?.mode){case\"opensearch\":throw Error(\"Opensearch not supported yet\");case\"db\":{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size;break}default:{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size,this._parseFacetResults(t)}}this._dataState=\"success\",this._updateSearchPosition()})).catch((e=>{this._dataState=\"error\",Fe.show({message:e instanceof Error?e.message:\"Failed to load data\",type:\"error\"})}))}_parseFacetResults(e){if(e.data.facetFields){for(const t of this._model.columns){if(!t.facetable)continue;const i=e.data.facetFields[t.id];if(!i){this._buckets.set(t.id,[]);continue}const s=[];for(const e of i){let i=e.name;\"boolean\"===t.type&&\"string\"==typeof e.name&&(\"true\"===e.name?i=!0:\"false\"===e.name&&(i=!1)),null===e.name&&e.count>0&&s.unshift({val:null,count:e.count}),null!==e.name&&s.push({val:i,count:e.count})}if(t.filter&&\"in\"===t.filter.operator&&Array.isArray(t.filter.value))for(const e of t.filter.value)s.some((t=>t.val===e))||s.push({val:e,count:0});this._buckets.set(t.id,s)}this._buckets=new Map(this._buckets)}}_initRefresh(){clearInterval(this._refreshTimer),this._model.refreshInterval&&this._model.refreshInterval>0&&(this._refreshTimer=window.setInterval((()=>{this._fetch()}),this._model.refreshInterval))}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._page=1,this._fetch()}_getGridTemplateColumns(){return this.getDisplayedColumns().map((e=>e.width?e.width:\"actions\"===e.type?\"max-content\":\"minmax(80px, auto)\")).join(\" \")}_updateSearchPosition(){if(this._searchPositionLocked)return;const e=this.shadowRoot?.querySelector(\".search\"),t=e?.querySelector(\".search-field\");e&&t&&(e.style.justifyContent=\"center\",t.style.marginLeft=\"\",requestAnimationFrame((()=>{const i=e.getBoundingClientRect(),s=t.getBoundingClientRect().left-i.left;e.style.justifyContent=\"flex-start\",t.style.marginLeft=`${s}px`,this._searchPositionLocked=!0})))}_toggleColumnPicker(){this._columnPickerOpen=!this._columnPickerOpen}_toggleColumn(e){this._model.displayedColumns.includes(e)?this._model.displayedColumns=this._model.displayedColumns.filter((t=>t!==e)):this._model.displayedColumns=[...this._model.displayedColumns,e]}_handleRowMouseDown(){this._model.rowClickable&&window.getSelection()?.removeAllRanges()}_handleRowClick(e,t){if(!this._model.rowClickable)return;const i=window.getSelection();i&&i.toString().length>0||this.dispatchEvent(new CustomEvent(\"row-click\",{detail:{row:e,rowIndex:t},bubbles:!0,composed:!0}))}getDisplayedColumns(){return this._model.displayedColumns.map((e=>this._model.columns.find((t=>t.id===e)))).sort(((e,t)=>\"actions\"===e.type&&\"actions\"!==t.type?1:\"actions\"!==e.type&&\"actions\"===t.type?-1:0))}_handleScroll(e){const t=e.target;this._canScrollLeft=t.scrollLeft>0,this._canScrollRight=t.scrollLeft<t.scrollWidth-t.clientWidth-1}_updateScrollFlags(){const e=this.shadowRoot?.querySelector(\".content\");e&&(this._canScrollLeft=e.scrollLeft>0,this._canScrollRight=e.scrollWidth>e.clientWidth&&e.scrollLeft<e.scrollWidth-e.clientWidth-1,this._canScrollHorizontal=e.scrollWidth>e.clientWidth),this.classList.toggle(\"kr-table--scroll-left-available\",this._canScrollLeft),this.classList.toggle(\"kr-table--scroll-right-available\",this._canScrollRight),this.classList.toggle(\"kr-table--scroll-horizontal-available\",this._canScrollHorizontal),this.classList.toggle(\"kr-table--sticky-left\",this.getDisplayedColumns().some((e=>\"left\"===e.sticky))),this.classList.toggle(\"kr-table--sticky-right\",this.getDisplayedColumns().some((e=>\"right\"===e.sticky)))}_handleResizeStart(e,t){e.preventDefault();const i=this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${t}\"]`);this._resizing={columnId:t,startX:e.clientX,startWidth:i?.offsetWidth||200},document.addEventListener(\"mousemove\",this._handleResizeMove),document.addEventListener(\"mouseup\",this._handleResizeEnd)}_handleAction(e){e.href||this.dispatchEvent(new CustomEvent(\"action\",{detail:{action:e.id},bubbles:!0,composed:!0}))}_handleKqlChange(e,t){const i=e.target.value.trim();if(i){if(t.filter.setKql(i),this.requestUpdate(),!t.filter.isValid())return}else t.filter.clear(),this.requestUpdate();this._page=1,this._fetch()}_handleFilterPanelToggle(e,t){if(e.stopPropagation(),this._filterPanelOpened===t.id)this._filterPanelOpened=null;else{const i=e.currentTarget.getBoundingClientRect();this._filterPanelPos={top:i.bottom+4,left:i.left},this._filterPanelOpened=t.id,t.facetable?this._filterPanelTab=\"counts\":this._filterPanelTab=\"filter\"}}_handleKqlClear(e){e.filter.clear(),this._page=1,this._fetch()}_handleFilterClear(){const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));e&&(e.filter.clear(),e.facetable&&!e.filterable&&(e.filter.operator=\"in\",e.filter.value=[])),this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterTextKeydown(e,t){\"Enter\"===e.key&&(e.preventDefault(),this._handleFilterApply())}_handleOperatorChange(e,t){t.filter.setOperator(e.target.value),this.requestUpdate()}_handleFilterStringChange(e,t){t.filter.setValue(e.target.value),this.requestUpdate()}_handleFilterNumberChange(e,t){t.filter.setValue(Number(e.target.value)),this.requestUpdate()}_handleFilterDateChange(e,t){t.filter.setValue(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterBooleanChange(e,t){t.filter.setValue(\"true\"===e.target.value),this.requestUpdate()}_handleFilterDateStartChange(e,t){t.filter.setStart(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterDateEndChange(e,t){t.filter.setEnd(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterNumberStartChange(e,t){t.filter.setStart(Number(e.target.value)),this.requestUpdate()}_handleFilterNumberEndChange(e,t){t.filter.setEnd(Number(e.target.value)),this.requestUpdate()}_handleFilterListChange(e,t){const i=e.target.value.split(\",\").map((e=>e.trim())).filter((e=>\"\"!==e));\"number\"===t.type?t.filter.setValue(i.map((e=>Number(e)))):t.filter.setValue(i),this.requestUpdate()}_handleFilterApply(){this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterPanelTabChange(e){this._filterPanelTab=e.detail.activeTabId}_handleBucketToggle(e,t,i){t.filter.toggle(i.val),this._page=1,this._fetch()}_renderCellContent(e,t,i){const s=t[e.id];if(e.render)return V`<slot name=\"cell-${i}-${e.id}\"></slot>`;if(null==s)return\"\";switch(e.type){case\"number\":return\"currency\"===e.format&&\"number\"==typeof s?s.toLocaleString(\"en-US\",{style:\"currency\",currency:\"USD\"}):String(s);case\"date\":{let e;if(s instanceof Date)e=s;else if(\"string\"==typeof s&&/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(s)){const t=s.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/,\"$1.$2\").replace(\" \",\"T\")+\"Z\";e=new Date(t)}else e=new Date(s);return e.toLocaleString(void 0,{year:\"numeric\",month:\"short\",day:\"numeric\",hour:\"numeric\",minute:\"2-digit\",timeZone:\"UTC\"})}case\"boolean\":return!0===s?\"Yes\":!1===s?\"No\":\"\";default:return String(s)}}_getHeaderCellClasses(e,t){return{\"header-cell\":!0,\"header-cell--align-center\":\"center\"===e.align,\"header-cell--align-right\":\"right\"===e.align,\"header-cell--sticky-left\":\"left\"===e.sticky,\"header-cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"header-cell--sticky-right\":\"right\"===e.sticky,\"header-cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellClasses(e,t){return{cell:!0,\"cell--actions\":\"actions\"===e.type,\"cell--align-center\":\"center\"===e.align,\"cell--align-right\":\"right\"===e.align,\"cell--sticky-left\":\"left\"===e.sticky,\"cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"cell--sticky-right\":\"right\"===e.sticky,\"cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellStyle(e,t){const i={};if(\"left\"===e.sticky){let e=0;for(let i=0;i<t;i++){const t=this.getDisplayedColumns()[i];\"left\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.left=`${e}px`}if(\"right\"===e.sticky){let e=0;for(let i=t+1;i<this.getDisplayedColumns().length;i++){const t=this.getDisplayedColumns()[i];\"right\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.right=`${e}px`}return i}_renderPagination(){const e=(this._page-1)*this._pageSize+1,t=Math.min(this._page*this._pageSize,this._totalItems);return V` <div class=\"pagination\"> <span class=\"pagination-icon ${1===this._page?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${e}-${t} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page===this._totalPages?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `}_renderHeader(){return!this._model.title&&!this._model.actions?.length&&this._totalPages<=1?B:V` <div class=\"header\"> <div class=\"title\">${this._model.title??\"\"}</div> ${\"db\"!==this._model.dataSource?.mode||this._model.columns.some((e=>e.searchable))?V` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `:V`<div class=\"search\"></div>`} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${()=>this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen?\"open\":\"\"}\"> ${[...this._model.columns].filter((e=>\"actions\"!==e.type)).sort(((e,t)=>(e.label??e.id).localeCompare(t.label??t.id))).map((e=>V` <div class=\"column-picker-item\" @click=${()=>this._toggleColumn(e.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(e.id)?\"checked\":\"\"}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${e.label??e.id}</span> </div> `))} </div> </div> ${1===this._model.actions?.length?V` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${()=>this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> `:this._model.actions?.length?V` <kr-button class=\"actions\" .options=${this._model.actions.map((e=>({id:e.id,label:e.label})))} @option-select=${e=>this._handleAction({id:e.detail.id,label:e.detail.label})} > Actions </kr-button> `:B} </div> </div> `}_renderStatus(){return\"loading\"===this._dataState&&0===this._data.length?V`<div class=\"status\">Loading...</div>`:\"error\"===this._dataState&&0===this._data.length?V`<div class=\"status status--error\">Error loading data</div>`:0===this._data.length?V`<div class=\"status\">No data available</div>`:B}_renderFilterPanel(){if(!this._filterPanelOpened)return B;const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));let t=V``;t=\"empty\"===e.filter.operator||\"n_empty\"===e.filter.operator?V` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${e.filter.text} /> `:\"between\"===e.filter.operator&&\"date\"===e.type?V` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.start??null} @change=${t=>this._handleFilterDateStartChange(t,e)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.end??null} @change=${t=>this._handleFilterDateEndChange(t,e)} /> `:\"between\"===e.filter.operator&&\"number\"===e.type?V` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${e.filter.value?.start??\"\"} @input=${t=>this._handleFilterNumberStartChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${e.filter.value?.end??\"\"} @input=${t=>this._handleFilterNumberEndChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:\"in\"===e.filter.operator?V` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${e.filter.text} @input=${t=>this._handleFilterListChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} ></textarea> `:\"boolean\"===e.type?V` <kr-select-field placeholder=\"Value\" .value=${String(e.filter.value??\"\")} @change=${t=>this._handleFilterBooleanChange(t,e)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `:\"date\"===e.type?V` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value} @change=${t=>this._handleFilterDateChange(t,e)} /> `:\"number\"===e.type?V` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${e.filter.text} @input=${t=>this._handleFilterNumberChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:V` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${e.filter.text} @input=${t=>this._handleFilterStringChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `;const i=V` <div class=\"filter-panel__content\"> <kr-select-field .value=${e.filter.operator} @change=${t=>this._handleOperatorChange(t,e)} > ${tt(e.type).map((e=>V` <kr-select-option value=${e.key}>${e.label}</kr-select-option> `))} </kr-select-field> ${t} </div> `,s=this._buckets.get(e.id)||[];let o,r;return o=s.length?V` <div class=\"buckets\"> ${s.map((t=>{let i=\"(Empty)\";null!==t.val&&void 0!==t.val&&(i=\"boolean\"===e.type?!0===t.val||\"true\"===t.val?\"Yes\":\"No\":String(t.val));let s=B;return e.filter.has(t.val)&&(s=V` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `),V` <div class=\"bucket\" @click=${i=>this._handleBucketToggle(i,e,t)} > <div class=${we({bucket__checkbox:!0,\"bucket__checkbox--checked\":e.filter.has(t.val)})}> ${s} </div> <span class=\"bucket__label\">${i}</span> <span class=\"bucket__count\">${t.count}</span> </div> `}))} </div> `:V`<div class=\"bucket-empty\">No data</div>`,r=e.facetable&&e.filterable?V` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${e=>this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${i} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${o} </kr-tab> </kr-tab-group> `:e.facetable?o:i,V` <div class=\"filter-panel\" style=${Ie({top:this._filterPanelPos.top+\"px\",left:this._filterPanelPos.left+\"px\"})} > ${r} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `}_renderFilterRow(){const e=this.getDisplayedColumns();return e.some((e=>e.filterable||e.facetable))?V` <div class=\"filter-row\"> ${e.map(((t,i)=>t.filterable||t.facetable?V` <div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Ie(this._getCellStyle(t,i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${we({\"filter-cell__input\":!0,\"filter-cell__input--invalid\":!t.filter.isValid()})} .value=${t.filter.kql} @change=${e=>this._handleKqlChange(e,t)} /> ${t.filter?.kql?.length>0?V` <button class=\"filter-cell__clear\" @click=${()=>this._handleKqlClear(t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> `:B} <button class=${we({\"filter-cell__advanced\":!0,\"filter-cell__advanced--opened\":this._filterPanelOpened===t.id})} @click=${e=>this._handleFilterPanelToggle(e,t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `:V`<div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Ie(this._getCellStyle(t,i))} ></div>`))} </div> `:B}_renderTable(){return V` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map(((e,t)=>V` <div class=${we(this._getHeaderCellClasses(e,t))} style=${Ie(this._getCellStyle(e,t))} data-column-id=${e.id} >${e.label??e.id}${!1!==e.resizable?V`<div class=\"header-cell__resize\" @mousedown=${t=>this._handleResizeStart(t,e.id)} ></div>`:B}</div> `))} </div> ${this._renderFilterRow()} ${this._data.map(((e,t)=>{const i=this.getDisplayedColumns().map(((i,s)=>V` <div class=${we(this._getCellClasses(i,s))} style=${Ie(this._getCellStyle(i,s))} data-column-id=${i.id} > ${this._renderCellContent(i,e,t)} </div> `));return this._model.rowHref?V` <a href=${this._model.rowHref(e)} class=${we({row:!0,\"row--clickable\":!0,\"row--link\":!0})} @mousedown=${()=>this._handleRowMouseDown()} @click=${()=>this._handleRowClick(e,t)} >${i}</a> `:V` <div class=${we({row:!0,\"row--clickable\":!!this._model.rowClickable})} @mousedown=${()=>this._handleRowMouseDown()} @click=${()=>this._handleRowClick(e,t)} >${i}</div> `}))} </div> </div> </div> `}render(){return this._model.columns.length?V` ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `:V`<slot></slot>`}}"
|
|
1155
|
+
},
|
|
1156
|
+
{
|
|
1157
|
+
"kind": "variable",
|
|
1158
|
+
"name": "ft",
|
|
1159
|
+
"default": "class extends ae{constructor(){super(...arguments),this.size=\"md\",this.color=\"dark\"}render(){var e=\"\",t=\"\";return e=\"sm\"==this.size?\"16px\":\"md\"==this.size?\"24px\":\"lg\"==this.size?\"32px\":\"xl\"==this.size?\"48px\":this.size,t=\"dark\"==this.color?\"#163052\":\"light\"==this.color?\"#ffffff\":this.color,V` <svg class=\"spinner\" style=${`width: ${e}; height: ${e}; color: ${t}`} viewBox=\"0 0 44 44\" role=\"status\" aria-label=\"Loading\" > <circle class=\"circle\" cx=\"22\" cy=\"22\" r=\"20\" fill=\"none\" stroke-width=\"4\" /> </svg> `}}"
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
"kind": "variable",
|
|
1163
|
+
"name": "vt",
|
|
1164
|
+
"default": "class extends ae{constructor(){super(...arguments),this.color=\"dark\"}render(){let e=\"\",t=\"\";return e=\"dark\"===this.color?\"#163052\":\"light\"===this.color?\"#ffffff\":this.color,t=this.trackColor?this.trackColor:\"light\"===this.color?\"#ffffff4d\":\"#0000001a\",V` <div class=\"progress-bar\" style=${`background: ${t}`} role=\"status\" aria-label=\"Loading\" > <div class=\"fill\" style=${`background: ${e}`}></div> </div> `}}"
|
|
1165
|
+
},
|
|
1166
|
+
{
|
|
1167
|
+
"kind": "variable",
|
|
1168
|
+
"name": "_t"
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
"kind": "variable",
|
|
1172
|
+
"name": "xt",
|
|
1173
|
+
"default": "class extends ae{constructor(){super(...arguments),this.files=[],this.emptyMessage=\"No files\"}_handleFileClick(e){if(this.dispatchEvent(new CustomEvent(\"file-click\",{bubbles:!0,composed:!0,detail:{file:e}})),e.url){_t.open({src:e.url,name:e.name}).addEventListener(\"download\",(()=>{this._handleDownload(e)}))}}_handleDownload(e){this.dispatchEvent(new CustomEvent(\"download\",{bubbles:!0,composed:!0,detail:{file:e}}))}_handleDelete(e){this.dispatchEvent(new CustomEvent(\"delete\",{bubbles:!0,composed:!0,detail:{file:e}}))}_getExtension(e){return e.split(\".\").pop()?.toLowerCase()||\"\"}_getExtClass(e){return[\"pdf\"].includes(e)?\"file-list__ext--pdf\":[\"doc\",\"docx\",\"rtf\",\"txt\"].includes(e)?\"file-list__ext--doc\":[\"xls\",\"xlsx\",\"csv\"].includes(e)?\"file-list__ext--xls\":[\"zip\",\"rar\",\"7z\",\"gz\",\"tar\"].includes(e)?\"file-list__ext--zip\":[\"jpg\",\"jpeg\",\"png\",\"gif\",\"webp\",\"svg\",\"bmp\"].includes(e)?\"file-list__ext--img\":\"file-list__ext--default\"}_getExtIcon(e){return[\"jpg\",\"jpeg\",\"png\",\"gif\",\"webp\",\"svg\",\"bmp\"].includes(e)?V`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4.86 8.86-3 3.87L9 13.14 6 17h12l-3.86-5.14z\"/></svg>`:[\"pdf\"].includes(e)?V`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8.5 7.5c0 .83-.67 1.5-1.5 1.5H9v2H7.5V7H10c.83 0 1.5.67 1.5 1.5v1zm5 2c0 .83-.67 1.5-1.5 1.5h-2.5V7H15c.83 0 1.5.67 1.5 1.5v3zm4-3H19v1h1.5V11H19v2h-1.5V7h3v1.5zM9 9.5h1v-1H9v1zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm10 5.5h1v-3h-1v3z\"/></svg>`:[\"doc\",\"docx\",\"rtf\",\"txt\"].includes(e)?V`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6zm2-6h8v2H8v-2zm0-4h8v2H8v-2zm0 8h5v2H8v-2z\"/></svg>`:[\"xls\",\"xlsx\",\"csv\"].includes(e)?V`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 2v3H5V5h14zm0 5v4H5v-4h14zM5 19v-3h14v3H5zm2-8h4v2H7v-2zm0 5h4v2H7v-2z\"/></svg>`:[\"zip\",\"rar\",\"7z\",\"gz\",\"tar\"].includes(e)?V`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 6h-8l-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V6h5.17l2 2H20v10zm-8-4h2v2h-2v-2zm0-4h2v2h-2v-2zm-2 2h2v2h-2v-2z\"/></svg>`:V`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z\"/></svg>`}render(){return this.files.length?V` <div class=\"file-list\"> ${this.files.map((e=>{const t=this._getExtension(e.name),i=e.meta||e.date||\"\";return V` <div class=\"file-list__item\"> <div class=\"file-list__ext ${this._getExtClass(t)}\">${this._getExtIcon(t)}</div> <div class=\"file-list__info\"> <a class=\"file-list__name\" @click=${()=>this._handleFileClick(e)}>${e.name}</a> ${i?V`<div class=\"file-list__meta\">${i}</div>`:\"\"} </div> <div class=\"file-list__actions\"> <svg class=\"file-list__action\" @click=${()=>this._handleDownload(e)} xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" title=\"Download\"><path d=\"M19 9h-4V3H9v6H5l7 7 7-7zm-8 2V5h2v6h1.17L12 13.17 9.83 11H11zm-6 7h14v2H5v-2z\"/></svg> <svg class=\"file-list__action file-list__action--delete\" @click=${()=>this._handleDelete(e)} xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" title=\"Delete\"><path d=\"M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z\"/></svg> </div> </div> `}))} </div> `:V`<div class=\"file-list__empty\">${this.emptyMessage}</div>`}}"
|
|
1174
|
+
},
|
|
1175
|
+
{
|
|
1176
|
+
"kind": "variable",
|
|
1177
|
+
"name": "St",
|
|
1178
|
+
"default": "class extends ae{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"\",this.type=\"text\",this.required=!1,this.disabled=!1,this.readonly=!1,this.autocomplete=\"\",this.hint=\"\",this._touched=!1,this._dirty=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._dirty=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}connectedCallback(){super.connectedCallback(),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity()}_updateValidity(){this._input&&this._internals.setValidity(this._input.validity,this._input.validationMessage)}_handleInput(e){this.value=e.target.value,this._dirty=!0,this._internals.setFormValue(this.value),this._internals.setValidity(this._input.validity,this._input.validationMessage)}_handleChange(e){this.value=e.target.value,this._internals.setFormValue(this.value)}_handleBlur(){this._touched=!0,this._internals.setValidity(this._input.validity,this._input.validationMessage)}render(){let e=\"\";return this._touched&&this._input&&!this._input.validity.valid&&(e=this._input.validationMessage),V` <div class=\"wrapper\"> ${this.label?V` <label for=\"input\"> ${this.label} ${this.required?V`<span class=\"required\" aria-hidden=\"true\">*</span>`:\"\"} </label> `:\"\"} <input id=\"input\" class=${we({\"input--invalid\":this._touched&&this._input&&!this._input.validity.valid})} type=${this.type} name=${this.name} .value=${$t(this.value)} placeholder=${this.placeholder} ?required=${this.required} ?disabled=${this.disabled} ?readonly=${this.readonly} minlength=${kt(this.minlength)} maxlength=${kt(this.maxlength)} pattern=${kt(this.pattern)} autocomplete=${kt(this.autocomplete||void 0)} @input=${this._handleInput} @change=${this._handleChange} @blur=${this._handleBlur} /> ${e?V`<div class=\"validation-message\">${e}</div>`:this.hint?V`<div class=\"hint\">${this.hint}</div>`:\"\"} </div> `}focus(){this._input?.focus()}blur(){this._input?.blur()}select(){this._input?.select()}}"
|
|
1179
|
+
},
|
|
1180
|
+
{
|
|
1181
|
+
"kind": "variable",
|
|
1182
|
+
"name": "zt",
|
|
1183
|
+
"default": "class extends ae{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"\",this.required=!1,this.disabled=!1,this.readonly=!1,this.rows=3,this.autocomplete=\"\",this.hint=\"\",this._touched=!1,this._dirty=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._dirty=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}connectedCallback(){super.connectedCallback(),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity()}_updateValidity(){this._textarea&&this._internals.setValidity(this._textarea.validity,this._textarea.validationMessage)}_handleInput(e){this.value=e.target.value,this._dirty=!0,this._internals.setFormValue(this.value),this._internals.setValidity(this._textarea.validity,this._textarea.validationMessage)}_handleChange(e){this.value=e.target.value,this._internals.setFormValue(this.value)}_handleBlur(){this._touched=!0,this._internals.setValidity(this._textarea.validity,this._textarea.validationMessage)}render(){let e=\"\";return this._touched&&this._textarea&&!this._textarea.validity.valid&&(e=this._textarea.validationMessage),V` <div class=\"wrapper\"> ${this.label?V` <label for=\"textarea\"> ${this.label} ${this.required?V`<span class=\"required\" aria-hidden=\"true\">*</span>`:B} </label> `:B} <textarea id=\"textarea\" class=${we({\"textarea--invalid\":this._touched&&this._textarea&&!this._textarea.validity.valid})} name=${this.name} .value=${$t(this.value)} placeholder=${this.placeholder} ?required=${this.required} ?disabled=${this.disabled} ?readonly=${this.readonly} rows=${this.rows} cols=${kt(this.cols)} minlength=${kt(this.minlength)} maxlength=${kt(this.maxlength)} autocomplete=${kt(this.autocomplete||void 0)} @input=${this._handleInput} @change=${this._handleChange} @blur=${this._handleBlur} ></textarea> ${e?V`<div class=\"validation-message\">${e}</div>`:this.hint?V`<div class=\"hint\">${this.hint}</div>`:B} </div> `}focus(){this._textarea?.focus()}blur(){this._textarea?.blur()}select(){this._textarea?.select()}}"
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
"kind": "variable",
|
|
1187
|
+
"name": "Dt",
|
|
1188
|
+
"default": "class extends ae{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"\",this.disabled=!1,this.readonly=!1,this.required=!1,this.hint=\"\",this.options=[],this.statusType=\"finished\",this.loadingText=\"Loading...\",this.errorText=\"Error loading options\",this.emptyText=\"No matches found\",this.filteringType=\"auto\",this.highlightMatches=!0,this._isOpen=!1,this._highlightedIndex=-1,this._touched=!1,this._dirty=!1,this._handleDocumentClick=this._onDocumentClick.bind(this),this._internals=this.attachInternals()}connectedCallback(){super.connectedCallback(),document.addEventListener(\"click\",this._handleDocumentClick)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"click\",this._handleDocumentClick)}firstUpdated(){this._updateFormValue()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._dirty=!1,this._isOpen=!1,this._highlightedIndex=-1,this._updateFormValue()}formStateRestoreCallback(e){this.value=e}get _filteredOptions(){if(\"manual\"===this.filteringType||!this.value)return this.options;const e=this.value.toLowerCase(),t=[];for(const i of this.options)if(At(i)){const s=i.options.filter((t=>{const i=(t.label||t.value).toLowerCase(),s=t.filteringTags?.join(\" \").toLowerCase()||\"\";return i.includes(e)||s.includes(e)}));s.length>0&&t.push({...i,options:s})}else{const s=(i.label||i.value).toLowerCase(),o=i.filteringTags?.join(\" \").toLowerCase()||\"\";(s.includes(e)||o.includes(e))&&t.push(i)}return t}get _flatOptions(){const e=[];for(const t of this._filteredOptions)At(t)?e.push(...t.options):e.push(t);return e}_updateFormValue(){this._internals.setFormValue(this.value),this.required&&!this.value?this._internals.setValidity({valueMissing:!0},\"This field is required\",this._input):this._internals.setValidity({})}_onInput(e){const t=e.target;this.value=t.value,this._dirty=!0,this._isOpen=!0,this._highlightedIndex=-1,this._updateFormValue(),this.dispatchEvent(new CustomEvent(\"change\",{detail:{value:this.value},bubbles:!0,composed:!0})),\"manual\"===this.filteringType&&this.dispatchEvent(new CustomEvent(\"load-items\",{detail:{filteringText:this.value},bubbles:!0,composed:!0}))}_onFocus(){this._isOpen=!0,\"manual\"===this.filteringType&&this.dispatchEvent(new CustomEvent(\"load-items\",{detail:{filteringText:this.value},bubbles:!0,composed:!0}))}_onBlur(){this._touched=!0,setTimeout((()=>{this._isOpen=!1,this._highlightedIndex=-1}),200),this._updateFormValue()}_onKeyDown(e){const t=this._flatOptions;switch(e.key){case\"ArrowDown\":e.preventDefault(),this._isOpen=!0,this._highlightedIndex=Math.min(this._highlightedIndex+1,t.length-1),this._scrollToHighlighted();break;case\"ArrowUp\":e.preventDefault(),this._highlightedIndex=Math.max(this._highlightedIndex-1,-1),this._scrollToHighlighted();break;case\"Enter\":this._highlightedIndex>=0&&t[this._highlightedIndex]&&(e.preventDefault(),this._selectOption(t[this._highlightedIndex]));break;case\"Escape\":e.preventDefault(),this._isOpen=!1,this._highlightedIndex=-1;break;case\"Tab\":this._isOpen=!1,this._highlightedIndex=-1}}_scrollToHighlighted(){this.updateComplete.then((()=>{const e=this.shadowRoot?.querySelector(\".dropdown\"),t=this.shadowRoot?.querySelector(\".option.is-highlighted\");if(e&&t){const i=e.getBoundingClientRect(),s=t.getBoundingClientRect();(s.bottom>i.bottom||s.top<i.top)&&t.scrollIntoView({block:\"nearest\"})}}))}_selectOption(e){e.disabled||(this.value=e.label||e.value,this._isOpen=!1,this._highlightedIndex=-1,this._dirty=!0,this._updateFormValue(),this.dispatchEvent(new CustomEvent(\"select\",{detail:{value:e.value,selectedOption:e},bubbles:!0,composed:!0})),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})))}_handleClear(){this.value=\"\",this._updateFormValue(),this.dispatchEvent(new CustomEvent(\"change\",{detail:{value:\"\"},bubbles:!0,composed:!0})),this._input?.focus()}_onDocumentClick(e){e.composedPath().includes(this)||(this._isOpen=!1)}_highlightMatch(e){if(!this.value||\"manual\"===this.filteringType||!this.highlightMatches)return V`${e}`;const t=this.value.toLowerCase(),i=e.toLowerCase().indexOf(t);if(-1===i)return V`${e}`;const s=e.slice(0,i),o=e.slice(i,i+this.value.length),r=e.slice(i+this.value.length);return V`${s}<span class=\"highlight\">${o}</span>${r}`}_renderOption(e,t){const i=t===this._highlightedIndex;return V` <button class=${we({option:!0,\"is-highlighted\":i})} type=\"button\" role=\"option\" aria-selected=${i} ?disabled=${e.disabled} @click=${()=>this._selectOption(e)} @mouseenter=${()=>{this._highlightedIndex=t}} > <div class=\"option-content\"> <div class=\"option-label\"> ${this._highlightMatch(e.label||e.value)} ${e.labelTag?V`<span class=\"option-tag\">${e.labelTag}</span>`:B} </div> ${e.description?V`<div class=\"option-description\">${e.description}</div>`:B} ${e.tags&&e.tags.length>0?V` <div class=\"option-tags\"> ${e.tags.map((e=>V`<span class=\"option-tag\">${e}</span>`))} </div> `:B} </div> </button> `}_renderDropdownContent(){if(\"loading\"===this.statusType)return V` <div class=\"status\"> <div class=\"spinner\"></div> ${this.loadingText} </div> `;if(\"error\"===this.statusType)return V` <div class=\"status is-error\"> <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\"> <path d=\"M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z\" /> </svg> ${this.errorText} </div> `;const e=this._filteredOptions;if(0===e.length)return V`<div class=\"empty\">${this.emptyText}</div>`;let t=0;return V` ${e.map((e=>{if(At(e)){const i=e.options.map((e=>{const i=this._renderOption(e,t);return t++,i}));return V` <div class=\"group-label\">${e.label}</div> ${i} `}const i=this._renderOption(e,t);return t++,i}))} `}render(){const e=this._touched&&!this.validity.valid;return V` <div class=\"field-wrapper\"> ${this.label?V` <label> ${this.label} ${this.required?V`<span class=\"required\">*</span>`:B} </label> `:B} <div class=\"input-container\"> <div class=\"input-wrapper\"> <input type=\"text\" .value=${$t(this.value)} placeholder=${kt(this.placeholder||void 0)} ?disabled=${this.disabled} ?readonly=${this.readonly} ?required=${this.required} name=${kt(this.name||void 0)} autocomplete=\"off\" role=\"combobox\" aria-autocomplete=\"list\" aria-expanded=${this._isOpen} aria-controls=\"dropdown\" class=${we({\"input--invalid\":e})} @input=${this._onInput} @blur=${this._onBlur} @focus=${this._onFocus} @keydown=${this._onKeyDown} /> <div class=\"icon-container\"> ${!this.value||this.disabled||this.readonly?\"\":V` <button class=\"clear-button\" type=\"button\" aria-label=\"Clear\" @click=${this._handleClear} > <svg width=\"16\" height=\"16\" fill=\"currentColor\" viewBox=\"0 0 16 16\"> <path d=\"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z\" /> </svg> </button> `} ${this.value||this.disabled||this.readonly?\"\":V` <svg class=\"search-icon\" fill=\"currentColor\" viewBox=\"0 0 16 16\"> <path d=\"M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z\" /> </svg> `} </div> </div> <div id=\"dropdown\" role=\"listbox\" class=${we({dropdown:!0,\"is-open\":this._isOpen})} > ${this._renderDropdownContent()} </div> </div> ${e?V`<div class=\"validation-message\">${this.validationMessage}</div>`:this.hint?V`<div class=\"hint\">${this.hint}</div>`:B} </div> `}}"
|
|
1189
|
+
}
|
|
1190
|
+
],
|
|
1191
|
+
"exports": [
|
|
1192
|
+
{
|
|
1193
|
+
"kind": "custom-element-definition",
|
|
1194
|
+
"name": "e",
|
|
1195
|
+
"declaration": {
|
|
1196
|
+
"name": "t",
|
|
1197
|
+
"module": "dist/krubble-components.bundled.min.js"
|
|
726
1198
|
}
|
|
727
1199
|
},
|
|
728
1200
|
{
|
|
@@ -753,7 +1225,7 @@
|
|
|
753
1225
|
"kind": "js",
|
|
754
1226
|
"name": "KRAutoSuggest",
|
|
755
1227
|
"declaration": {
|
|
756
|
-
"name": "
|
|
1228
|
+
"name": "Dt",
|
|
757
1229
|
"module": "dist/krubble-components.bundled.min.js"
|
|
758
1230
|
}
|
|
759
1231
|
},
|
|
@@ -761,7 +1233,7 @@
|
|
|
761
1233
|
"kind": "js",
|
|
762
1234
|
"name": "KRButton",
|
|
763
1235
|
"declaration": {
|
|
764
|
-
"name": "
|
|
1236
|
+
"name": "Ee",
|
|
765
1237
|
"module": "dist/krubble-components.bundled.min.js"
|
|
766
1238
|
}
|
|
767
1239
|
},
|
|
@@ -769,7 +1241,7 @@
|
|
|
769
1241
|
"kind": "js",
|
|
770
1242
|
"name": "KRCodeDemo",
|
|
771
1243
|
"declaration": {
|
|
772
|
-
"name": "
|
|
1244
|
+
"name": "Pe",
|
|
773
1245
|
"module": "dist/krubble-components.bundled.min.js"
|
|
774
1246
|
}
|
|
775
1247
|
},
|
|
@@ -777,7 +1249,7 @@
|
|
|
777
1249
|
"kind": "js",
|
|
778
1250
|
"name": "KRContextMenu",
|
|
779
1251
|
"declaration": {
|
|
780
|
-
"name": "
|
|
1252
|
+
"name": "De",
|
|
781
1253
|
"module": "dist/krubble-components.bundled.min.js"
|
|
782
1254
|
}
|
|
783
1255
|
},
|
|
@@ -785,7 +1257,7 @@
|
|
|
785
1257
|
"kind": "js",
|
|
786
1258
|
"name": "KRDialog",
|
|
787
1259
|
"declaration": {
|
|
788
|
-
"name": "
|
|
1260
|
+
"name": "Ue",
|
|
789
1261
|
"module": "dist/krubble-components.bundled.min.js"
|
|
790
1262
|
}
|
|
791
1263
|
},
|
|
@@ -793,7 +1265,7 @@
|
|
|
793
1265
|
"kind": "js",
|
|
794
1266
|
"name": "KRDialogRef",
|
|
795
1267
|
"declaration": {
|
|
796
|
-
"name": "
|
|
1268
|
+
"name": "Ve",
|
|
797
1269
|
"module": "dist/krubble-components.bundled.min.js"
|
|
798
1270
|
}
|
|
799
1271
|
},
|
|
@@ -801,7 +1273,7 @@
|
|
|
801
1273
|
"kind": "js",
|
|
802
1274
|
"name": "KRFileList",
|
|
803
1275
|
"declaration": {
|
|
804
|
-
"name": "
|
|
1276
|
+
"name": "xt",
|
|
805
1277
|
"module": "dist/krubble-components.bundled.min.js"
|
|
806
1278
|
}
|
|
807
1279
|
},
|
|
@@ -809,7 +1281,7 @@
|
|
|
809
1281
|
"kind": "js",
|
|
810
1282
|
"name": "KRFilePreview",
|
|
811
1283
|
"declaration": {
|
|
812
|
-
"name": "
|
|
1284
|
+
"name": "_t",
|
|
813
1285
|
"module": "dist/krubble-components.bundled.min.js"
|
|
814
1286
|
}
|
|
815
1287
|
},
|
|
@@ -817,7 +1289,15 @@
|
|
|
817
1289
|
"kind": "js",
|
|
818
1290
|
"name": "KRProgressBar",
|
|
819
1291
|
"declaration": {
|
|
820
|
-
"name": "
|
|
1292
|
+
"name": "vt",
|
|
1293
|
+
"module": "dist/krubble-components.bundled.min.js"
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
"kind": "js",
|
|
1298
|
+
"name": "KRQuery",
|
|
1299
|
+
"declaration": {
|
|
1300
|
+
"name": "dt",
|
|
821
1301
|
"module": "dist/krubble-components.bundled.min.js"
|
|
822
1302
|
}
|
|
823
1303
|
},
|
|
@@ -825,7 +1305,7 @@
|
|
|
825
1305
|
"kind": "js",
|
|
826
1306
|
"name": "KRSelectField",
|
|
827
1307
|
"declaration": {
|
|
828
|
-
"name": "
|
|
1308
|
+
"name": "Qe",
|
|
829
1309
|
"module": "dist/krubble-components.bundled.min.js"
|
|
830
1310
|
}
|
|
831
1311
|
},
|
|
@@ -833,7 +1313,7 @@
|
|
|
833
1313
|
"kind": "js",
|
|
834
1314
|
"name": "KRSelectOption",
|
|
835
1315
|
"declaration": {
|
|
836
|
-
"name": "
|
|
1316
|
+
"name": "Je",
|
|
837
1317
|
"module": "dist/krubble-components.bundled.min.js"
|
|
838
1318
|
}
|
|
839
1319
|
},
|
|
@@ -849,7 +1329,7 @@
|
|
|
849
1329
|
"kind": "js",
|
|
850
1330
|
"name": "KRSpinner",
|
|
851
1331
|
"declaration": {
|
|
852
|
-
"name": "
|
|
1332
|
+
"name": "ft",
|
|
853
1333
|
"module": "dist/krubble-components.bundled.min.js"
|
|
854
1334
|
}
|
|
855
1335
|
},
|
|
@@ -865,7 +1345,7 @@
|
|
|
865
1345
|
"kind": "js",
|
|
866
1346
|
"name": "KRTabGroup",
|
|
867
1347
|
"declaration": {
|
|
868
|
-
"name": "
|
|
1348
|
+
"name": "We",
|
|
869
1349
|
"module": "dist/krubble-components.bundled.min.js"
|
|
870
1350
|
}
|
|
871
1351
|
},
|
|
@@ -873,7 +1353,7 @@
|
|
|
873
1353
|
"kind": "js",
|
|
874
1354
|
"name": "KRTable",
|
|
875
1355
|
"declaration": {
|
|
876
|
-
"name": "
|
|
1356
|
+
"name": "pt",
|
|
877
1357
|
"module": "dist/krubble-components.bundled.min.js"
|
|
878
1358
|
}
|
|
879
1359
|
},
|
|
@@ -881,7 +1361,7 @@
|
|
|
881
1361
|
"kind": "js",
|
|
882
1362
|
"name": "KRTextField",
|
|
883
1363
|
"declaration": {
|
|
884
|
-
"name": "
|
|
1364
|
+
"name": "St",
|
|
885
1365
|
"module": "dist/krubble-components.bundled.min.js"
|
|
886
1366
|
}
|
|
887
1367
|
},
|
|
@@ -889,7 +1369,23 @@
|
|
|
889
1369
|
"kind": "js",
|
|
890
1370
|
"name": "KRTextareaField",
|
|
891
1371
|
"declaration": {
|
|
892
|
-
"name": "
|
|
1372
|
+
"name": "zt",
|
|
1373
|
+
"module": "dist/krubble-components.bundled.min.js"
|
|
1374
|
+
}
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
"kind": "js",
|
|
1378
|
+
"name": "KR_OPERATORS",
|
|
1379
|
+
"declaration": {
|
|
1380
|
+
"name": "et",
|
|
1381
|
+
"module": "dist/krubble-components.bundled.min.js"
|
|
1382
|
+
}
|
|
1383
|
+
},
|
|
1384
|
+
{
|
|
1385
|
+
"kind": "js",
|
|
1386
|
+
"name": "getOperatorsForType",
|
|
1387
|
+
"declaration": {
|
|
1388
|
+
"name": "tt",
|
|
893
1389
|
"module": "dist/krubble-components.bundled.min.js"
|
|
894
1390
|
}
|
|
895
1391
|
},
|
|
@@ -897,7 +1393,7 @@
|
|
|
897
1393
|
"kind": "js",
|
|
898
1394
|
"name": "krBaseCSS",
|
|
899
1395
|
"declaration": {
|
|
900
|
-
"name": "
|
|
1396
|
+
"name": "ne",
|
|
901
1397
|
"module": "dist/krubble-components.bundled.min.js"
|
|
902
1398
|
}
|
|
903
1399
|
}
|
|
@@ -1097,6 +1593,14 @@
|
|
|
1097
1593
|
"module": "./table/table.js"
|
|
1098
1594
|
}
|
|
1099
1595
|
},
|
|
1596
|
+
{
|
|
1597
|
+
"kind": "js",
|
|
1598
|
+
"name": "KRTableColumnDef",
|
|
1599
|
+
"declaration": {
|
|
1600
|
+
"name": "KRTableColumnDef",
|
|
1601
|
+
"module": "./table/table.js"
|
|
1602
|
+
}
|
|
1603
|
+
},
|
|
1100
1604
|
{
|
|
1101
1605
|
"kind": "js",
|
|
1102
1606
|
"name": "KRTableColumn",
|
|
@@ -1123,74 +1627,130 @@
|
|
|
1123
1627
|
},
|
|
1124
1628
|
{
|
|
1125
1629
|
"kind": "js",
|
|
1126
|
-
"name": "
|
|
1630
|
+
"name": "KRQuery",
|
|
1127
1631
|
"declaration": {
|
|
1128
|
-
"name": "
|
|
1129
|
-
"module": "./
|
|
1632
|
+
"name": "KRQuery",
|
|
1633
|
+
"module": "./table/query.js"
|
|
1130
1634
|
}
|
|
1131
1635
|
},
|
|
1132
1636
|
{
|
|
1133
1637
|
"kind": "js",
|
|
1134
|
-
"name": "
|
|
1638
|
+
"name": "KR_OPERATORS",
|
|
1135
1639
|
"declaration": {
|
|
1136
|
-
"name": "
|
|
1137
|
-
"module": "./
|
|
1640
|
+
"name": "KR_OPERATORS",
|
|
1641
|
+
"module": "./table/query.js"
|
|
1138
1642
|
}
|
|
1139
1643
|
},
|
|
1140
1644
|
{
|
|
1141
1645
|
"kind": "js",
|
|
1142
|
-
"name": "
|
|
1646
|
+
"name": "getOperatorsForType",
|
|
1143
1647
|
"declaration": {
|
|
1144
|
-
"name": "
|
|
1145
|
-
"module": "./
|
|
1648
|
+
"name": "getOperatorsForType",
|
|
1649
|
+
"module": "./table/query.js"
|
|
1146
1650
|
}
|
|
1147
1651
|
},
|
|
1148
1652
|
{
|
|
1149
1653
|
"kind": "js",
|
|
1150
|
-
"name": "
|
|
1654
|
+
"name": "KROperator",
|
|
1151
1655
|
"declaration": {
|
|
1152
|
-
"name": "
|
|
1153
|
-
"module": "./
|
|
1656
|
+
"name": "KROperator",
|
|
1657
|
+
"module": "./table/query.js"
|
|
1154
1658
|
}
|
|
1155
1659
|
},
|
|
1156
1660
|
{
|
|
1157
1661
|
"kind": "js",
|
|
1158
|
-
"name": "
|
|
1662
|
+
"name": "KROperatorType",
|
|
1159
1663
|
"declaration": {
|
|
1160
|
-
"name": "
|
|
1161
|
-
"module": "./
|
|
1664
|
+
"name": "KROperatorType",
|
|
1665
|
+
"module": "./table/query.js"
|
|
1162
1666
|
}
|
|
1163
1667
|
},
|
|
1164
1668
|
{
|
|
1165
1669
|
"kind": "js",
|
|
1166
|
-
"name": "
|
|
1670
|
+
"name": "KRDateSpecificity",
|
|
1167
1671
|
"declaration": {
|
|
1168
|
-
"name": "
|
|
1169
|
-
"module": "./
|
|
1672
|
+
"name": "KRDateSpecificity",
|
|
1673
|
+
"module": "./table/query.js"
|
|
1170
1674
|
}
|
|
1171
1675
|
},
|
|
1172
1676
|
{
|
|
1173
1677
|
"kind": "js",
|
|
1174
|
-
"name": "
|
|
1678
|
+
"name": "KRQueryRange",
|
|
1175
1679
|
"declaration": {
|
|
1176
|
-
"name": "
|
|
1177
|
-
"module": "./
|
|
1680
|
+
"name": "KRQueryRange",
|
|
1681
|
+
"module": "./table/query.js"
|
|
1178
1682
|
}
|
|
1179
1683
|
},
|
|
1180
1684
|
{
|
|
1181
1685
|
"kind": "js",
|
|
1182
|
-
"name": "
|
|
1686
|
+
"name": "KRSpinner",
|
|
1183
1687
|
"declaration": {
|
|
1184
|
-
"name": "
|
|
1185
|
-
"module": "./
|
|
1688
|
+
"name": "KRSpinner",
|
|
1689
|
+
"module": "./spinner/spinner.js"
|
|
1186
1690
|
}
|
|
1187
1691
|
},
|
|
1188
1692
|
{
|
|
1189
1693
|
"kind": "js",
|
|
1190
|
-
"name": "
|
|
1694
|
+
"name": "KRProgressBar",
|
|
1191
1695
|
"declaration": {
|
|
1192
|
-
"name": "
|
|
1193
|
-
"module": "./
|
|
1696
|
+
"name": "KRProgressBar",
|
|
1697
|
+
"module": "./progress-bar/progress-bar.js"
|
|
1698
|
+
}
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
"kind": "js",
|
|
1702
|
+
"name": "KRFileList",
|
|
1703
|
+
"declaration": {
|
|
1704
|
+
"name": "KRFileList",
|
|
1705
|
+
"module": "./file-list/file-list.js"
|
|
1706
|
+
}
|
|
1707
|
+
},
|
|
1708
|
+
{
|
|
1709
|
+
"kind": "js",
|
|
1710
|
+
"name": "KRFile",
|
|
1711
|
+
"declaration": {
|
|
1712
|
+
"name": "KRFile",
|
|
1713
|
+
"module": "./file-list/file-list.js"
|
|
1714
|
+
}
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
"kind": "js",
|
|
1718
|
+
"name": "KRFilePreview",
|
|
1719
|
+
"declaration": {
|
|
1720
|
+
"name": "KRFilePreview",
|
|
1721
|
+
"module": "./file-preview/file-preview.js"
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
{
|
|
1725
|
+
"kind": "js",
|
|
1726
|
+
"name": "KRFilePreviewOptions",
|
|
1727
|
+
"declaration": {
|
|
1728
|
+
"name": "KRFilePreviewOptions",
|
|
1729
|
+
"module": "./file-preview/file-preview.js"
|
|
1730
|
+
}
|
|
1731
|
+
},
|
|
1732
|
+
{
|
|
1733
|
+
"kind": "js",
|
|
1734
|
+
"name": "KRTextField",
|
|
1735
|
+
"declaration": {
|
|
1736
|
+
"name": "KRTextField",
|
|
1737
|
+
"module": "./form/index.js"
|
|
1738
|
+
}
|
|
1739
|
+
},
|
|
1740
|
+
{
|
|
1741
|
+
"kind": "js",
|
|
1742
|
+
"name": "KRTextareaField",
|
|
1743
|
+
"declaration": {
|
|
1744
|
+
"name": "KRTextareaField",
|
|
1745
|
+
"module": "./form/index.js"
|
|
1746
|
+
}
|
|
1747
|
+
},
|
|
1748
|
+
{
|
|
1749
|
+
"kind": "js",
|
|
1750
|
+
"name": "KRSelectField",
|
|
1751
|
+
"declaration": {
|
|
1752
|
+
"name": "KRSelectField",
|
|
1753
|
+
"module": "./form/index.js"
|
|
1194
1754
|
}
|
|
1195
1755
|
},
|
|
1196
1756
|
{
|
|
@@ -1726,6 +2286,277 @@
|
|
|
1726
2286
|
}
|
|
1727
2287
|
]
|
|
1728
2288
|
},
|
|
2289
|
+
{
|
|
2290
|
+
"kind": "javascript-module",
|
|
2291
|
+
"path": "dist/table/query.js",
|
|
2292
|
+
"declarations": [
|
|
2293
|
+
{
|
|
2294
|
+
"kind": "variable",
|
|
2295
|
+
"name": "KR_OPERATORS",
|
|
2296
|
+
"type": {
|
|
2297
|
+
"text": "object"
|
|
2298
|
+
},
|
|
2299
|
+
"default": "{ equals: { key: 'equals', type: 'comparison', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Equals' }, n_equals: { key: 'n_equals', type: 'comparison', dataTypes: ['string', 'number', 'date', 'boolean'], label: \"Doesn't equal\" }, contains: { key: 'contains', type: 'comparison', dataTypes: ['string'], label: 'Contains' }, n_contains: { key: 'n_contains', type: 'comparison', dataTypes: ['string'], label: \"Doesn't contain\" }, starts_with: { key: 'starts_with', type: 'comparison', dataTypes: ['string'], label: 'Starts with' }, ends_with: { key: 'ends_with', type: 'comparison', dataTypes: ['string'], label: 'Ends with' }, less_than: { key: 'less_than', type: 'comparison', dataTypes: ['number', 'date'], label: 'Less than' }, less_than_equal: { key: 'less_than_equal', type: 'comparison', dataTypes: ['number', 'date'], label: 'Less than or equal' }, greater_than: { key: 'greater_than', type: 'comparison', dataTypes: ['number', 'date'], label: 'Greater than' }, greater_than_equal: { key: 'greater_than_equal', type: 'comparison', dataTypes: ['number', 'date'], label: 'Greater than or equal' }, between: { key: 'between', type: 'range', dataTypes: ['number', 'date'], label: 'Between' }, in: { key: 'in', type: 'list', dataTypes: ['string', 'number'], label: 'In' }, empty: { key: 'empty', type: 'nil', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Empty' }, n_empty: { key: 'n_empty', type: 'nil', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Not empty' }, }",
|
|
2300
|
+
"description": "Data-driven operator metadata map"
|
|
2301
|
+
},
|
|
2302
|
+
{
|
|
2303
|
+
"kind": "function",
|
|
2304
|
+
"name": "getOperatorsForType",
|
|
2305
|
+
"parameters": [
|
|
2306
|
+
{
|
|
2307
|
+
"name": "columnType"
|
|
2308
|
+
}
|
|
2309
|
+
],
|
|
2310
|
+
"description": "Returns the list of operators available for a given column type"
|
|
2311
|
+
},
|
|
2312
|
+
{
|
|
2313
|
+
"kind": "function",
|
|
2314
|
+
"name": "termify",
|
|
2315
|
+
"parameters": [
|
|
2316
|
+
{
|
|
2317
|
+
"name": "value"
|
|
2318
|
+
},
|
|
2319
|
+
{
|
|
2320
|
+
"name": "exact",
|
|
2321
|
+
"default": "true"
|
|
2322
|
+
}
|
|
2323
|
+
],
|
|
2324
|
+
"description": "Converts a value to a Solr term"
|
|
2325
|
+
},
|
|
2326
|
+
{
|
|
2327
|
+
"kind": "class",
|
|
2328
|
+
"description": "",
|
|
2329
|
+
"name": "KRQuery",
|
|
2330
|
+
"members": [
|
|
2331
|
+
{
|
|
2332
|
+
"kind": "method",
|
|
2333
|
+
"name": "setKql",
|
|
2334
|
+
"parameters": [
|
|
2335
|
+
{
|
|
2336
|
+
"name": "kql"
|
|
2337
|
+
}
|
|
2338
|
+
],
|
|
2339
|
+
"description": "Parse a KQL text string and populate operator/value/values"
|
|
2340
|
+
},
|
|
2341
|
+
{
|
|
2342
|
+
"kind": "method",
|
|
2343
|
+
"name": "setOperator",
|
|
2344
|
+
"parameters": [
|
|
2345
|
+
{
|
|
2346
|
+
"name": "operator"
|
|
2347
|
+
}
|
|
2348
|
+
]
|
|
2349
|
+
},
|
|
2350
|
+
{
|
|
2351
|
+
"kind": "method",
|
|
2352
|
+
"name": "setValue",
|
|
2353
|
+
"parameters": [
|
|
2354
|
+
{
|
|
2355
|
+
"name": "value"
|
|
2356
|
+
},
|
|
2357
|
+
{
|
|
2358
|
+
"name": "specificity"
|
|
2359
|
+
}
|
|
2360
|
+
]
|
|
2361
|
+
},
|
|
2362
|
+
{
|
|
2363
|
+
"kind": "method",
|
|
2364
|
+
"name": "setStart",
|
|
2365
|
+
"parameters": [
|
|
2366
|
+
{
|
|
2367
|
+
"name": "value"
|
|
2368
|
+
},
|
|
2369
|
+
{
|
|
2370
|
+
"name": "specificity"
|
|
2371
|
+
}
|
|
2372
|
+
]
|
|
2373
|
+
},
|
|
2374
|
+
{
|
|
2375
|
+
"kind": "method",
|
|
2376
|
+
"name": "setEnd",
|
|
2377
|
+
"parameters": [
|
|
2378
|
+
{
|
|
2379
|
+
"name": "value"
|
|
2380
|
+
},
|
|
2381
|
+
{
|
|
2382
|
+
"name": "specificity"
|
|
2383
|
+
}
|
|
2384
|
+
]
|
|
2385
|
+
},
|
|
2386
|
+
{
|
|
2387
|
+
"kind": "method",
|
|
2388
|
+
"name": "clear"
|
|
2389
|
+
},
|
|
2390
|
+
{
|
|
2391
|
+
"kind": "method",
|
|
2392
|
+
"name": "isEmpty"
|
|
2393
|
+
},
|
|
2394
|
+
{
|
|
2395
|
+
"kind": "method",
|
|
2396
|
+
"name": "has",
|
|
2397
|
+
"parameters": [
|
|
2398
|
+
{
|
|
2399
|
+
"name": "val"
|
|
2400
|
+
}
|
|
2401
|
+
],
|
|
2402
|
+
"description": "Returns true if the value array contains the given value. Only applies to 'in' operator."
|
|
2403
|
+
},
|
|
2404
|
+
{
|
|
2405
|
+
"kind": "method",
|
|
2406
|
+
"name": "toggle",
|
|
2407
|
+
"parameters": [
|
|
2408
|
+
{
|
|
2409
|
+
"name": "val"
|
|
2410
|
+
}
|
|
2411
|
+
],
|
|
2412
|
+
"description": "Adds or removes a value from the 'in' list and rebuilds text/kql."
|
|
2413
|
+
},
|
|
2414
|
+
{
|
|
2415
|
+
"kind": "method",
|
|
2416
|
+
"name": "isValid"
|
|
2417
|
+
},
|
|
2418
|
+
{
|
|
2419
|
+
"kind": "method",
|
|
2420
|
+
"name": "toSolrData",
|
|
2421
|
+
"description": "Converts this filter to a Solr filter field object, or null if invalid"
|
|
2422
|
+
},
|
|
2423
|
+
{
|
|
2424
|
+
"kind": "method",
|
|
2425
|
+
"name": "toDbParams",
|
|
2426
|
+
"description": "Converts this filter to a DB filter field object, or null if invalid"
|
|
2427
|
+
},
|
|
2428
|
+
{
|
|
2429
|
+
"kind": "method",
|
|
2430
|
+
"name": "_buildText"
|
|
2431
|
+
},
|
|
2432
|
+
{
|
|
2433
|
+
"kind": "method",
|
|
2434
|
+
"name": "_format",
|
|
2435
|
+
"parameters": [
|
|
2436
|
+
{
|
|
2437
|
+
"name": "value"
|
|
2438
|
+
}
|
|
2439
|
+
]
|
|
2440
|
+
},
|
|
2441
|
+
{
|
|
2442
|
+
"kind": "method",
|
|
2443
|
+
"name": "_parse",
|
|
2444
|
+
"parameters": [
|
|
2445
|
+
{
|
|
2446
|
+
"name": "text"
|
|
2447
|
+
}
|
|
2448
|
+
],
|
|
2449
|
+
"description": "Parse a text value according to this query's type"
|
|
2450
|
+
},
|
|
2451
|
+
{
|
|
2452
|
+
"kind": "method",
|
|
2453
|
+
"name": "_parseDate",
|
|
2454
|
+
"parameters": [
|
|
2455
|
+
{
|
|
2456
|
+
"name": "input"
|
|
2457
|
+
}
|
|
2458
|
+
],
|
|
2459
|
+
"description": "Parse a date string into a UTC Date"
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
"kind": "method",
|
|
2463
|
+
"name": "_buildKql",
|
|
2464
|
+
"description": "Build a KQL display string from current operator/value state"
|
|
2465
|
+
},
|
|
2466
|
+
{
|
|
2467
|
+
"kind": "field",
|
|
2468
|
+
"name": "field",
|
|
2469
|
+
"type": {
|
|
2470
|
+
"text": "string"
|
|
2471
|
+
},
|
|
2472
|
+
"default": "''"
|
|
2473
|
+
},
|
|
2474
|
+
{
|
|
2475
|
+
"kind": "field",
|
|
2476
|
+
"name": "operator",
|
|
2477
|
+
"type": {
|
|
2478
|
+
"text": "string"
|
|
2479
|
+
},
|
|
2480
|
+
"default": "'equals'"
|
|
2481
|
+
},
|
|
2482
|
+
{
|
|
2483
|
+
"kind": "field",
|
|
2484
|
+
"name": "value",
|
|
2485
|
+
"type": {
|
|
2486
|
+
"text": "null"
|
|
2487
|
+
},
|
|
2488
|
+
"default": "null"
|
|
2489
|
+
},
|
|
2490
|
+
{
|
|
2491
|
+
"kind": "field",
|
|
2492
|
+
"name": "kql",
|
|
2493
|
+
"type": {
|
|
2494
|
+
"text": "string"
|
|
2495
|
+
},
|
|
2496
|
+
"default": "''"
|
|
2497
|
+
},
|
|
2498
|
+
{
|
|
2499
|
+
"kind": "field",
|
|
2500
|
+
"name": "text",
|
|
2501
|
+
"type": {
|
|
2502
|
+
"text": "string"
|
|
2503
|
+
},
|
|
2504
|
+
"default": "''"
|
|
2505
|
+
},
|
|
2506
|
+
{
|
|
2507
|
+
"kind": "field",
|
|
2508
|
+
"name": "type",
|
|
2509
|
+
"type": {
|
|
2510
|
+
"text": "string"
|
|
2511
|
+
},
|
|
2512
|
+
"default": "''"
|
|
2513
|
+
},
|
|
2514
|
+
{
|
|
2515
|
+
"kind": "field",
|
|
2516
|
+
"name": "specificity",
|
|
2517
|
+
"type": {
|
|
2518
|
+
"text": "array"
|
|
2519
|
+
},
|
|
2520
|
+
"default": "[]"
|
|
2521
|
+
}
|
|
2522
|
+
]
|
|
2523
|
+
}
|
|
2524
|
+
],
|
|
2525
|
+
"exports": [
|
|
2526
|
+
{
|
|
2527
|
+
"kind": "js",
|
|
2528
|
+
"name": "KR_OPERATORS",
|
|
2529
|
+
"declaration": {
|
|
2530
|
+
"name": "KR_OPERATORS",
|
|
2531
|
+
"module": "dist/table/query.js"
|
|
2532
|
+
}
|
|
2533
|
+
},
|
|
2534
|
+
{
|
|
2535
|
+
"kind": "js",
|
|
2536
|
+
"name": "getOperatorsForType",
|
|
2537
|
+
"declaration": {
|
|
2538
|
+
"name": "getOperatorsForType",
|
|
2539
|
+
"module": "dist/table/query.js"
|
|
2540
|
+
}
|
|
2541
|
+
},
|
|
2542
|
+
{
|
|
2543
|
+
"kind": "js",
|
|
2544
|
+
"name": "termify",
|
|
2545
|
+
"declaration": {
|
|
2546
|
+
"name": "termify",
|
|
2547
|
+
"module": "dist/table/query.js"
|
|
2548
|
+
}
|
|
2549
|
+
},
|
|
2550
|
+
{
|
|
2551
|
+
"kind": "js",
|
|
2552
|
+
"name": "KRQuery",
|
|
2553
|
+
"declaration": {
|
|
2554
|
+
"name": "KRQuery",
|
|
2555
|
+
"module": "dist/table/query.js"
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
]
|
|
2559
|
+
},
|
|
1729
2560
|
{
|
|
1730
2561
|
"kind": "javascript-module",
|
|
1731
2562
|
"path": "dist/table/table.js",
|
|
@@ -1733,7 +2564,7 @@
|
|
|
1733
2564
|
{
|
|
1734
2565
|
"kind": "variable",
|
|
1735
2566
|
"name": "KRTable",
|
|
1736
|
-
"default": "class KRTable extends LitElement { constructor() { super(...arguments); /** * Internal flag to switch between scroll edge modes: * - 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge) * - 'edge': Padding scrolls with content, allowing table to reach edges when scrolling */ this._scrollStyle = 'overlay'; this._data = []; this._dataState = 'idle'; this._page = 1; this._pageSize = 50; this._totalItems = 0; this._totalPages = 0; this._searchQuery = ''; this._canScrollLeft = false; this._canScrollRight = false; this._canScrollHorizontal = false; this._columnPickerOpen = false; this._displayedColumns = []; this._resizing = null; this._resizeObserver = null; this._searchPositionLocked = false; this._def = { columns: [] }; this.def = { columns: [] }; this._handleClickOutsideColumnPicker = (e) => { if (!this._columnPickerOpen) return; const path = e.composedPath(); const picker = this.shadowRoot?.querySelector('.column-picker-wrapper'); if (picker && !path.includes(picker)) { this._columnPickerOpen = false; } }; this._handleResizeMove = (e) => { if (!this._resizing) return; const col = this._def.columns.find(c => c.id === this._resizing.columnId); if (col) { const newWidth = this._resizing.startWidth + (e.clientX - this._resizing.startX); col.width = `${Math.min(900, Math.max(50, newWidth))}px`; this.requestUpdate(); } }; this._handleResizeEnd = () => { this._resizing = null; document.removeEventListener('mousemove', this._handleResizeMove); document.removeEventListener('mouseup', this._handleResizeEnd); }; } connectedCallback() { super.connectedCallback(); this.classList.toggle('kr-table--scroll-overlay', this._scrollStyle === 'overlay'); this.classList.toggle('kr-table--scroll-edge', this._scrollStyle === 'edge'); this._fetch(); this._initRefresh(); document.addEventListener('click', this._handleClickOutsideColumnPicker); this._resizeObserver = new ResizeObserver(() => { // Unlock and recalculate on resize since layout changes this._searchPositionLocked = false; this._updateSearchPosition(); }); this._resizeObserver.observe(this); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._refreshTimer); document.removeEventListener('click', this._handleClickOutsideColumnPicker); this._resizeObserver?.disconnect(); } willUpdate(changedProperties) { if (changedProperties.has('def')) { // Copy user's def and normalize action columns this._def = { ...this.def, columns: this.def.columns.map(col => { if (col.type === 'actions') { return { ...col, label: col.label ?? '', sticky: 'right', resizable: false }; } return { ...col }; }) }; this._displayedColumns = this._def.displayedColumns || this._def.columns.map(c => c.id); this._fetch(); this._initRefresh(); } } updated(changedProperties) { this._updateScrollFlags(); this._syncSlottedContent(); } /** Syncs light DOM content for cells with custom render functions */ _syncSlottedContent() { const columns = this.getDisplayedColumns().filter(col => col.render); if (!columns.length) return; // Clear old slotted content this.querySelectorAll('[slot^=\"cell-\"]').forEach(el => el.remove()); // Create new slotted content this._data.forEach((row, rowIndex) => { columns.forEach(col => { const result = col.render(row); if (!result) return; const el = document.createElement('span'); el.slot = `cell-${rowIndex}-${col.id}`; if (col.type === 'actions') { el.style.display = 'flex'; el.style.gap = '8px'; } if (typeof result === 'string') { el.innerHTML = result; } else { render(result, el); } this.appendChild(el); }); }); } // ---------------------------------------------------------------------------- // Public Interface // ---------------------------------------------------------------------------- refresh() { this._fetch(); } goToPrevPage() { if (this._page > 1) { this._page--; this._fetch(); } } goToNextPage() { if (this._page < this._totalPages) { this._page++; this._fetch(); } } goToPage(page) { if (page >= 1 && page <= this._totalPages) { this._page = page; this._fetch(); } } // ---------------------------------------------------------------------------- // Data Fetching // ---------------------------------------------------------------------------- /** * Fetches data from the API and updates the table. * Shows a loading spinner while fetching, then displays rows on success * or an error snackbar on failure. * Request/response format depends on dataSource.mode (solr, opensearch, db). */ _fetch() { if (!this._def.dataSource) return; this._dataState = 'loading'; // Build request based on mode let request; switch (this._def.dataSource.mode) { case 'opensearch': throw Error('Opensearch not supported yet'); case 'db': request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; if (this._searchQuery?.trim().length) { this._def.columns.filter(col => col.searchable).forEach(col => { request.queryFields.push({ name: col.id, operation: 'CONTAINS', value: this._searchQuery, and: false }); }); } break; default: // solr request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; if (this._searchQuery?.trim().length) { request.queryFields.push({ name: '_text_', operation: 'IS', value: escapeSolrQuery(this._searchQuery) }); } } this._def.dataSource.fetch(request) .then(response => { // Parse response based on mode switch (this._def.dataSource?.mode) { case 'opensearch': { throw Error('Opensearch not supported yet'); break; } case 'db': { const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; break; } default: { // solr const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; } } this._dataState = 'success'; this._updateSearchPosition(); }) .catch(err => { this._dataState = 'error'; KRSnackbar.show({ message: err instanceof Error ? err.message : 'Failed to load data', type: 'error' }); }); } /** * Sets up auto-refresh so the table automatically fetches fresh data * at a regular interval (useful for dashboards, monitoring views). * Configured via def.refreshInterval in milliseconds. */ _initRefresh() { clearInterval(this._refreshTimer); if (this._def.refreshInterval && this._def.refreshInterval > 0) { this._refreshTimer = window.setInterval(() => { this._fetch(); }, this._def.refreshInterval); } } _handleSearch(e) { const input = e.target; this._searchQuery = input.value; this._page = 1; this._fetch(); } _getGridTemplateColumns() { const cols = this.getDisplayedColumns(); return cols.map((col) => { // If column has explicit width, use it if (col.width) { return col.width; } // Actions columns: fit content without minimum if (col.type === 'actions') { return 'max-content'; } // No width specified - use content-based sizing with minimum return 'minmax(80px, auto)'; }).join(' '); } /** * Updates search position to be centered with equal gaps from title and tools. * On first call: resets to flex centering, measures position, then locks with fixed margin. * Subsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize). */ _updateSearchPosition() { // Skip if already locked (prevents shifts on pagination changes) if (this._searchPositionLocked) return; const search = this.shadowRoot?.querySelector('.search'); const searchField = search?.querySelector('.search-field'); if (!search || !searchField) return; // Reset to flex centering search.style.justifyContent = 'center'; searchField.style.marginLeft = ''; requestAnimationFrame(() => { const searchRect = search.getBoundingClientRect(); const fieldRect = searchField.getBoundingClientRect(); // Calculate how far from the left of search container the field currently is const currentOffset = fieldRect.left - searchRect.left; // Lock position: switch to flex-start and use fixed margin search.style.justifyContent = 'flex-start'; searchField.style.marginLeft = `${currentOffset}px`; // Mark as locked so pagination changes don't shift the search this._searchPositionLocked = true; }); } // ---------------------------------------------------------------------------- // Columns // ---------------------------------------------------------------------------- _toggleColumnPicker() { this._columnPickerOpen = !this._columnPickerOpen; } _toggleColumn(columnId) { if (this._displayedColumns.includes(columnId)) { this._displayedColumns = this._displayedColumns.filter(id => id !== columnId); } else { this._displayedColumns = [...this._displayedColumns, columnId]; } } // Clear any existing text selection on mousedown so we only detect // selections made during this click gesture, not stale selections from elsewhere _handleRowMouseDown() { if (!this._def.rowClickable) { return; } window.getSelection()?.removeAllRanges(); } _handleRowClick(row, rowIndex) { if (!this._def.rowClickable) { return; } const selection = window.getSelection(); if (selection && selection.toString().length > 0) { return; } this.dispatchEvent(new CustomEvent('row-click', { detail: { row, rowIndex }, bubbles: true, composed: true })); } // When a user toggles a column on via the column picker, it gets appended // to _displayedColumns. By mapping over _displayedColumns (not def.columns), // the new column appears at the right edge of the table instead of jumping // back to its original position in the column definition. // Actions columns are always moved to the end. getDisplayedColumns() { return this._displayedColumns .map(id => this._def.columns.find(col => col.id === id)) .sort((a, b) => { if (a.type === 'actions' && b.type !== 'actions') return 1; if (a.type !== 'actions' && b.type === 'actions') return -1; return 0; }); } // ---------------------------------------------------------------------------- // Scrolling // ---------------------------------------------------------------------------- /** * Scroll event handler that updates scroll flags in real-time as user scrolls. * Updates shadow indicators to show if more content exists left/right. */ _handleScroll(e) { const container = e.target; this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollLeft < container.scrollWidth - container.clientWidth - 1; } /** * Updates scroll state flags for the table content container. * - _canScrollLeft: true if scrolled right (can scroll back left) * - _canScrollRight: true if more content exists to the right * - _canScrollHorizontal: true if content is wider than container * These flags control scroll shadow indicators and CSS classes. */ _updateScrollFlags() { const container = this.shadowRoot?.querySelector('.content'); if (container) { this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollWidth > container.clientWidth && container.scrollLeft < container.scrollWidth - container.clientWidth - 1; this._canScrollHorizontal = container.scrollWidth > container.clientWidth; } this.classList.toggle('kr-table--scroll-left-available', this._canScrollLeft); this.classList.toggle('kr-table--scroll-right-available', this._canScrollRight); this.classList.toggle('kr-table--scroll-horizontal-available', this._canScrollHorizontal); this.classList.toggle('kr-table--sticky-left', this.getDisplayedColumns().some(c => c.sticky === 'left')); this.classList.toggle('kr-table--sticky-right', this.getDisplayedColumns().some(c => c.sticky === 'right')); } // ---------------------------------------------------------------------------- // Column Resizing // ---------------------------------------------------------------------------- _handleResizeStart(e, columnId) { e.preventDefault(); const headerCell = this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${columnId}\"]`); this._resizing = { columnId, startX: e.clientX, startWidth: headerCell?.offsetWidth || 200 }; document.addEventListener('mousemove', this._handleResizeMove); document.addEventListener('mouseup', this._handleResizeEnd); } // ---------------------------------------------------------------------------- // Header // ---------------------------------------------------------------------------- _handleAction(action) { if (action.href) { return; } this.dispatchEvent(new CustomEvent('action', { detail: { action: action.id }, bubbles: true, composed: true })); } // ---------------------------------------------------------------------------- // Rendering // ---------------------------------------------------------------------------- _renderCellContent(column, row, rowIndex) { const value = row[column.id]; if (column.render) { // Use slot to project content from light DOM so external styles apply return html `<slot name=\"cell-${rowIndex}-${column.id}\"></slot>`; } if (value === null || value === undefined) { return ''; } switch (column.type) { case 'number': return typeof value === 'number' ? value.toLocaleString() : String(value); case 'currency': return typeof value === 'number' ? value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }) : String(value); case 'date': { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(value)) { // MySQL datetime format (UTC): \"2026-01-28 01:33:44:517\" // Replace last colon before ms with dot, append Z for UTC const isoString = value.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/, '$1.$2').replace(' ', 'T') + 'Z'; date = new Date(isoString); } else { date = new Date(value); } // Show date and time for datetime values return date.toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }); } case 'boolean': if (value === true) return 'Yes'; if (value === false) return 'No'; return ''; default: return String(value); } } /** * Returns CSS classes for a header cell based on column config. */ _getHeaderCellClasses(column, index) { return { 'header-cell': true, 'header-cell--align-center': column.align === 'center', 'header-cell--align-right': column.align === 'right', 'header-cell--sticky-left': column.sticky === 'left', 'header-cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'header-cell--sticky-right': column.sticky === 'right', 'header-cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns CSS classes for a table cell based on column config: * - Alignment (center, right) * - Sticky positioning (left, right) * - Border classes for the last left-sticky or first right-sticky column */ _getCellClasses(column, index) { return { 'cell': true, 'cell--actions': column.type === 'actions', 'cell--align-center': column.align === 'center', 'cell--align-right': column.align === 'right', 'cell--sticky-left': column.sticky === 'left', 'cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'cell--sticky-right': column.sticky === 'right', 'cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns inline styles for a table cell: * - Width (from column config or default 150px) * - Min-width (if specified) * - Left/right offset for sticky columns (calculated from widths of preceding sticky columns) */ _getCellStyle(column, index) { const styles = {}; if (column.sticky === 'left') { let leftOffset = 0; for (let i = 0; i < index; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'left') { leftOffset += parseInt(col.width || '0', 10); } } styles.left = `${leftOffset}px`; } if (column.sticky === 'right') { let rightOffset = 0; for (let i = index + 1; i < this.getDisplayedColumns().length; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'right') { rightOffset += parseInt(col.width || '0', 10); } } styles.right = `${rightOffset}px`; } return styles; } /** * Renders the pagination controls: * - Previous page arrow (disabled on first page) * - Range text showing \"1-50 of 150\" format * - Next page arrow (disabled on last page) * * Hidden when there's no data or all data fits on one page. */ _renderPagination() { const start = (this._page - 1) * this._pageSize + 1; const end = Math.min(this._page * this._pageSize, this._totalItems); return html ` <div class=\"pagination\"> <span class=\"pagination-icon ${this._page === 1 ? 'pagination-icon--disabled' : ''}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${start}-${end} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page === this._totalPages ? 'pagination-icon--disabled' : ''}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `; } /** * Renders the header toolbar containing: * - Title (left) * - Search bar with view selector dropdown (center) * - Tools (right): page navigation, refresh button, column visibility picker, actions dropdown * * Hidden when there's no title, no actions, and data fits on one page. */ _renderHeader() { if (!this._def.title && !this._def.actions?.length && this._totalPages <= 1) { return nothing; } return html ` <div class=\"header\"> <div class=\"title\">${this._def.title ?? ''}</div> ${this._def.dataSource?.mode === 'db' && !this._def.columns.some(col => col.searchable) ? html `<div class=\"search\"></div>` : html ` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${() => this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen ? 'open' : ''}\"> ${[...this._def.columns].filter(col => col.type !== 'actions').sort((a, b) => (a.label ?? a.id).localeCompare(b.label ?? b.id)).map(col => html ` <div class=\"column-picker-item\" @click=${() => this._toggleColumn(col.id)}> <div class=\"column-picker-checkbox ${this._displayedColumns.includes(col.id) ? 'checked' : ''}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${col.label ?? col.id}</span> </div> `)} </div> </div> ${this._def.actions?.length === 1 ? html ` <kr-button class=\"actions\" .href=${this._def.actions[0].href} .target=${this._def.actions[0].target} @click=${() => this._handleAction(this._def.actions[0])} > ${this._def.actions[0].label} </kr-button> ` : this._def.actions?.length ? html ` <kr-button class=\"actions\" .options=${this._def.actions.map(a => ({ id: a.id, label: a.label }))} @option-select=${(e) => this._handleAction({ id: e.detail.id, label: e.detail.label })} > Actions </kr-button> ` : nothing} </div> </div> `; } /** Renders status message (loading, error, empty) */ _renderStatus() { if (this._dataState === 'loading' && this._data.length === 0) { return html `<div class=\"status\">Loading...</div>`; } if (this._dataState === 'error' && this._data.length === 0) { return html `<div class=\"status status--error\">Error loading data</div>`; } if (this._data.length === 0) { return html `<div class=\"status\">No data available</div>`; } return nothing; } /** Renders the scrollable data grid with column headers and rows. */ _renderTable() { return html ` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map((col, i) => html ` <div class=${classMap(this._getHeaderCellClasses(col, i))} style=${styleMap(this._getCellStyle(col, i))} data-column-id=${col.id} >${col.label ?? col.id}${col.resizable !== false ? html `<div class=\"header-cell__resize\" @mousedown=${(e) => this._handleResizeStart(e, col.id)} ></div>` : nothing}</div> `)} </div> ${this._data.map((row, rowIndex) => { const cells = this.getDisplayedColumns().map((col, i) => html ` <div class=${classMap(this._getCellClasses(col, i))} style=${styleMap(this._getCellStyle(col, i))} data-column-id=${col.id} > ${this._renderCellContent(col, row, rowIndex)} </div> `); if (this._def.rowHref) { return html ` <a href=${this._def.rowHref(row)} class=${classMap({ 'row': true, 'row--clickable': true, 'row--link': true })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</a> `; } return html ` <div class=${classMap({ 'row': true, 'row--clickable': !!this._def.rowClickable })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</div> `; })} </div> </div> </div> `; } /** * Renders a data table with: * - Header bar with title, search input with view selector, and tools (pagination, refresh, column visibility, actions dropdown) * - Scrollable grid with sticky header row and optional sticky left/right columns * - Loading, error message, or empty state when no data */ render() { if (!this._def.columns.length) { return html `<slot></slot>`; } return html ` ${this._renderHeader()} ${this._renderTable()} `; } }"
|
|
2567
|
+
"default": "class KRTable extends LitElement { constructor() { super(...arguments); /** * Internal flag to switch between scroll edge modes: * - 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge) * - 'edge': Padding scrolls with content, allowing table to reach edges when scrolling */ this._scrollStyle = 'overlay'; this._data = []; this._dataState = 'idle'; this._page = 1; this._pageSize = 50; this._totalItems = 0; this._totalPages = 0; this._searchQuery = ''; this._canScrollLeft = false; this._canScrollRight = false; this._canScrollHorizontal = false; this._columnPickerOpen = false; this._filterPanelOpened = null; this._filterPanelTab = 'filter'; this._buckets = new Map(); this._filterPanelPos = { top: 0, left: 0 }; this._resizing = null; this._resizeObserver = null; this._searchPositionLocked = false; this._model = new KRTableModel(); this.def = { columns: [] }; this._handleClickOutside = (e) => { const path = e.composedPath(); if (this._columnPickerOpen) { const picker = this.shadowRoot?.querySelector('.column-picker-wrapper'); if (picker && !path.includes(picker)) { this._columnPickerOpen = false; } } if (this._filterPanelOpened) { if (!path.some((el) => el.classList?.contains('filter-panel'))) { this._handleFilterApply(); } } }; this._handleResizeMove = (e) => { if (!this._resizing) return; const col = this._model.columns.find(c => c.id === this._resizing.columnId); if (col) { const newWidth = this._resizing.startWidth + (e.clientX - this._resizing.startX); col.width = `${Math.min(900, Math.max(50, newWidth))}px`; this.requestUpdate(); } }; this._handleResizeEnd = () => { this._resizing = null; document.removeEventListener('mousemove', this._handleResizeMove); document.removeEventListener('mouseup', this._handleResizeEnd); }; } connectedCallback() { super.connectedCallback(); this.classList.toggle('kr-table--scroll-overlay', this._scrollStyle === 'overlay'); this.classList.toggle('kr-table--scroll-edge', this._scrollStyle === 'edge'); this._fetch(); this._initRefresh(); document.addEventListener('click', this._handleClickOutside); this._resizeObserver = new ResizeObserver(() => { // Unlock and recalculate on resize since layout changes this._searchPositionLocked = false; this._updateSearchPosition(); }); this._resizeObserver.observe(this); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._refreshTimer); document.removeEventListener('click', this._handleClickOutside); this._resizeObserver?.disconnect(); } willUpdate(changedProperties) { if (changedProperties.has('def')) { // Build internal model from user-provided def this._model = new KRTableModel(); if (this.def.title) { this._model.title = this.def.title; } if (this.def.actions) { this._model.actions = this.def.actions; } if (this.def.data) { this._model.data = this.def.data; } if (this.def.dataSource) { this._model.dataSource = this.def.dataSource; } if (typeof this.def.refreshInterval === 'number') { this._model.refreshInterval = this.def.refreshInterval; } if (typeof this.def.pageSize === 'number') { this._model.pageSize = this.def.pageSize; } if (this.def.rowClickable) { this._model.rowClickable = this.def.rowClickable; } if (this.def.rowHref) { this._model.rowHref = this.def.rowHref; } this._model.columns = this.def.columns.map(col => { const column = { ...col, filter: null }; if (!column.type) { column.type = 'string'; } if (column.type === 'actions') { column.label = col.label ?? ''; column.sticky = 'right'; column.resizable = false; return column; } if (col.filterable || col.facetable) { column.filter = new KRQuery(); column.filter.field = col.id; column.filter.type = column.type; if (col.facetable && !col.filterable) { column.filter.operator = 'in'; column.filter.value = []; } else if (column.filter.type === 'string') { column.filter.operator = 'contains'; } } return column; }); if (this.def.displayedColumns) { this._model.displayedColumns = this.def.displayedColumns; } else { this._model.displayedColumns = this._model.columns.map(c => c.id); } this._fetch(); this._initRefresh(); } } updated(changedProperties) { this._updateScrollFlags(); this._syncSlottedContent(); } /** Syncs light DOM content for cells with custom render functions */ _syncSlottedContent() { const columns = this.getDisplayedColumns().filter(col => col.render); if (!columns.length) return; // Clear old slotted content this.querySelectorAll('[slot^=\"cell-\"]').forEach(el => el.remove()); // Create new slotted content this._data.forEach((row, rowIndex) => { columns.forEach(col => { const result = col.render(row); if (!result) return; const el = document.createElement('span'); el.slot = `cell-${rowIndex}-${col.id}`; if (col.type === 'actions') { el.style.display = 'flex'; el.style.gap = '8px'; } if (typeof result === 'string') { el.innerHTML = result; } else { render(result, el); } this.appendChild(el); }); }); } // ---------------------------------------------------------------------------- // Public Interface // ---------------------------------------------------------------------------- refresh() { this._fetch(); } goToPrevPage() { if (this._page > 1) { this._page--; this._fetch(); } } goToNextPage() { if (this._page < this._totalPages) { this._page++; this._fetch(); } } goToPage(page) { if (page >= 1 && page <= this._totalPages) { this._page = page; this._fetch(); } } // ---------------------------------------------------------------------------- // Data Fetching // ---------------------------------------------------------------------------- _toSolrData() { const request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } const filterData = col.filter.toSolrData(); if (col.facetable && col.filter.operator === 'in') { filterData.tagged = true; } request.filterFields.push(filterData); } for (const col of this._model.columns) { if (!col.facetable) { continue; } request.facetFields.push({ name: col.id, type: 'FIELD', limit: 100, sort: 'count', minimumCount: 1 }); } if (this._searchQuery?.trim().length) { request.queryFields.push({ name: '_text_', operation: 'IS', value: termify(this._searchQuery, false) }); } return request; } _toDbParams() { const request = { page: this._page - 1, size: this._pageSize, sorts: [], filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } request.filterFields.push(col.filter.toDbParams()); } if (this._searchQuery?.trim().length) { this._model.columns.filter(col => col.searchable).forEach(col => { request.queryFields.push({ name: col.id, operation: 'CONTAINS', value: this._searchQuery, and: false }); }); } return request; } /** * Fetches data from the API and updates the table. * Shows a loading spinner while fetching, then displays rows on success * or an error snackbar on failure. * Request/response format depends on dataSource.mode (solr, opensearch, db). */ _fetch() { if (this._model.data) { this._data = this._model.data; this._totalItems = this._model.data.length; this._totalPages = Math.ceil(this._model.data.length / this._pageSize); this._dataState = 'success'; return; } if (!this._model.dataSource) return; this._dataState = 'loading'; let request; if (this._model.dataSource.mode === 'db') { request = this._toDbParams(); } else { request = this._toSolrData(); } this._model.dataSource.fetch(request) .then(response => { // Parse response based on mode switch (this._model.dataSource?.mode) { case 'opensearch': { throw Error('Opensearch not supported yet'); break; } case 'db': { const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; break; } default: { // solr const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; this._parseFacetResults(res); } } this._dataState = 'success'; this._updateSearchPosition(); }) .catch(err => { this._dataState = 'error'; KRSnackbar.show({ message: err instanceof Error ? err.message : 'Failed to load data', type: 'error' }); }); } _parseFacetResults(response) { if (!response.data.facetFields) { return; } for (const col of this._model.columns) { if (!col.facetable) { continue; } const rawBuckets = response.data.facetFields[col.id]; if (!rawBuckets) { this._buckets.set(col.id, []); continue; } const buckets = []; for (const raw of rawBuckets) { // Solr returns boolean facet values as strings — coerce to actual booleans // so they match the filter values stored by toggle(). let val = raw.name; if (col.type === 'boolean' && typeof raw.name === 'string') { if (raw.name === 'true') { val = true; } else if (raw.name === 'false') { val = false; } } if (raw.name === null && raw.count > 0) { buckets.unshift({ val: null, count: raw.count }); } if (raw.name !== null) { buckets.push({ val: val, count: raw.count }); } } // Bucket sync: ensure selected values appear even with 0 results if (col.filter && col.filter.operator === 'in' && Array.isArray(col.filter.value)) { for (const selectedVal of col.filter.value) { if (!buckets.some(b => b.val === selectedVal)) { buckets.push({ val: selectedVal, count: 0 }); } } } this._buckets.set(col.id, buckets); } // Trigger re-render since Map mutation doesn't trigger Lit updates this._buckets = new Map(this._buckets); } /** * Sets up auto-refresh so the table automatically fetches fresh data * at a regular interval (useful for dashboards, monitoring views). * Configured via def.refreshInterval in milliseconds. */ _initRefresh() { clearInterval(this._refreshTimer); if (this._model.refreshInterval && this._model.refreshInterval > 0) { this._refreshTimer = window.setInterval(() => { this._fetch(); }, this._model.refreshInterval); } } _handleSearch(e) { const input = e.target; this._searchQuery = input.value; this._page = 1; this._fetch(); } _getGridTemplateColumns() { const cols = this.getDisplayedColumns(); return cols.map((col) => { // If column has explicit width, use it if (col.width) { return col.width; } // Actions columns: fit content without minimum if (col.type === 'actions') { return 'max-content'; } // No width specified - use content-based sizing with minimum return 'minmax(80px, auto)'; }).join(' '); } /** * Updates search position to be centered with equal gaps from title and tools. * On first call: resets to flex centering, measures position, then locks with fixed margin. * Subsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize). */ _updateSearchPosition() { // Skip if already locked (prevents shifts on pagination changes) if (this._searchPositionLocked) return; const search = this.shadowRoot?.querySelector('.search'); const searchField = search?.querySelector('.search-field'); if (!search || !searchField) return; // Reset to flex centering search.style.justifyContent = 'center'; searchField.style.marginLeft = ''; requestAnimationFrame(() => { const searchRect = search.getBoundingClientRect(); const fieldRect = searchField.getBoundingClientRect(); // Calculate how far from the left of search container the field currently is const currentOffset = fieldRect.left - searchRect.left; // Lock position: switch to flex-start and use fixed margin search.style.justifyContent = 'flex-start'; searchField.style.marginLeft = `${currentOffset}px`; // Mark as locked so pagination changes don't shift the search this._searchPositionLocked = true; }); } // ---------------------------------------------------------------------------- // Columns // ---------------------------------------------------------------------------- _toggleColumnPicker() { this._columnPickerOpen = !this._columnPickerOpen; } _toggleColumn(columnId) { if (this._model.displayedColumns.includes(columnId)) { this._model.displayedColumns = this._model.displayedColumns.filter(id => id !== columnId); } else { this._model.displayedColumns = [...this._model.displayedColumns, columnId]; } } // Clear any existing text selection on mousedown so we only detect // selections made during this click gesture, not stale selections from elsewhere _handleRowMouseDown() { if (!this._model.rowClickable) { return; } window.getSelection()?.removeAllRanges(); } _handleRowClick(row, rowIndex) { if (!this._model.rowClickable) { return; } const selection = window.getSelection(); if (selection && selection.toString().length > 0) { return; } this.dispatchEvent(new CustomEvent('row-click', { detail: { row, rowIndex }, bubbles: true, composed: true })); } // When a user toggles a column on via the column picker, it gets appended // to _displayedColumns. By mapping over _displayedColumns (not def.columns), // the new column appears at the right edge of the table instead of jumping // back to its original position in the column definition. // Actions columns are always moved to the end. getDisplayedColumns() { return this._model.displayedColumns .map(id => this._model.columns.find(col => col.id === id)) .sort((a, b) => { if (a.type === 'actions' && b.type !== 'actions') return 1; if (a.type !== 'actions' && b.type === 'actions') return -1; return 0; }); } // ---------------------------------------------------------------------------- // Scrolling // ---------------------------------------------------------------------------- /** * Scroll event handler that updates scroll flags in real-time as user scrolls. * Updates shadow indicators to show if more content exists left/right. */ _handleScroll(e) { const container = e.target; this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollLeft < container.scrollWidth - container.clientWidth - 1; } /** * Updates scroll state flags for the table content container. * - _canScrollLeft: true if scrolled right (can scroll back left) * - _canScrollRight: true if more content exists to the right * - _canScrollHorizontal: true if content is wider than container * These flags control scroll shadow indicators and CSS classes. */ _updateScrollFlags() { const container = this.shadowRoot?.querySelector('.content'); if (container) { this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollWidth > container.clientWidth && container.scrollLeft < container.scrollWidth - container.clientWidth - 1; this._canScrollHorizontal = container.scrollWidth > container.clientWidth; } this.classList.toggle('kr-table--scroll-left-available', this._canScrollLeft); this.classList.toggle('kr-table--scroll-right-available', this._canScrollRight); this.classList.toggle('kr-table--scroll-horizontal-available', this._canScrollHorizontal); this.classList.toggle('kr-table--sticky-left', this.getDisplayedColumns().some(c => c.sticky === 'left')); this.classList.toggle('kr-table--sticky-right', this.getDisplayedColumns().some(c => c.sticky === 'right')); } // ---------------------------------------------------------------------------- // Column Resizing // ---------------------------------------------------------------------------- _handleResizeStart(e, columnId) { e.preventDefault(); const headerCell = this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${columnId}\"]`); this._resizing = { columnId, startX: e.clientX, startWidth: headerCell?.offsetWidth || 200 }; document.addEventListener('mousemove', this._handleResizeMove); document.addEventListener('mouseup', this._handleResizeEnd); } // ---------------------------------------------------------------------------- // Header // ---------------------------------------------------------------------------- _handleAction(action) { if (action.href) { return; } this.dispatchEvent(new CustomEvent('action', { detail: { action: action.id }, bubbles: true, composed: true })); } // ---------------------------------------------------------------------------- // Filter Handlers // ---------------------------------------------------------------------------- _handleKqlChange(e, column) { const kql = e.target.value.trim(); if (!kql) { column.filter.clear(); this.requestUpdate(); } else { column.filter.setKql(kql); this.requestUpdate(); if (!column.filter.isValid()) { return; } } this._page = 1; this._fetch(); } _handleFilterPanelToggle(e, column) { e.stopPropagation(); if (this._filterPanelOpened === column.id) { this._filterPanelOpened = null; } else { const rect = e.currentTarget.getBoundingClientRect(); this._filterPanelPos = { top: rect.bottom + 4, left: rect.left }; this._filterPanelOpened = column.id; if (column.facetable) { this._filterPanelTab = 'counts'; } else { this._filterPanelTab = 'filter'; } } } _handleKqlClear(column) { column.filter.clear(); this._page = 1; this._fetch(); } _handleFilterClear() { const column = this._model.columns.find(c => c.id === this._filterPanelOpened); if (column) { column.filter.clear(); if (column.facetable && !column.filterable) { column.filter.operator = 'in'; column.filter.value = []; } } this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterTextKeydown(e, column) { if (e.key === 'Enter') { e.preventDefault(); this._handleFilterApply(); } } _handleOperatorChange(e, column) { column.filter.setOperator(e.target.value); this.requestUpdate(); } _handleFilterStringChange(e, column) { column.filter.setValue(e.target.value); this.requestUpdate(); } _handleFilterNumberChange(e, column) { column.filter.setValue(Number(e.target.value)); this.requestUpdate(); } _handleFilterDateChange(e, column) { column.filter.setValue(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterBooleanChange(e, column) { column.filter.setValue(e.target.value === 'true'); this.requestUpdate(); } _handleFilterDateStartChange(e, column) { column.filter.setStart(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterDateEndChange(e, column) { column.filter.setEnd(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterNumberStartChange(e, column) { column.filter.setStart(Number(e.target.value)); this.requestUpdate(); } _handleFilterNumberEndChange(e, column) { column.filter.setEnd(Number(e.target.value)); this.requestUpdate(); } _handleFilterListChange(e, column) { const items = e.target.value.split(',').map((v) => v.trim()).filter((v) => v !== ''); if (column.type === 'number') { column.filter.setValue(items.map((v) => Number(v))); } else { column.filter.setValue(items); } this.requestUpdate(); } _handleFilterApply() { this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterPanelTabChange(e) { this._filterPanelTab = e.detail.activeTabId; } _handleBucketToggle(e, column, bucket) { column.filter.toggle(bucket.val); this._page = 1; this._fetch(); } // ---------------------------------------------------------------------------- // Rendering // ---------------------------------------------------------------------------- _renderCellContent(column, row, rowIndex) { const value = row[column.id]; if (column.render) { // Use slot to project content from light DOM so external styles apply return html `<slot name=\"cell-${rowIndex}-${column.id}\"></slot>`; } if (value === null || value === undefined) { return ''; } switch (column.type) { case 'number': if (column.format === 'currency' && typeof value === 'number') { return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); } return String(value); case 'date': { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(value)) { // MySQL datetime format (UTC): \"2026-01-28 01:33:44:517\" // Replace last colon before ms with dot, append Z for UTC const isoString = value.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/, '$1.$2').replace(' ', 'T') + 'Z'; date = new Date(isoString); } else { date = new Date(value); } // Show date and time for datetime values in UTC return date.toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZone: 'UTC' }); } case 'boolean': if (value === true) return 'Yes'; if (value === false) return 'No'; return ''; default: return String(value); } } /** * Returns CSS classes for a header cell based on column config. */ _getHeaderCellClasses(column, index) { return { 'header-cell': true, 'header-cell--align-center': column.align === 'center', 'header-cell--align-right': column.align === 'right', 'header-cell--sticky-left': column.sticky === 'left', 'header-cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'header-cell--sticky-right': column.sticky === 'right', 'header-cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns CSS classes for a table cell based on column config: * - Alignment (center, right) * - Sticky positioning (left, right) * - Border classes for the last left-sticky or first right-sticky column */ _getCellClasses(column, index) { return { 'cell': true, 'cell--actions': column.type === 'actions', 'cell--align-center': column.align === 'center', 'cell--align-right': column.align === 'right', 'cell--sticky-left': column.sticky === 'left', 'cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'cell--sticky-right': column.sticky === 'right', 'cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns inline styles for a table cell: * - Width (from column config or default 150px) * - Min-width (if specified) * - Left/right offset for sticky columns (calculated from widths of preceding sticky columns) */ _getCellStyle(column, index) { const styles = {}; if (column.sticky === 'left') { let leftOffset = 0; for (let i = 0; i < index; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'left') { leftOffset += parseInt(col.width || '0', 10); } } styles.left = `${leftOffset}px`; } if (column.sticky === 'right') { let rightOffset = 0; for (let i = index + 1; i < this.getDisplayedColumns().length; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'right') { rightOffset += parseInt(col.width || '0', 10); } } styles.right = `${rightOffset}px`; } return styles; } /** * Renders the pagination controls: * - Previous page arrow (disabled on first page) * - Range text showing \"1-50 of 150\" format * - Next page arrow (disabled on last page) * * Hidden when there's no data or all data fits on one page. */ _renderPagination() { const start = (this._page - 1) * this._pageSize + 1; const end = Math.min(this._page * this._pageSize, this._totalItems); return html ` <div class=\"pagination\"> <span class=\"pagination-icon ${this._page === 1 ? 'pagination-icon--disabled' : ''}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${start}-${end} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page === this._totalPages ? 'pagination-icon--disabled' : ''}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `; } /** * Renders the header toolbar containing: * - Title (left) * - Search bar with view selector dropdown (center) * - Tools (right): page navigation, refresh button, column visibility picker, actions dropdown * * Hidden when there's no title, no actions, and data fits on one page. */ _renderHeader() { if (!this._model.title && !this._model.actions?.length && this._totalPages <= 1) { return nothing; } return html ` <div class=\"header\"> <div class=\"title\">${this._model.title ?? ''}</div> ${this._model.dataSource?.mode === 'db' && !this._model.columns.some(col => col.searchable) ? html `<div class=\"search\"></div>` : html ` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${() => this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen ? 'open' : ''}\"> ${[...this._model.columns].filter(col => col.type !== 'actions').sort((a, b) => (a.label ?? a.id).localeCompare(b.label ?? b.id)).map(col => html ` <div class=\"column-picker-item\" @click=${() => this._toggleColumn(col.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(col.id) ? 'checked' : ''}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${col.label ?? col.id}</span> </div> `)} </div> </div> ${this._model.actions?.length === 1 ? html ` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${() => this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> ` : this._model.actions?.length ? html ` <kr-button class=\"actions\" .options=${this._model.actions.map(a => ({ id: a.id, label: a.label }))} @option-select=${(e) => this._handleAction({ id: e.detail.id, label: e.detail.label })} > Actions </kr-button> ` : nothing} </div> </div> `; } /** Renders status message (loading, error, empty) */ _renderStatus() { if (this._dataState === 'loading' && this._data.length === 0) { return html `<div class=\"status\">Loading...</div>`; } if (this._dataState === 'error' && this._data.length === 0) { return html `<div class=\"status status--error\">Error loading data</div>`; } if (this._data.length === 0) { return html `<div class=\"status\">No data available</div>`; } return nothing; } _renderFilterPanel() { if (!this._filterPanelOpened) { return nothing; } const column = this._model.columns.find(c => c.id === this._filterPanelOpened); // Build filter content (operator + value input) let valueInput = html ``; if (column.filter.operator === 'empty' || column.filter.operator === 'n_empty') { valueInput = html ` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${column.filter.text} /> `; } else if (column.filter.operator === 'between' && column.type === 'date') { valueInput = html ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.start ?? null} @change=${(e) => this._handleFilterDateStartChange(e, column)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.end ?? null} @change=${(e) => this._handleFilterDateEndChange(e, column)} /> `; } else if (column.filter.operator === 'between' && column.type === 'number') { valueInput = html ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${column.filter.value?.start ?? ''} @input=${(e) => this._handleFilterNumberStartChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${column.filter.value?.end ?? ''} @input=${(e) => this._handleFilterNumberEndChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else if (column.filter.operator === 'in') { valueInput = html ` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${column.filter.text} @input=${(e) => this._handleFilterListChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} ></textarea> `; } else if (column.type === 'boolean') { valueInput = html ` <kr-select-field placeholder=\"Value\" .value=${String(column.filter.value ?? '')} @change=${(e) => this._handleFilterBooleanChange(e, column)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `; } else if (column.type === 'date') { valueInput = html ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value} @change=${(e) => this._handleFilterDateChange(e, column)} /> `; } else if (column.type === 'number') { valueInput = html ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${column.filter.text} @input=${(e) => this._handleFilterNumberChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else { valueInput = html ` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${column.filter.text} @input=${(e) => this._handleFilterStringChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } const filterContent = html ` <div class=\"filter-panel__content\"> <kr-select-field .value=${column.filter.operator} @change=${(e) => this._handleOperatorChange(e, column)} > ${getOperatorsForType(column.type).map(op => html ` <kr-select-option value=${op.key}>${op.label}</kr-select-option> `)} </kr-select-field> ${valueInput} </div> `; // Build bucket list content const buckets = this._buckets.get(column.id) || []; let bucketContent; if (!buckets.length) { bucketContent = html `<div class=\"bucket-empty\">No data</div>`; } else { bucketContent = html ` <div class=\"buckets\"> ${buckets.map(bucket => { let bucketLabel = '(Empty)'; if (bucket.val !== null && bucket.val !== undefined) { if (column.type === 'boolean') { if (bucket.val === true || bucket.val === 'true') { bucketLabel = 'Yes'; } else { bucketLabel = 'No'; } } else { bucketLabel = String(bucket.val); } } let checkIcon = nothing; if (column.filter.has(bucket.val)) { checkIcon = html ` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `; } return html ` <div class=\"bucket\" @click=${(e) => this._handleBucketToggle(e, column, bucket)} > <div class=${classMap({ 'bucket__checkbox': true, 'bucket__checkbox--checked': column.filter.has(bucket.val) })}> ${checkIcon} </div> <span class=\"bucket__label\">${bucketLabel}</span> <span class=\"bucket__count\">${bucket.count}</span> </div> `; })} </div> `; } // Build panel body — tabs if both filterable+facetable, otherwise just the relevant content let panelBody; if (column.facetable && column.filterable) { panelBody = html ` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${(e) => this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${filterContent} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${bucketContent} </kr-tab> </kr-tab-group> `; } else if (column.facetable) { panelBody = bucketContent; } else { panelBody = filterContent; } return html ` <div class=\"filter-panel\" style=${styleMap({ top: this._filterPanelPos.top + 'px', left: this._filterPanelPos.left + 'px' })} > ${panelBody} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `; } /** * Renders filter row below column headers. * Only displays for columns with filterable: true. */ _renderFilterRow() { const columns = this.getDisplayedColumns(); if (!columns.some(col => col.filterable || col.facetable)) { return nothing; } return html ` <div class=\"filter-row\"> ${columns.map((col, i) => { if (!col.filterable && !col.facetable) { return html `<div class=${classMap({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${styleMap(this._getCellStyle(col, i))} ></div>`; } return html ` <div class=${classMap({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${styleMap(this._getCellStyle(col, i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${classMap({ 'filter-cell__input': true, 'filter-cell__input--invalid': !col.filter.isValid() })} .value=${col.filter.kql} @change=${(e) => this._handleKqlChange(e, col)} /> ${col.filter?.kql?.length > 0 ? html ` <button class=\"filter-cell__clear\" @click=${() => this._handleKqlClear(col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> ` : nothing} <button class=${classMap({ 'filter-cell__advanced': true, 'filter-cell__advanced--opened': this._filterPanelOpened === col.id })} @click=${(e) => this._handleFilterPanelToggle(e, col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `; })} </div> `; } /** Renders the scrollable data grid with column headers and rows. */ _renderTable() { return html ` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map((col, i) => html ` <div class=${classMap(this._getHeaderCellClasses(col, i))} style=${styleMap(this._getCellStyle(col, i))} data-column-id=${col.id} >${col.label ?? col.id}${col.resizable !== false ? html `<div class=\"header-cell__resize\" @mousedown=${(e) => this._handleResizeStart(e, col.id)} ></div>` : nothing}</div> `)} </div> ${this._renderFilterRow()} ${this._data.map((row, rowIndex) => { const cells = this.getDisplayedColumns().map((col, i) => html ` <div class=${classMap(this._getCellClasses(col, i))} style=${styleMap(this._getCellStyle(col, i))} data-column-id=${col.id} > ${this._renderCellContent(col, row, rowIndex)} </div> `); if (this._model.rowHref) { return html ` <a href=${this._model.rowHref(row)} class=${classMap({ 'row': true, 'row--clickable': true, 'row--link': true })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</a> `; } return html ` <div class=${classMap({ 'row': true, 'row--clickable': !!this._model.rowClickable })} @mousedown=${() => this._handleRowMouseDown()} @click=${() => this._handleRowClick(row, rowIndex)} >${cells}</div> `; })} </div> </div> </div> `; } /** * Renders a data table with: * - Header bar with title, search input with view selector, and tools (pagination, refresh, column visibility, actions dropdown) * - Scrollable grid with sticky header row and optional sticky left/right columns * - Loading, error message, or empty state when no data */ render() { if (!this._model.columns.length) { return html `<slot></slot>`; } return html ` ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `; } }"
|
|
1737
2568
|
}
|
|
1738
2569
|
],
|
|
1739
2570
|
"exports": [
|
|
@@ -4044,11 +4875,433 @@
|
|
|
4044
4875
|
},
|
|
4045
4876
|
{
|
|
4046
4877
|
"kind": "javascript-module",
|
|
4047
|
-
"path": "src/table/
|
|
4878
|
+
"path": "src/table/query.ts",
|
|
4048
4879
|
"declarations": [
|
|
4049
4880
|
{
|
|
4050
|
-
"kind": "
|
|
4051
|
-
"
|
|
4881
|
+
"kind": "variable",
|
|
4882
|
+
"name": "KR_OPERATORS",
|
|
4883
|
+
"type": {
|
|
4884
|
+
"text": "Record<KROperator, KROperatorMeta>"
|
|
4885
|
+
},
|
|
4886
|
+
"default": "{ equals: { key: 'equals', type: 'comparison', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Equals' }, n_equals: { key: 'n_equals', type: 'comparison', dataTypes: ['string', 'number', 'date', 'boolean'], label: \"Doesn't equal\" }, contains: { key: 'contains', type: 'comparison', dataTypes: ['string'], label: 'Contains' }, n_contains: { key: 'n_contains', type: 'comparison', dataTypes: ['string'], label: \"Doesn't contain\" }, starts_with: { key: 'starts_with', type: 'comparison', dataTypes: ['string'], label: 'Starts with' }, ends_with: { key: 'ends_with', type: 'comparison', dataTypes: ['string'], label: 'Ends with' }, less_than: { key: 'less_than', type: 'comparison', dataTypes: ['number', 'date'], label: 'Less than' }, less_than_equal: { key: 'less_than_equal', type: 'comparison', dataTypes: ['number', 'date'], label: 'Less than or equal' }, greater_than: { key: 'greater_than', type: 'comparison', dataTypes: ['number', 'date'], label: 'Greater than' }, greater_than_equal: { key: 'greater_than_equal', type: 'comparison', dataTypes: ['number', 'date'], label: 'Greater than or equal' }, between: { key: 'between', type: 'range', dataTypes: ['number', 'date'], label: 'Between' }, in: { key: 'in', type: 'list', dataTypes: ['string', 'number'], label: 'In' }, empty: { key: 'empty', type: 'nil', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Empty' }, n_empty: { key: 'n_empty', type: 'nil', dataTypes: ['string', 'number', 'date', 'boolean'], label: 'Not empty' }, }",
|
|
4887
|
+
"description": "Data-driven operator metadata map"
|
|
4888
|
+
},
|
|
4889
|
+
{
|
|
4890
|
+
"kind": "function",
|
|
4891
|
+
"name": "getOperatorsForType",
|
|
4892
|
+
"return": {
|
|
4893
|
+
"type": {
|
|
4894
|
+
"text": "{ key: KROperator; label: string }[]"
|
|
4895
|
+
}
|
|
4896
|
+
},
|
|
4897
|
+
"parameters": [
|
|
4898
|
+
{
|
|
4899
|
+
"name": "columnType",
|
|
4900
|
+
"type": {
|
|
4901
|
+
"text": "string"
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
],
|
|
4905
|
+
"description": "Returns the list of operators available for a given column type"
|
|
4906
|
+
},
|
|
4907
|
+
{
|
|
4908
|
+
"kind": "function",
|
|
4909
|
+
"name": "termify",
|
|
4910
|
+
"return": {
|
|
4911
|
+
"type": {
|
|
4912
|
+
"text": "string"
|
|
4913
|
+
}
|
|
4914
|
+
},
|
|
4915
|
+
"parameters": [
|
|
4916
|
+
{
|
|
4917
|
+
"name": "value",
|
|
4918
|
+
"type": {
|
|
4919
|
+
"text": "any"
|
|
4920
|
+
}
|
|
4921
|
+
},
|
|
4922
|
+
{
|
|
4923
|
+
"name": "exact",
|
|
4924
|
+
"default": "true",
|
|
4925
|
+
"type": {
|
|
4926
|
+
"text": "boolean"
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
],
|
|
4930
|
+
"description": "Converts a value to a Solr term"
|
|
4931
|
+
},
|
|
4932
|
+
{
|
|
4933
|
+
"kind": "class",
|
|
4934
|
+
"description": "",
|
|
4935
|
+
"name": "KRQuery",
|
|
4936
|
+
"members": [
|
|
4937
|
+
{
|
|
4938
|
+
"kind": "field",
|
|
4939
|
+
"name": "field",
|
|
4940
|
+
"type": {
|
|
4941
|
+
"text": "string"
|
|
4942
|
+
},
|
|
4943
|
+
"default": "''"
|
|
4944
|
+
},
|
|
4945
|
+
{
|
|
4946
|
+
"kind": "field",
|
|
4947
|
+
"name": "operator",
|
|
4948
|
+
"type": {
|
|
4949
|
+
"text": "KROperator"
|
|
4950
|
+
},
|
|
4951
|
+
"default": "'equals'"
|
|
4952
|
+
},
|
|
4953
|
+
{
|
|
4954
|
+
"kind": "field",
|
|
4955
|
+
"name": "value",
|
|
4956
|
+
"type": {
|
|
4957
|
+
"text": "any"
|
|
4958
|
+
},
|
|
4959
|
+
"default": "null"
|
|
4960
|
+
},
|
|
4961
|
+
{
|
|
4962
|
+
"kind": "field",
|
|
4963
|
+
"name": "kql",
|
|
4964
|
+
"type": {
|
|
4965
|
+
"text": "string"
|
|
4966
|
+
},
|
|
4967
|
+
"default": "''"
|
|
4968
|
+
},
|
|
4969
|
+
{
|
|
4970
|
+
"kind": "field",
|
|
4971
|
+
"name": "text",
|
|
4972
|
+
"type": {
|
|
4973
|
+
"text": "string"
|
|
4974
|
+
},
|
|
4975
|
+
"default": "''"
|
|
4976
|
+
},
|
|
4977
|
+
{
|
|
4978
|
+
"kind": "field",
|
|
4979
|
+
"name": "type",
|
|
4980
|
+
"type": {
|
|
4981
|
+
"text": "string"
|
|
4982
|
+
},
|
|
4983
|
+
"default": "''"
|
|
4984
|
+
},
|
|
4985
|
+
{
|
|
4986
|
+
"kind": "field",
|
|
4987
|
+
"name": "specificity",
|
|
4988
|
+
"type": {
|
|
4989
|
+
"text": "KRDateSpecificity[]"
|
|
4990
|
+
},
|
|
4991
|
+
"default": "[]"
|
|
4992
|
+
},
|
|
4993
|
+
{
|
|
4994
|
+
"kind": "method",
|
|
4995
|
+
"name": "setKql",
|
|
4996
|
+
"return": {
|
|
4997
|
+
"type": {
|
|
4998
|
+
"text": "void"
|
|
4999
|
+
}
|
|
5000
|
+
},
|
|
5001
|
+
"parameters": [
|
|
5002
|
+
{
|
|
5003
|
+
"name": "kql",
|
|
5004
|
+
"type": {
|
|
5005
|
+
"text": "string"
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
],
|
|
5009
|
+
"description": "Parse a KQL text string and populate operator/value/values"
|
|
5010
|
+
},
|
|
5011
|
+
{
|
|
5012
|
+
"kind": "method",
|
|
5013
|
+
"name": "setOperator",
|
|
5014
|
+
"return": {
|
|
5015
|
+
"type": {
|
|
5016
|
+
"text": "void"
|
|
5017
|
+
}
|
|
5018
|
+
},
|
|
5019
|
+
"parameters": [
|
|
5020
|
+
{
|
|
5021
|
+
"name": "operator",
|
|
5022
|
+
"type": {
|
|
5023
|
+
"text": "KROperator"
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
]
|
|
5027
|
+
},
|
|
5028
|
+
{
|
|
5029
|
+
"kind": "method",
|
|
5030
|
+
"name": "setValue",
|
|
5031
|
+
"return": {
|
|
5032
|
+
"type": {
|
|
5033
|
+
"text": "void"
|
|
5034
|
+
}
|
|
5035
|
+
},
|
|
5036
|
+
"parameters": [
|
|
5037
|
+
{
|
|
5038
|
+
"name": "value",
|
|
5039
|
+
"type": {
|
|
5040
|
+
"text": "any"
|
|
5041
|
+
}
|
|
5042
|
+
},
|
|
5043
|
+
{
|
|
5044
|
+
"name": "specificity",
|
|
5045
|
+
"optional": true,
|
|
5046
|
+
"type": {
|
|
5047
|
+
"text": "KRDateSpecificity"
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
]
|
|
5051
|
+
},
|
|
5052
|
+
{
|
|
5053
|
+
"kind": "method",
|
|
5054
|
+
"name": "setStart",
|
|
5055
|
+
"return": {
|
|
5056
|
+
"type": {
|
|
5057
|
+
"text": "void"
|
|
5058
|
+
}
|
|
5059
|
+
},
|
|
5060
|
+
"parameters": [
|
|
5061
|
+
{
|
|
5062
|
+
"name": "value",
|
|
5063
|
+
"type": {
|
|
5064
|
+
"text": "any"
|
|
5065
|
+
}
|
|
5066
|
+
},
|
|
5067
|
+
{
|
|
5068
|
+
"name": "specificity",
|
|
5069
|
+
"optional": true,
|
|
5070
|
+
"type": {
|
|
5071
|
+
"text": "KRDateSpecificity"
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
]
|
|
5075
|
+
},
|
|
5076
|
+
{
|
|
5077
|
+
"kind": "method",
|
|
5078
|
+
"name": "setEnd",
|
|
5079
|
+
"return": {
|
|
5080
|
+
"type": {
|
|
5081
|
+
"text": "void"
|
|
5082
|
+
}
|
|
5083
|
+
},
|
|
5084
|
+
"parameters": [
|
|
5085
|
+
{
|
|
5086
|
+
"name": "value",
|
|
5087
|
+
"type": {
|
|
5088
|
+
"text": "any"
|
|
5089
|
+
}
|
|
5090
|
+
},
|
|
5091
|
+
{
|
|
5092
|
+
"name": "specificity",
|
|
5093
|
+
"optional": true,
|
|
5094
|
+
"type": {
|
|
5095
|
+
"text": "KRDateSpecificity"
|
|
5096
|
+
}
|
|
5097
|
+
}
|
|
5098
|
+
]
|
|
5099
|
+
},
|
|
5100
|
+
{
|
|
5101
|
+
"kind": "method",
|
|
5102
|
+
"name": "clear",
|
|
5103
|
+
"return": {
|
|
5104
|
+
"type": {
|
|
5105
|
+
"text": "void"
|
|
5106
|
+
}
|
|
5107
|
+
}
|
|
5108
|
+
},
|
|
5109
|
+
{
|
|
5110
|
+
"kind": "method",
|
|
5111
|
+
"name": "isEmpty",
|
|
5112
|
+
"return": {
|
|
5113
|
+
"type": {
|
|
5114
|
+
"text": "boolean"
|
|
5115
|
+
}
|
|
5116
|
+
}
|
|
5117
|
+
},
|
|
5118
|
+
{
|
|
5119
|
+
"kind": "method",
|
|
5120
|
+
"name": "has",
|
|
5121
|
+
"return": {
|
|
5122
|
+
"type": {
|
|
5123
|
+
"text": "boolean"
|
|
5124
|
+
}
|
|
5125
|
+
},
|
|
5126
|
+
"parameters": [
|
|
5127
|
+
{
|
|
5128
|
+
"name": "val",
|
|
5129
|
+
"type": {
|
|
5130
|
+
"text": "any"
|
|
5131
|
+
}
|
|
5132
|
+
}
|
|
5133
|
+
],
|
|
5134
|
+
"description": "Returns true if the value array contains the given value. Only applies to 'in' operator."
|
|
5135
|
+
},
|
|
5136
|
+
{
|
|
5137
|
+
"kind": "method",
|
|
5138
|
+
"name": "toggle",
|
|
5139
|
+
"return": {
|
|
5140
|
+
"type": {
|
|
5141
|
+
"text": "void"
|
|
5142
|
+
}
|
|
5143
|
+
},
|
|
5144
|
+
"parameters": [
|
|
5145
|
+
{
|
|
5146
|
+
"name": "val",
|
|
5147
|
+
"type": {
|
|
5148
|
+
"text": "any"
|
|
5149
|
+
}
|
|
5150
|
+
}
|
|
5151
|
+
],
|
|
5152
|
+
"description": "Adds or removes a value from the 'in' list and rebuilds text/kql."
|
|
5153
|
+
},
|
|
5154
|
+
{
|
|
5155
|
+
"kind": "method",
|
|
5156
|
+
"name": "isValid",
|
|
5157
|
+
"return": {
|
|
5158
|
+
"type": {
|
|
5159
|
+
"text": "boolean"
|
|
5160
|
+
}
|
|
5161
|
+
}
|
|
5162
|
+
},
|
|
5163
|
+
{
|
|
5164
|
+
"kind": "method",
|
|
5165
|
+
"name": "toSolrData",
|
|
5166
|
+
"return": {
|
|
5167
|
+
"type": {
|
|
5168
|
+
"text": "any"
|
|
5169
|
+
}
|
|
5170
|
+
},
|
|
5171
|
+
"description": "Converts this filter to a Solr filter field object, or null if invalid"
|
|
5172
|
+
},
|
|
5173
|
+
{
|
|
5174
|
+
"kind": "method",
|
|
5175
|
+
"name": "toDbParams",
|
|
5176
|
+
"return": {
|
|
5177
|
+
"type": {
|
|
5178
|
+
"text": "any"
|
|
5179
|
+
}
|
|
5180
|
+
},
|
|
5181
|
+
"description": "Converts this filter to a DB filter field object, or null if invalid"
|
|
5182
|
+
},
|
|
5183
|
+
{
|
|
5184
|
+
"kind": "method",
|
|
5185
|
+
"name": "_buildText",
|
|
5186
|
+
"privacy": "private",
|
|
5187
|
+
"return": {
|
|
5188
|
+
"type": {
|
|
5189
|
+
"text": "void"
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
5192
|
+
},
|
|
5193
|
+
{
|
|
5194
|
+
"kind": "method",
|
|
5195
|
+
"name": "_format",
|
|
5196
|
+
"privacy": "private",
|
|
5197
|
+
"return": {
|
|
5198
|
+
"type": {
|
|
5199
|
+
"text": "string"
|
|
5200
|
+
}
|
|
5201
|
+
},
|
|
5202
|
+
"parameters": [
|
|
5203
|
+
{
|
|
5204
|
+
"name": "value",
|
|
5205
|
+
"type": {
|
|
5206
|
+
"text": "any"
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
]
|
|
5210
|
+
},
|
|
5211
|
+
{
|
|
5212
|
+
"kind": "method",
|
|
5213
|
+
"name": "_parse",
|
|
5214
|
+
"privacy": "private",
|
|
5215
|
+
"return": {
|
|
5216
|
+
"type": {
|
|
5217
|
+
"text": "any"
|
|
5218
|
+
}
|
|
5219
|
+
},
|
|
5220
|
+
"parameters": [
|
|
5221
|
+
{
|
|
5222
|
+
"name": "text",
|
|
5223
|
+
"type": {
|
|
5224
|
+
"text": "string"
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
],
|
|
5228
|
+
"description": "Parse a text value according to this query's type"
|
|
5229
|
+
},
|
|
5230
|
+
{
|
|
5231
|
+
"kind": "method",
|
|
5232
|
+
"name": "_parseDate",
|
|
5233
|
+
"privacy": "private",
|
|
5234
|
+
"return": {
|
|
5235
|
+
"type": {
|
|
5236
|
+
"text": "Date | null"
|
|
5237
|
+
}
|
|
5238
|
+
},
|
|
5239
|
+
"parameters": [
|
|
5240
|
+
{
|
|
5241
|
+
"name": "input",
|
|
5242
|
+
"type": {
|
|
5243
|
+
"text": "any"
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
],
|
|
5247
|
+
"description": "Parse a date string into a UTC Date"
|
|
5248
|
+
},
|
|
5249
|
+
{
|
|
5250
|
+
"kind": "method",
|
|
5251
|
+
"name": "_buildKql",
|
|
5252
|
+
"privacy": "private",
|
|
5253
|
+
"return": {
|
|
5254
|
+
"type": {
|
|
5255
|
+
"text": "void"
|
|
5256
|
+
}
|
|
5257
|
+
},
|
|
5258
|
+
"description": "Build a KQL display string from current operator/value state"
|
|
5259
|
+
}
|
|
5260
|
+
]
|
|
5261
|
+
}
|
|
5262
|
+
],
|
|
5263
|
+
"exports": [
|
|
5264
|
+
{
|
|
5265
|
+
"kind": "js",
|
|
5266
|
+
"name": "KR_OPERATORS",
|
|
5267
|
+
"declaration": {
|
|
5268
|
+
"name": "KR_OPERATORS",
|
|
5269
|
+
"module": "src/table/query.ts"
|
|
5270
|
+
}
|
|
5271
|
+
},
|
|
5272
|
+
{
|
|
5273
|
+
"kind": "js",
|
|
5274
|
+
"name": "getOperatorsForType",
|
|
5275
|
+
"declaration": {
|
|
5276
|
+
"name": "getOperatorsForType",
|
|
5277
|
+
"module": "src/table/query.ts"
|
|
5278
|
+
}
|
|
5279
|
+
},
|
|
5280
|
+
{
|
|
5281
|
+
"kind": "js",
|
|
5282
|
+
"name": "termify",
|
|
5283
|
+
"declaration": {
|
|
5284
|
+
"name": "termify",
|
|
5285
|
+
"module": "src/table/query.ts"
|
|
5286
|
+
}
|
|
5287
|
+
},
|
|
5288
|
+
{
|
|
5289
|
+
"kind": "js",
|
|
5290
|
+
"name": "KRQuery",
|
|
5291
|
+
"declaration": {
|
|
5292
|
+
"name": "KRQuery",
|
|
5293
|
+
"module": "src/table/query.ts"
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
]
|
|
5297
|
+
},
|
|
5298
|
+
{
|
|
5299
|
+
"kind": "javascript-module",
|
|
5300
|
+
"path": "src/table/table.ts",
|
|
5301
|
+
"declarations": [
|
|
5302
|
+
{
|
|
5303
|
+
"kind": "class",
|
|
5304
|
+
"description": "",
|
|
4052
5305
|
"name": "KRTable",
|
|
4053
5306
|
"members": [
|
|
4054
5307
|
{
|
|
@@ -4170,12 +5423,39 @@
|
|
|
4170
5423
|
},
|
|
4171
5424
|
{
|
|
4172
5425
|
"kind": "field",
|
|
4173
|
-
"name": "
|
|
5426
|
+
"name": "_filterPanelOpened",
|
|
4174
5427
|
"type": {
|
|
4175
|
-
"text": "string
|
|
5428
|
+
"text": "string | null"
|
|
4176
5429
|
},
|
|
4177
5430
|
"privacy": "private",
|
|
4178
|
-
"default": "
|
|
5431
|
+
"default": "null"
|
|
5432
|
+
},
|
|
5433
|
+
{
|
|
5434
|
+
"kind": "field",
|
|
5435
|
+
"name": "_filterPanelTab",
|
|
5436
|
+
"type": {
|
|
5437
|
+
"text": "'filter' | 'counts'"
|
|
5438
|
+
},
|
|
5439
|
+
"privacy": "private",
|
|
5440
|
+
"default": "'filter'"
|
|
5441
|
+
},
|
|
5442
|
+
{
|
|
5443
|
+
"kind": "field",
|
|
5444
|
+
"name": "_buckets",
|
|
5445
|
+
"type": {
|
|
5446
|
+
"text": "Map<string, KRBucket[]>"
|
|
5447
|
+
},
|
|
5448
|
+
"privacy": "private",
|
|
5449
|
+
"default": "new Map()"
|
|
5450
|
+
},
|
|
5451
|
+
{
|
|
5452
|
+
"kind": "field",
|
|
5453
|
+
"name": "_filterPanelPos",
|
|
5454
|
+
"type": {
|
|
5455
|
+
"text": "object"
|
|
5456
|
+
},
|
|
5457
|
+
"privacy": "private",
|
|
5458
|
+
"default": "{ top: 0, left: 0 }"
|
|
4179
5459
|
},
|
|
4180
5460
|
{
|
|
4181
5461
|
"kind": "field",
|
|
@@ -4206,12 +5486,9 @@
|
|
|
4206
5486
|
},
|
|
4207
5487
|
{
|
|
4208
5488
|
"kind": "field",
|
|
4209
|
-
"name": "
|
|
4210
|
-
"type": {
|
|
4211
|
-
"text": "KRTableDef"
|
|
4212
|
-
},
|
|
5489
|
+
"name": "_model",
|
|
4213
5490
|
"privacy": "private",
|
|
4214
|
-
"default": "
|
|
5491
|
+
"default": "new KRTableModel()"
|
|
4215
5492
|
},
|
|
4216
5493
|
{
|
|
4217
5494
|
"kind": "field",
|
|
@@ -4223,135 +5500,428 @@
|
|
|
4223
5500
|
"attribute": "def"
|
|
4224
5501
|
},
|
|
4225
5502
|
{
|
|
4226
|
-
"kind": "method",
|
|
4227
|
-
"name": "_syncSlottedContent",
|
|
4228
|
-
"privacy": "private",
|
|
4229
|
-
"description": "Syncs light DOM content for cells with custom render functions"
|
|
5503
|
+
"kind": "method",
|
|
5504
|
+
"name": "_syncSlottedContent",
|
|
5505
|
+
"privacy": "private",
|
|
5506
|
+
"description": "Syncs light DOM content for cells with custom render functions"
|
|
5507
|
+
},
|
|
5508
|
+
{
|
|
5509
|
+
"kind": "method",
|
|
5510
|
+
"name": "refresh"
|
|
5511
|
+
},
|
|
5512
|
+
{
|
|
5513
|
+
"kind": "method",
|
|
5514
|
+
"name": "goToPrevPage"
|
|
5515
|
+
},
|
|
5516
|
+
{
|
|
5517
|
+
"kind": "method",
|
|
5518
|
+
"name": "goToNextPage"
|
|
5519
|
+
},
|
|
5520
|
+
{
|
|
5521
|
+
"kind": "method",
|
|
5522
|
+
"name": "goToPage",
|
|
5523
|
+
"parameters": [
|
|
5524
|
+
{
|
|
5525
|
+
"name": "page",
|
|
5526
|
+
"type": {
|
|
5527
|
+
"text": "number"
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
]
|
|
5531
|
+
},
|
|
5532
|
+
{
|
|
5533
|
+
"kind": "method",
|
|
5534
|
+
"name": "_toSolrData",
|
|
5535
|
+
"privacy": "private"
|
|
5536
|
+
},
|
|
5537
|
+
{
|
|
5538
|
+
"kind": "method",
|
|
5539
|
+
"name": "_toDbParams",
|
|
5540
|
+
"privacy": "private"
|
|
5541
|
+
},
|
|
5542
|
+
{
|
|
5543
|
+
"kind": "method",
|
|
5544
|
+
"name": "_fetch",
|
|
5545
|
+
"privacy": "private",
|
|
5546
|
+
"description": "Fetches data from the API and updates the table.\nShows a loading spinner while fetching, then displays rows on success\nor an error snackbar on failure.\nRequest/response format depends on dataSource.mode (solr, opensearch, db)."
|
|
5547
|
+
},
|
|
5548
|
+
{
|
|
5549
|
+
"kind": "method",
|
|
5550
|
+
"name": "_parseFacetResults",
|
|
5551
|
+
"privacy": "private",
|
|
5552
|
+
"parameters": [
|
|
5553
|
+
{
|
|
5554
|
+
"name": "response",
|
|
5555
|
+
"type": {
|
|
5556
|
+
"text": "KRSolrResponse"
|
|
5557
|
+
}
|
|
5558
|
+
}
|
|
5559
|
+
]
|
|
5560
|
+
},
|
|
5561
|
+
{
|
|
5562
|
+
"kind": "method",
|
|
5563
|
+
"name": "_initRefresh",
|
|
5564
|
+
"privacy": "private",
|
|
5565
|
+
"description": "Sets up auto-refresh so the table automatically fetches fresh data\nat a regular interval (useful for dashboards, monitoring views).\nConfigured via def.refreshInterval in milliseconds."
|
|
5566
|
+
},
|
|
5567
|
+
{
|
|
5568
|
+
"kind": "method",
|
|
5569
|
+
"name": "_handleSearch",
|
|
5570
|
+
"privacy": "private",
|
|
5571
|
+
"parameters": [
|
|
5572
|
+
{
|
|
5573
|
+
"name": "e",
|
|
5574
|
+
"type": {
|
|
5575
|
+
"text": "Event"
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5578
|
+
]
|
|
5579
|
+
},
|
|
5580
|
+
{
|
|
5581
|
+
"kind": "method",
|
|
5582
|
+
"name": "_getGridTemplateColumns",
|
|
5583
|
+
"privacy": "private",
|
|
5584
|
+
"return": {
|
|
5585
|
+
"type": {
|
|
5586
|
+
"text": "string"
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5589
|
+
},
|
|
5590
|
+
{
|
|
5591
|
+
"kind": "method",
|
|
5592
|
+
"name": "_updateSearchPosition",
|
|
5593
|
+
"privacy": "private",
|
|
5594
|
+
"description": "Updates search position to be centered with equal gaps from title and tools.\nOn first call: resets to flex centering, measures position, then locks with fixed margin.\nSubsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize)."
|
|
5595
|
+
},
|
|
5596
|
+
{
|
|
5597
|
+
"kind": "method",
|
|
5598
|
+
"name": "_toggleColumnPicker",
|
|
5599
|
+
"privacy": "private"
|
|
5600
|
+
},
|
|
5601
|
+
{
|
|
5602
|
+
"kind": "method",
|
|
5603
|
+
"name": "_toggleColumn",
|
|
5604
|
+
"privacy": "private",
|
|
5605
|
+
"parameters": [
|
|
5606
|
+
{
|
|
5607
|
+
"name": "columnId",
|
|
5608
|
+
"type": {
|
|
5609
|
+
"text": "string"
|
|
5610
|
+
}
|
|
5611
|
+
}
|
|
5612
|
+
]
|
|
5613
|
+
},
|
|
5614
|
+
{
|
|
5615
|
+
"kind": "method",
|
|
5616
|
+
"name": "_handleRowMouseDown",
|
|
5617
|
+
"privacy": "private"
|
|
5618
|
+
},
|
|
5619
|
+
{
|
|
5620
|
+
"kind": "method",
|
|
5621
|
+
"name": "_handleRowClick",
|
|
5622
|
+
"privacy": "private",
|
|
5623
|
+
"parameters": [
|
|
5624
|
+
{
|
|
5625
|
+
"name": "row",
|
|
5626
|
+
"type": {
|
|
5627
|
+
"text": "Record<string, any>"
|
|
5628
|
+
}
|
|
5629
|
+
},
|
|
5630
|
+
{
|
|
5631
|
+
"name": "rowIndex",
|
|
5632
|
+
"type": {
|
|
5633
|
+
"text": "number"
|
|
5634
|
+
}
|
|
5635
|
+
}
|
|
5636
|
+
]
|
|
5637
|
+
},
|
|
5638
|
+
{
|
|
5639
|
+
"kind": "field",
|
|
5640
|
+
"name": "_handleClickOutside",
|
|
5641
|
+
"privacy": "private"
|
|
5642
|
+
},
|
|
5643
|
+
{
|
|
5644
|
+
"kind": "method",
|
|
5645
|
+
"name": "getDisplayedColumns",
|
|
5646
|
+
"return": {
|
|
5647
|
+
"type": {
|
|
5648
|
+
"text": "KRTableColumn[]"
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5651
|
+
},
|
|
5652
|
+
{
|
|
5653
|
+
"kind": "method",
|
|
5654
|
+
"name": "_handleScroll",
|
|
5655
|
+
"privacy": "private",
|
|
5656
|
+
"parameters": [
|
|
5657
|
+
{
|
|
5658
|
+
"name": "e",
|
|
5659
|
+
"type": {
|
|
5660
|
+
"text": "Event"
|
|
5661
|
+
}
|
|
5662
|
+
}
|
|
5663
|
+
],
|
|
5664
|
+
"description": "Scroll event handler that updates scroll flags in real-time as user scrolls.\nUpdates shadow indicators to show if more content exists left/right."
|
|
5665
|
+
},
|
|
5666
|
+
{
|
|
5667
|
+
"kind": "method",
|
|
5668
|
+
"name": "_updateScrollFlags",
|
|
5669
|
+
"privacy": "private",
|
|
5670
|
+
"description": "Updates scroll state flags for the table content container.\n- _canScrollLeft: true if scrolled right (can scroll back left)\n- _canScrollRight: true if more content exists to the right\n- _canScrollHorizontal: true if content is wider than container\nThese flags control scroll shadow indicators and CSS classes."
|
|
5671
|
+
},
|
|
5672
|
+
{
|
|
5673
|
+
"kind": "method",
|
|
5674
|
+
"name": "_handleResizeStart",
|
|
5675
|
+
"privacy": "private",
|
|
5676
|
+
"parameters": [
|
|
5677
|
+
{
|
|
5678
|
+
"name": "e",
|
|
5679
|
+
"type": {
|
|
5680
|
+
"text": "MouseEvent"
|
|
5681
|
+
}
|
|
5682
|
+
},
|
|
5683
|
+
{
|
|
5684
|
+
"name": "columnId",
|
|
5685
|
+
"type": {
|
|
5686
|
+
"text": "string"
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
]
|
|
5690
|
+
},
|
|
5691
|
+
{
|
|
5692
|
+
"kind": "field",
|
|
5693
|
+
"name": "_handleResizeMove",
|
|
5694
|
+
"privacy": "private"
|
|
4230
5695
|
},
|
|
4231
5696
|
{
|
|
4232
|
-
"kind": "
|
|
4233
|
-
"name": "
|
|
5697
|
+
"kind": "field",
|
|
5698
|
+
"name": "_handleResizeEnd",
|
|
5699
|
+
"privacy": "private"
|
|
4234
5700
|
},
|
|
4235
5701
|
{
|
|
4236
5702
|
"kind": "method",
|
|
4237
|
-
"name": "
|
|
5703
|
+
"name": "_handleAction",
|
|
5704
|
+
"privacy": "private",
|
|
5705
|
+
"parameters": [
|
|
5706
|
+
{
|
|
5707
|
+
"name": "action",
|
|
5708
|
+
"type": {
|
|
5709
|
+
"text": "KRTableAction"
|
|
5710
|
+
}
|
|
5711
|
+
}
|
|
5712
|
+
]
|
|
4238
5713
|
},
|
|
4239
5714
|
{
|
|
4240
5715
|
"kind": "method",
|
|
4241
|
-
"name": "
|
|
5716
|
+
"name": "_handleKqlChange",
|
|
5717
|
+
"privacy": "private",
|
|
5718
|
+
"parameters": [
|
|
5719
|
+
{
|
|
5720
|
+
"name": "e",
|
|
5721
|
+
"type": {
|
|
5722
|
+
"text": "Event"
|
|
5723
|
+
}
|
|
5724
|
+
},
|
|
5725
|
+
{
|
|
5726
|
+
"name": "column",
|
|
5727
|
+
"type": {
|
|
5728
|
+
"text": "KRTableColumn"
|
|
5729
|
+
}
|
|
5730
|
+
}
|
|
5731
|
+
]
|
|
4242
5732
|
},
|
|
4243
5733
|
{
|
|
4244
5734
|
"kind": "method",
|
|
4245
|
-
"name": "
|
|
5735
|
+
"name": "_handleFilterPanelToggle",
|
|
5736
|
+
"privacy": "private",
|
|
4246
5737
|
"parameters": [
|
|
4247
5738
|
{
|
|
4248
|
-
"name": "
|
|
5739
|
+
"name": "e",
|
|
4249
5740
|
"type": {
|
|
4250
|
-
"text": "
|
|
5741
|
+
"text": "Event"
|
|
5742
|
+
}
|
|
5743
|
+
},
|
|
5744
|
+
{
|
|
5745
|
+
"name": "column",
|
|
5746
|
+
"type": {
|
|
5747
|
+
"text": "KRTableColumn"
|
|
4251
5748
|
}
|
|
4252
5749
|
}
|
|
4253
5750
|
]
|
|
4254
5751
|
},
|
|
4255
5752
|
{
|
|
4256
5753
|
"kind": "method",
|
|
4257
|
-
"name": "
|
|
5754
|
+
"name": "_handleKqlClear",
|
|
4258
5755
|
"privacy": "private",
|
|
4259
|
-
"
|
|
5756
|
+
"parameters": [
|
|
5757
|
+
{
|
|
5758
|
+
"name": "column",
|
|
5759
|
+
"type": {
|
|
5760
|
+
"text": "KRTableColumn"
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
]
|
|
4260
5764
|
},
|
|
4261
5765
|
{
|
|
4262
5766
|
"kind": "method",
|
|
4263
|
-
"name": "
|
|
4264
|
-
"privacy": "private"
|
|
4265
|
-
"description": "Sets up auto-refresh so the table automatically fetches fresh data\nat a regular interval (useful for dashboards, monitoring views).\nConfigured via def.refreshInterval in milliseconds."
|
|
5767
|
+
"name": "_handleFilterClear",
|
|
5768
|
+
"privacy": "private"
|
|
4266
5769
|
},
|
|
4267
5770
|
{
|
|
4268
5771
|
"kind": "method",
|
|
4269
|
-
"name": "
|
|
5772
|
+
"name": "_handleFilterTextKeydown",
|
|
4270
5773
|
"privacy": "private",
|
|
4271
5774
|
"parameters": [
|
|
4272
5775
|
{
|
|
4273
5776
|
"name": "e",
|
|
4274
5777
|
"type": {
|
|
4275
|
-
"text": "
|
|
5778
|
+
"text": "KeyboardEvent"
|
|
5779
|
+
}
|
|
5780
|
+
},
|
|
5781
|
+
{
|
|
5782
|
+
"name": "column",
|
|
5783
|
+
"type": {
|
|
5784
|
+
"text": "KRTableColumn"
|
|
4276
5785
|
}
|
|
4277
5786
|
}
|
|
4278
5787
|
]
|
|
4279
5788
|
},
|
|
4280
5789
|
{
|
|
4281
5790
|
"kind": "method",
|
|
4282
|
-
"name": "
|
|
5791
|
+
"name": "_handleOperatorChange",
|
|
4283
5792
|
"privacy": "private",
|
|
4284
|
-
"
|
|
4285
|
-
|
|
4286
|
-
"
|
|
5793
|
+
"parameters": [
|
|
5794
|
+
{
|
|
5795
|
+
"name": "e",
|
|
5796
|
+
"type": {
|
|
5797
|
+
"text": "Event"
|
|
5798
|
+
}
|
|
5799
|
+
},
|
|
5800
|
+
{
|
|
5801
|
+
"name": "column",
|
|
5802
|
+
"type": {
|
|
5803
|
+
"text": "KRTableColumn"
|
|
5804
|
+
}
|
|
4287
5805
|
}
|
|
4288
|
-
|
|
5806
|
+
]
|
|
4289
5807
|
},
|
|
4290
5808
|
{
|
|
4291
5809
|
"kind": "method",
|
|
4292
|
-
"name": "
|
|
5810
|
+
"name": "_handleFilterStringChange",
|
|
4293
5811
|
"privacy": "private",
|
|
4294
|
-
"
|
|
5812
|
+
"parameters": [
|
|
5813
|
+
{
|
|
5814
|
+
"name": "e",
|
|
5815
|
+
"type": {
|
|
5816
|
+
"text": "Event"
|
|
5817
|
+
}
|
|
5818
|
+
},
|
|
5819
|
+
{
|
|
5820
|
+
"name": "column",
|
|
5821
|
+
"type": {
|
|
5822
|
+
"text": "KRTableColumn"
|
|
5823
|
+
}
|
|
5824
|
+
}
|
|
5825
|
+
]
|
|
4295
5826
|
},
|
|
4296
5827
|
{
|
|
4297
5828
|
"kind": "method",
|
|
4298
|
-
"name": "
|
|
4299
|
-
"privacy": "private"
|
|
5829
|
+
"name": "_handleFilterNumberChange",
|
|
5830
|
+
"privacy": "private",
|
|
5831
|
+
"parameters": [
|
|
5832
|
+
{
|
|
5833
|
+
"name": "e",
|
|
5834
|
+
"type": {
|
|
5835
|
+
"text": "Event"
|
|
5836
|
+
}
|
|
5837
|
+
},
|
|
5838
|
+
{
|
|
5839
|
+
"name": "column",
|
|
5840
|
+
"type": {
|
|
5841
|
+
"text": "KRTableColumn"
|
|
5842
|
+
}
|
|
5843
|
+
}
|
|
5844
|
+
]
|
|
4300
5845
|
},
|
|
4301
5846
|
{
|
|
4302
5847
|
"kind": "method",
|
|
4303
|
-
"name": "
|
|
5848
|
+
"name": "_handleFilterDateChange",
|
|
4304
5849
|
"privacy": "private",
|
|
4305
5850
|
"parameters": [
|
|
4306
5851
|
{
|
|
4307
|
-
"name": "
|
|
5852
|
+
"name": "e",
|
|
4308
5853
|
"type": {
|
|
4309
|
-
"text": "
|
|
5854
|
+
"text": "Event"
|
|
5855
|
+
}
|
|
5856
|
+
},
|
|
5857
|
+
{
|
|
5858
|
+
"name": "column",
|
|
5859
|
+
"type": {
|
|
5860
|
+
"text": "KRTableColumn"
|
|
4310
5861
|
}
|
|
4311
5862
|
}
|
|
4312
5863
|
]
|
|
4313
5864
|
},
|
|
4314
5865
|
{
|
|
4315
5866
|
"kind": "method",
|
|
4316
|
-
"name": "
|
|
4317
|
-
"privacy": "private"
|
|
5867
|
+
"name": "_handleFilterBooleanChange",
|
|
5868
|
+
"privacy": "private",
|
|
5869
|
+
"parameters": [
|
|
5870
|
+
{
|
|
5871
|
+
"name": "e",
|
|
5872
|
+
"type": {
|
|
5873
|
+
"text": "Event"
|
|
5874
|
+
}
|
|
5875
|
+
},
|
|
5876
|
+
{
|
|
5877
|
+
"name": "column",
|
|
5878
|
+
"type": {
|
|
5879
|
+
"text": "KRTableColumn"
|
|
5880
|
+
}
|
|
5881
|
+
}
|
|
5882
|
+
]
|
|
4318
5883
|
},
|
|
4319
5884
|
{
|
|
4320
5885
|
"kind": "method",
|
|
4321
|
-
"name": "
|
|
5886
|
+
"name": "_handleFilterDateStartChange",
|
|
4322
5887
|
"privacy": "private",
|
|
4323
5888
|
"parameters": [
|
|
4324
5889
|
{
|
|
4325
|
-
"name": "
|
|
5890
|
+
"name": "e",
|
|
4326
5891
|
"type": {
|
|
4327
|
-
"text": "
|
|
5892
|
+
"text": "Event"
|
|
4328
5893
|
}
|
|
4329
5894
|
},
|
|
4330
5895
|
{
|
|
4331
|
-
"name": "
|
|
5896
|
+
"name": "column",
|
|
4332
5897
|
"type": {
|
|
4333
|
-
"text": "
|
|
5898
|
+
"text": "KRTableColumn"
|
|
4334
5899
|
}
|
|
4335
5900
|
}
|
|
4336
5901
|
]
|
|
4337
5902
|
},
|
|
4338
|
-
{
|
|
4339
|
-
"kind": "field",
|
|
4340
|
-
"name": "_handleClickOutsideColumnPicker",
|
|
4341
|
-
"privacy": "private"
|
|
4342
|
-
},
|
|
4343
5903
|
{
|
|
4344
5904
|
"kind": "method",
|
|
4345
|
-
"name": "
|
|
4346
|
-
"
|
|
4347
|
-
|
|
4348
|
-
|
|
5905
|
+
"name": "_handleFilterDateEndChange",
|
|
5906
|
+
"privacy": "private",
|
|
5907
|
+
"parameters": [
|
|
5908
|
+
{
|
|
5909
|
+
"name": "e",
|
|
5910
|
+
"type": {
|
|
5911
|
+
"text": "Event"
|
|
5912
|
+
}
|
|
5913
|
+
},
|
|
5914
|
+
{
|
|
5915
|
+
"name": "column",
|
|
5916
|
+
"type": {
|
|
5917
|
+
"text": "KRTableColumn"
|
|
5918
|
+
}
|
|
4349
5919
|
}
|
|
4350
|
-
|
|
5920
|
+
]
|
|
4351
5921
|
},
|
|
4352
5922
|
{
|
|
4353
5923
|
"kind": "method",
|
|
4354
|
-
"name": "
|
|
5924
|
+
"name": "_handleFilterNumberStartChange",
|
|
4355
5925
|
"privacy": "private",
|
|
4356
5926
|
"parameters": [
|
|
4357
5927
|
{
|
|
@@ -4359,54 +5929,92 @@
|
|
|
4359
5929
|
"type": {
|
|
4360
5930
|
"text": "Event"
|
|
4361
5931
|
}
|
|
5932
|
+
},
|
|
5933
|
+
{
|
|
5934
|
+
"name": "column",
|
|
5935
|
+
"type": {
|
|
5936
|
+
"text": "KRTableColumn"
|
|
5937
|
+
}
|
|
4362
5938
|
}
|
|
4363
|
-
]
|
|
4364
|
-
"description": "Scroll event handler that updates scroll flags in real-time as user scrolls.\nUpdates shadow indicators to show if more content exists left/right."
|
|
5939
|
+
]
|
|
4365
5940
|
},
|
|
4366
5941
|
{
|
|
4367
5942
|
"kind": "method",
|
|
4368
|
-
"name": "
|
|
5943
|
+
"name": "_handleFilterNumberEndChange",
|
|
4369
5944
|
"privacy": "private",
|
|
4370
|
-
"
|
|
5945
|
+
"parameters": [
|
|
5946
|
+
{
|
|
5947
|
+
"name": "e",
|
|
5948
|
+
"type": {
|
|
5949
|
+
"text": "Event"
|
|
5950
|
+
}
|
|
5951
|
+
},
|
|
5952
|
+
{
|
|
5953
|
+
"name": "column",
|
|
5954
|
+
"type": {
|
|
5955
|
+
"text": "KRTableColumn"
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
]
|
|
4371
5959
|
},
|
|
4372
5960
|
{
|
|
4373
5961
|
"kind": "method",
|
|
4374
|
-
"name": "
|
|
5962
|
+
"name": "_handleFilterListChange",
|
|
4375
5963
|
"privacy": "private",
|
|
4376
5964
|
"parameters": [
|
|
4377
5965
|
{
|
|
4378
5966
|
"name": "e",
|
|
4379
5967
|
"type": {
|
|
4380
|
-
"text": "
|
|
5968
|
+
"text": "Event"
|
|
4381
5969
|
}
|
|
4382
5970
|
},
|
|
4383
5971
|
{
|
|
4384
|
-
"name": "
|
|
5972
|
+
"name": "column",
|
|
4385
5973
|
"type": {
|
|
4386
|
-
"text": "
|
|
5974
|
+
"text": "KRTableColumn"
|
|
4387
5975
|
}
|
|
4388
5976
|
}
|
|
4389
5977
|
]
|
|
4390
5978
|
},
|
|
4391
5979
|
{
|
|
4392
|
-
"kind": "
|
|
4393
|
-
"name": "
|
|
5980
|
+
"kind": "method",
|
|
5981
|
+
"name": "_handleFilterApply",
|
|
4394
5982
|
"privacy": "private"
|
|
4395
5983
|
},
|
|
4396
5984
|
{
|
|
4397
|
-
"kind": "
|
|
4398
|
-
"name": "
|
|
4399
|
-
"privacy": "private"
|
|
5985
|
+
"kind": "method",
|
|
5986
|
+
"name": "_handleFilterPanelTabChange",
|
|
5987
|
+
"privacy": "private",
|
|
5988
|
+
"parameters": [
|
|
5989
|
+
{
|
|
5990
|
+
"name": "e",
|
|
5991
|
+
"type": {
|
|
5992
|
+
"text": "CustomEvent"
|
|
5993
|
+
}
|
|
5994
|
+
}
|
|
5995
|
+
]
|
|
4400
5996
|
},
|
|
4401
5997
|
{
|
|
4402
5998
|
"kind": "method",
|
|
4403
|
-
"name": "
|
|
5999
|
+
"name": "_handleBucketToggle",
|
|
4404
6000
|
"privacy": "private",
|
|
4405
6001
|
"parameters": [
|
|
4406
6002
|
{
|
|
4407
|
-
"name": "
|
|
6003
|
+
"name": "e",
|
|
4408
6004
|
"type": {
|
|
4409
|
-
"text": "
|
|
6005
|
+
"text": "Event"
|
|
6006
|
+
}
|
|
6007
|
+
},
|
|
6008
|
+
{
|
|
6009
|
+
"name": "column",
|
|
6010
|
+
"type": {
|
|
6011
|
+
"text": "KRTableColumn"
|
|
6012
|
+
}
|
|
6013
|
+
},
|
|
6014
|
+
{
|
|
6015
|
+
"name": "bucket",
|
|
6016
|
+
"type": {
|
|
6017
|
+
"text": "KRBucket"
|
|
4410
6018
|
}
|
|
4411
6019
|
}
|
|
4412
6020
|
]
|
|
@@ -4529,6 +6137,17 @@
|
|
|
4529
6137
|
"privacy": "private",
|
|
4530
6138
|
"description": "Renders status message (loading, error, empty)"
|
|
4531
6139
|
},
|
|
6140
|
+
{
|
|
6141
|
+
"kind": "method",
|
|
6142
|
+
"name": "_renderFilterPanel",
|
|
6143
|
+
"privacy": "private"
|
|
6144
|
+
},
|
|
6145
|
+
{
|
|
6146
|
+
"kind": "method",
|
|
6147
|
+
"name": "_renderFilterRow",
|
|
6148
|
+
"privacy": "private",
|
|
6149
|
+
"description": "Renders filter row below column headers.\nOnly displays for columns with filterable: true."
|
|
6150
|
+
},
|
|
4532
6151
|
{
|
|
4533
6152
|
"kind": "method",
|
|
4534
6153
|
"name": "_renderTable",
|