mirror of https://github.com/rancher/ui.git
Merge pull request #3340 from loganhz/apps
Support search in apps and multi-cluster apps list page
This commit is contained in:
commit
51a52fd8ae
|
|
@ -4,6 +4,7 @@ import Controller, { inject as controller } from '@ember/controller';
|
||||||
import C from 'ui/utils/constants';
|
import C from 'ui/utils/constants';
|
||||||
import { computed, get, observer } from '@ember/object';
|
import { computed, get, observer } from '@ember/object';
|
||||||
import { once } from '@ember/runloop';
|
import { once } from '@ember/runloop';
|
||||||
|
import { filter } from 'ui/utils/search-text';
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
prefs: service(),
|
prefs: service(),
|
||||||
|
|
@ -18,7 +19,7 @@ export default Controller.extend({
|
||||||
once(() => this.get('catalog').fetchAppTemplates(get(this, 'model.apps')));
|
once(() => this.get('catalog').fetchAppTemplates(get(this, 'model.apps')));
|
||||||
}),
|
}),
|
||||||
|
|
||||||
filteredApps: computed('model.apps.@each.{type,isFromCatalog,tags,state}', 'tags', function() {
|
filteredApps: computed('model.apps.@each.{type,isFromCatalog,tags,state}', 'tags', 'searchText', function() {
|
||||||
var needTags = get(this, 'tags');
|
var needTags = get(this, 'tags');
|
||||||
|
|
||||||
var apps = get(this, 'model.apps').filter((ns) => !C.REMOVEDISH_STATES.includes(get(ns, 'state')));
|
var apps = get(this, 'model.apps').filter((ns) => !C.REMOVEDISH_STATES.includes(get(ns, 'state')));
|
||||||
|
|
@ -30,6 +31,8 @@ export default Controller.extend({
|
||||||
apps = apps.filterBy('isIstio', false);
|
apps = apps.filterBy('isIstio', false);
|
||||||
apps = apps.sortBy('displayName');
|
apps = apps.sortBy('displayName');
|
||||||
|
|
||||||
|
apps = filter(apps, get(this, 'searchText'));
|
||||||
|
|
||||||
const group = [];
|
const group = [];
|
||||||
let dataIndex = 0;
|
let dataIndex = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="pl-0 pr-0">
|
<section class="pl-0 pr-0">
|
||||||
|
<div class="row mb-15">
|
||||||
|
{{search-text searchText=searchText}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#each filteredApps as |group|}}
|
{{#each filteredApps as |group|}}
|
||||||
<div class="row flex">
|
<div class="row flex">
|
||||||
{{#each group as |ns|}}
|
{{#each group as |ns|}}
|
||||||
|
|
@ -18,7 +22,11 @@
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="text-center text-muted">
|
<div class="text-center text-muted">
|
||||||
{{t 'nav.apps.noData'}}
|
{{#if searchText}}
|
||||||
|
{{t "nav.apps.noMatch"}}
|
||||||
|
{{else}}
|
||||||
|
{{t "nav.apps.noData"}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -2,7 +2,7 @@ import Component from '@ember/component';
|
||||||
import layout from './template';
|
import layout from './template';
|
||||||
import { inject as service } from '@ember/service';
|
import { inject as service } from '@ember/service';
|
||||||
import { get, computed } from '@ember/object';
|
import { get, computed } from '@ember/object';
|
||||||
import { matches } from 'shared/components/sortable-table/component';
|
import { filter } from 'ui/utils/search-text';
|
||||||
|
|
||||||
const headers = [
|
const headers = [
|
||||||
{
|
{
|
||||||
|
|
@ -45,40 +45,6 @@ export default Component.extend({
|
||||||
],
|
],
|
||||||
|
|
||||||
projectsWithoutNamespace: computed('projectsWithoutNamespaces.[]', 'searchText', function() {
|
projectsWithoutNamespace: computed('projectsWithoutNamespaces.[]', 'searchText', function() {
|
||||||
let searchText = (get(this, 'searchText') || '').trim().toLowerCase();
|
return filter(get(this, 'projectsWithoutNamespaces').slice(), get(this, 'searchText'), ['displayName']);
|
||||||
let out = get(this, 'projectsWithoutNamespaces').slice();
|
|
||||||
let searchFields = ['displayName'];
|
|
||||||
|
|
||||||
if ( searchText.length ) {
|
|
||||||
let searchTokens = searchText.split(/\s*[, ]\s*/);
|
|
||||||
|
|
||||||
for ( let i = out.length - 1 ; i >= 0 ; i-- ) {
|
|
||||||
let hits = 0;
|
|
||||||
let row = out[i];
|
|
||||||
let mainFound = true;
|
|
||||||
|
|
||||||
for ( let j = 0 ; j < searchTokens.length ; j++ ) {
|
|
||||||
let expect = true;
|
|
||||||
let token = searchTokens[j];
|
|
||||||
|
|
||||||
if ( token.substr(0, 1) === '!' ) {
|
|
||||||
expect = false;
|
|
||||||
token = token.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( token && matches(searchFields, token, row) !== expect ) {
|
|
||||||
mainFound = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !mainFound && hits === 0 ) {
|
|
||||||
out.removeAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { computed, observer } from '@ember/object';
|
import { get, computed, observer } from '@ember/object';
|
||||||
import { alias } from '@ember/object/computed';
|
import { alias } from '@ember/object/computed';
|
||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import pagedArray from 'ember-cli-pagination/computed/paged-array';
|
import pagedArray from 'ember-cli-pagination/computed/paged-array';
|
||||||
import { matches } from 'shared/components/sortable-table/component';
|
import { filter } from 'ui/utils/search-text';
|
||||||
import layout from './template';
|
import layout from './template';
|
||||||
|
|
||||||
export const searchFields = ['displayName', 'id:prefix', 'displayState', 'image', 'displayIp:ip'];
|
export const searchFields = ['displayName', 'id:prefix', 'displayState', 'image', 'displayIp:ip'];
|
||||||
|
|
@ -48,33 +48,7 @@ export default Component.extend({
|
||||||
out.pushObject(pod);
|
out.pushObject(pod);
|
||||||
}
|
}
|
||||||
|
|
||||||
let searchFields = this.get('searchFields');
|
return filter(out, get(this, 'searchText'), get(this, 'searchFields'));
|
||||||
let searchText = (this.get('searchText') || '').trim().toLowerCase();
|
|
||||||
|
|
||||||
if ( searchText.length ) {
|
|
||||||
let searchTokens = searchText.split(/\s*[, ]\s*/);
|
|
||||||
|
|
||||||
for ( let i = out.length - 1 ; i >= 0 ; i-- ) {
|
|
||||||
let row = out[i].containers[0];
|
|
||||||
|
|
||||||
for ( let j = 0 ; j < searchTokens.length ; j++ ) {
|
|
||||||
let expect = true;
|
|
||||||
let token = searchTokens[j];
|
|
||||||
|
|
||||||
if ( token.substr(0, 1) === '!' ) {
|
|
||||||
expect = false;
|
|
||||||
token = token.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( token && matches(searchFields, token, row) !== expect ) {
|
|
||||||
out.removeAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
pagedContent: pagedArray('filtered', {
|
pagedContent: pagedArray('filtered', {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import Controller from '@ember/controller';
|
||||||
import C from 'ui/utils/constants';
|
import C from 'ui/utils/constants';
|
||||||
import { computed, get, observer } from '@ember/object';
|
import { computed, get, observer } from '@ember/object';
|
||||||
import { once } from '@ember/runloop';
|
import { once } from '@ember/runloop';
|
||||||
|
import { filter } from 'ui/utils/search-text';
|
||||||
|
|
||||||
export default Controller.extend({
|
export default Controller.extend({
|
||||||
prefs: service(),
|
prefs: service(),
|
||||||
|
|
@ -14,10 +15,11 @@ export default Controller.extend({
|
||||||
once(() => this.get('catalog').fetchAppTemplates(get(this, 'model.apps')));
|
once(() => this.get('catalog').fetchAppTemplates(get(this, 'model.apps')));
|
||||||
}),
|
}),
|
||||||
|
|
||||||
filteredApps: computed('model.apps.@each.{type,isFromCatalog,state}', function() {
|
filteredApps: computed('model.apps.@each.{type,isFromCatalog,state}', 'searchText', function() {
|
||||||
let apps = get(this, 'model.apps').filter((ns) => !C.REMOVEDISH_STATES.includes(get(ns, 'state')));
|
let apps = get(this, 'model.apps').filter((ns) => !C.REMOVEDISH_STATES.includes(get(ns, 'state')));
|
||||||
|
|
||||||
apps = apps.sortBy('displayName');
|
apps = apps.sortBy('displayName');
|
||||||
|
apps = filter(apps, get(this, 'searchText'));
|
||||||
|
|
||||||
const group = [];
|
const group = [];
|
||||||
let dataIndex = 0;
|
let dataIndex = 0;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="pl-0 pr-0">
|
<section class="pl-0 pr-0">
|
||||||
|
<div class="row mb-15">
|
||||||
|
{{search-text searchText=searchText}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#each filteredApps as |group|}}
|
{{#each filteredApps as |group|}}
|
||||||
<div class="row flex">
|
<div class="row flex">
|
||||||
{{#each group as |app|}}
|
{{#each group as |app|}}
|
||||||
|
|
@ -31,7 +35,11 @@
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="text-center text-muted">
|
<div class="text-center text-muted">
|
||||||
{{t 'multiClusterAppsPage.noData'}}
|
{{#if searchText}}
|
||||||
|
{{t "multiClusterAppsPage.noMatch"}}
|
||||||
|
{{else}}
|
||||||
|
{{t "multiClusterAppsPage.noData"}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import Component from '@ember/component';
|
||||||
|
import { set } from '@ember/object';
|
||||||
|
import layout from './template';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
layout,
|
||||||
|
searchFields: ['displayName', 'id:prefix', 'displayState'],
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
clearSearch() {
|
||||||
|
set(this, 'searchText', '');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="pull-right search-group input-group">
|
||||||
|
{{input
|
||||||
|
value=searchText
|
||||||
|
aria-title=(t "generic.search")
|
||||||
|
type="search" class="input-sm pull-right"
|
||||||
|
placeholder=(t "generic.search")
|
||||||
|
}}
|
||||||
|
{{#if searchText}}
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button
|
||||||
|
class="btn bg-transparent text-info pl-10 pr-10" {{action "clearSearch"}}
|
||||||
|
>
|
||||||
|
<i class="icon icon-close"/>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
@ -11,6 +11,7 @@ import { isArray } from '@ember/array';
|
||||||
import { observer } from '@ember/object'
|
import { observer } from '@ember/object'
|
||||||
import { run } from '@ember/runloop';
|
import { run } from '@ember/runloop';
|
||||||
import { isAlternate, isMore, isRange } from 'shared/utils/platform';
|
import { isAlternate, isMore, isRange } from 'shared/utils/platform';
|
||||||
|
import { filter } from 'ui/utils/search-text';
|
||||||
|
|
||||||
function toggleInput(node, on) {
|
function toggleInput(node, on) {
|
||||||
let id = get(node, 'id');
|
let id = get(node, 'id');
|
||||||
|
|
@ -34,70 +35,6 @@ function toggleInput(node, on) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function matches(fields, token, item) {
|
|
||||||
let tokenMayBeIp = /^[0-9a-f\.:]+$/i.test(token);
|
|
||||||
|
|
||||||
for ( let i = 0 ; i < fields.length ; i++ ) {
|
|
||||||
let field = fields[i];
|
|
||||||
|
|
||||||
if ( field ) {
|
|
||||||
// Modifiers:
|
|
||||||
// id: The token must match id format (i.e. 1i123)
|
|
||||||
let idx = field.indexOf(':');
|
|
||||||
let modifier = null;
|
|
||||||
|
|
||||||
if ( idx > 0 ) {
|
|
||||||
modifier = field.substr(idx + 1);
|
|
||||||
field = field.substr(0, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
let val = get(item, field);
|
|
||||||
|
|
||||||
if ( val === undefined ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
val = (`${ val }`).toLowerCase();
|
|
||||||
if ( !val ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ( modifier ) {
|
|
||||||
case 'exact':
|
|
||||||
if ( val === token ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'ip':
|
|
||||||
if ( tokenMayBeIp ) {
|
|
||||||
let re = new RegExp(`(?:^|\.)${ token }(?:\.|$)`);
|
|
||||||
|
|
||||||
if ( re.test(val) ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'prefix':
|
|
||||||
if ( val.indexOf(token) === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ( val.indexOf(token) >= 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Component.extend(Sortable, StickyHeader, {
|
export default Component.extend(Sortable, StickyHeader, {
|
||||||
prefs: service(),
|
prefs: service(),
|
||||||
intl: service(),
|
intl: service(),
|
||||||
|
|
@ -446,78 +383,17 @@ export default Component.extend(Sortable, StickyHeader, {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
filtered: computed('arranged.[]', 'searchText', function() {
|
filtered: computed('arranged.[]', 'searchText', function() {
|
||||||
let out = get(this, 'arranged').slice();
|
const { matches, subMatches } = filter(
|
||||||
let searchFields = get(this, 'searchFields');
|
get(this, 'arranged').slice(),
|
||||||
let searchText = (get(this, 'searchText') || '').trim().toLowerCase();
|
get(this, 'searchText'),
|
||||||
let subSearchField = get(this, 'subSearchField');
|
get(this, 'searchFields'),
|
||||||
let subFields = get(this, 'subFields');
|
get(this, 'subFields'),
|
||||||
let subMatches = null;
|
get(this, 'subSearchField')
|
||||||
|
);
|
||||||
if ( searchText.length ) {
|
|
||||||
subMatches = {};
|
|
||||||
|
|
||||||
let searchTokens = searchText.split(/\s*[, ]\s*/);
|
|
||||||
|
|
||||||
for ( let i = out.length - 1 ; i >= 0 ; i-- ) {
|
|
||||||
let hits = 0;
|
|
||||||
let row = out[i];
|
|
||||||
let mainFound = true;
|
|
||||||
|
|
||||||
for ( let j = 0 ; j < searchTokens.length ; j++ ) {
|
|
||||||
let expect = true;
|
|
||||||
let token = searchTokens[j];
|
|
||||||
|
|
||||||
if ( token.substr(0, 1) === '!' ) {
|
|
||||||
expect = false;
|
|
||||||
token = token.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( token && matches(searchFields, token, row) !== expect ) {
|
|
||||||
mainFound = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( subFields && subSearchField) {
|
|
||||||
let subRows = (row.get(subSearchField) || []);
|
|
||||||
|
|
||||||
for ( let k = subRows.length - 1 ; k >= 0 ; k-- ) {
|
|
||||||
let subFound = true;
|
|
||||||
|
|
||||||
for ( let l = 0 ; l < searchTokens.length ; l++ ) {
|
|
||||||
let expect = true;
|
|
||||||
let token = searchTokens[l];
|
|
||||||
|
|
||||||
if ( token.substr(0, 1) === '!' ) {
|
|
||||||
expect = false;
|
|
||||||
token = token.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( matches(subFields, token, subRows[k]) !== expect ) {
|
|
||||||
subFound = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( subFound ) {
|
|
||||||
hits++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subMatches[row.get('id')] = hits;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !mainFound && hits === 0 ) {
|
|
||||||
out.removeAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set(this, 'subMatches', subMatches);
|
set(this, 'subMatches', subMatches);
|
||||||
|
|
||||||
return out;
|
return matches;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
indexFrom: computed('page', 'perPage', function() {
|
indexFrom: computed('page', 'perPage', function() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
import { get } from '@ember/object';
|
||||||
|
|
||||||
|
const SEARCH_FIELDS = ['displayName', 'id:prefix', 'displayState'];
|
||||||
|
|
||||||
|
export function matches(fields, token, item) {
|
||||||
|
let tokenMayBeIp = /^[0-9a-f\.:]+$/i.test(token);
|
||||||
|
|
||||||
|
for ( let i = 0 ; i < fields.length ; i++ ) {
|
||||||
|
let field = fields[i];
|
||||||
|
|
||||||
|
if ( field ) {
|
||||||
|
// Modifiers:
|
||||||
|
// id: The token must match id format (i.e. 1i123)
|
||||||
|
let idx = field.indexOf(':');
|
||||||
|
let modifier = null;
|
||||||
|
|
||||||
|
if ( idx > 0 ) {
|
||||||
|
modifier = field.substr(idx + 1);
|
||||||
|
field = field.substr(0, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
let val = get(item, field);
|
||||||
|
|
||||||
|
if ( val === undefined ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = (`${ val }`).toLowerCase();
|
||||||
|
if ( !val ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( modifier ) {
|
||||||
|
case 'exact':
|
||||||
|
if ( val === token ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'ip':
|
||||||
|
if ( tokenMayBeIp ) {
|
||||||
|
let re = new RegExp(`(?:^|\.)${ token }(?:\.|$)`);
|
||||||
|
|
||||||
|
if ( re.test(val) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'prefix':
|
||||||
|
if ( val.indexOf(token) === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ( val.indexOf(token) >= 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function filter(out, searchText, searchFields = SEARCH_FIELDS, subFields, subSearchField) {
|
||||||
|
let subMatches = null;
|
||||||
|
|
||||||
|
searchText = (searchText || '').trim().toLowerCase();
|
||||||
|
|
||||||
|
if ( searchText.length ) {
|
||||||
|
subMatches = {};
|
||||||
|
|
||||||
|
let searchTokens = searchText.split(/\s*[, ]\s*/);
|
||||||
|
|
||||||
|
for ( let i = out.length - 1 ; i >= 0 ; i-- ) {
|
||||||
|
let row = out[i];
|
||||||
|
let hits = 0;
|
||||||
|
let mainFound = true;
|
||||||
|
|
||||||
|
for ( let j = 0 ; j < searchTokens.length ; j++ ) {
|
||||||
|
let expect = true;
|
||||||
|
let token = searchTokens[j];
|
||||||
|
|
||||||
|
if ( token.substr(0, 1) === '!' ) {
|
||||||
|
expect = false;
|
||||||
|
token = token.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( token && matches(searchFields, token, row) !== expect ) {
|
||||||
|
mainFound = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( subFields && subSearchField ) {
|
||||||
|
let subRows = (row.get(subSearchField) || []);
|
||||||
|
|
||||||
|
for ( let k = subRows.length - 1 ; k >= 0 ; k-- ) {
|
||||||
|
let subFound = true;
|
||||||
|
|
||||||
|
for ( let l = 0 ; l < searchTokens.length ; l++ ) {
|
||||||
|
let expect = true;
|
||||||
|
let token = searchTokens[l];
|
||||||
|
|
||||||
|
if ( token.substr(0, 1) === '!' ) {
|
||||||
|
expect = false;
|
||||||
|
token = token.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( matches(subFields, token, subRows[k]) !== expect ) {
|
||||||
|
subFound = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( subFound ) {
|
||||||
|
hits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subMatches[row.get('id')] = hits;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !mainFound && hits === 0 ) {
|
||||||
|
out.removeAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( subFields && subSearchField ) {
|
||||||
|
return {
|
||||||
|
matches: out,
|
||||||
|
subMatches
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export { default } from 'shared/components/search-text/component';
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
export { filter } from 'shared/utils/search-text';
|
||||||
|
|
@ -1573,6 +1573,7 @@ globalDnsPage:
|
||||||
multiClusterAppsPage:
|
multiClusterAppsPage:
|
||||||
header: Multi-Cluster Apps
|
header: Multi-Cluster Apps
|
||||||
noData: There are no multi-cluster apps launched
|
noData: There are no multi-cluster apps launched
|
||||||
|
noMatch: No multi-cluster apps match the current search
|
||||||
error:
|
error:
|
||||||
appData: Error loading global app data
|
appData: Error loading global app data
|
||||||
|
|
||||||
|
|
@ -7764,6 +7765,7 @@ nav:
|
||||||
tab: Apps
|
tab: Apps
|
||||||
apps: Apps
|
apps: Apps
|
||||||
noData: There are no apps launched.
|
noData: There are no apps launched.
|
||||||
|
noMatch: No apps match the current search
|
||||||
launch: Launch
|
launch: Launch
|
||||||
manage: Manage Catalogs
|
manage: Manage Catalogs
|
||||||
infra:
|
infra:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue