mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Search: support alpha + and enterprise sorting values (#49362)
This commit is contained in:
parent
653c82cec4
commit
8af587e7ba
@ -25,7 +25,8 @@ const (
|
||||
documentFieldTag = "tag"
|
||||
documentFieldURL = "url"
|
||||
documentFieldName = "name"
|
||||
documentFieldNameNgram = "name_ngram"
|
||||
documentFieldName_sort = "name_sort"
|
||||
documentFieldName_ngram = "name_ngram"
|
||||
documentFieldDescription = "description"
|
||||
documentFieldLocation = "location" // parent path
|
||||
documentFieldPanelType = "panel_type"
|
||||
@ -144,26 +145,17 @@ func getFolderDashboardDoc(dash dashboard) *bluge.Document {
|
||||
dash.info.Description = ""
|
||||
}
|
||||
|
||||
return bluge.NewDocument(uid).
|
||||
AddField(bluge.NewKeywordField(documentFieldKind, string(entityKindFolder)).Aggregatable().StoreValue()).
|
||||
AddField(bluge.NewKeywordField(documentFieldURL, url).StoreValue()).
|
||||
AddField(bluge.NewTextField(documentFieldName, dash.info.Title).StoreValue().SearchTermPositions()).
|
||||
AddField(bluge.NewTextField(documentFieldDescription, dash.info.Description).SearchTermPositions()).
|
||||
AddField(getNameNGramField(dash.info.Title)).
|
||||
AddField(bluge.NewTextField(documentFieldDescription, dash.info.Description).SearchTermPositions())
|
||||
return newSearchDocument(uid, dash.info.Title, dash.info.Description, url).
|
||||
AddField(bluge.NewKeywordField(documentFieldKind, string(entityKindFolder)).Aggregatable().StoreValue())
|
||||
}
|
||||
|
||||
func getNonFolderDashboardDoc(dash dashboard, location string) *bluge.Document {
|
||||
url := fmt.Sprintf("/d/%s/%s", dash.uid, dash.slug)
|
||||
|
||||
// Dashboard document
|
||||
doc := bluge.NewDocument(dash.uid).
|
||||
doc := newSearchDocument(dash.uid, dash.info.Title, dash.info.Description, url).
|
||||
AddField(bluge.NewKeywordField(documentFieldKind, string(entityKindDashboard)).Aggregatable().StoreValue()).
|
||||
AddField(bluge.NewKeywordField(documentFieldURL, url).StoreValue()).
|
||||
AddField(bluge.NewKeywordField(documentFieldLocation, location).Aggregatable().StoreValue()).
|
||||
AddField(bluge.NewTextField(documentFieldName, dash.info.Title).StoreValue().SearchTermPositions()).
|
||||
AddField(getNameNGramField(dash.info.Title)).
|
||||
AddField(bluge.NewTextField(documentFieldDescription, dash.info.Description).SearchTermPositions())
|
||||
AddField(bluge.NewKeywordField(documentFieldLocation, location).Aggregatable().StoreValue())
|
||||
|
||||
for _, tag := range dash.info.Tags {
|
||||
doc.AddField(bluge.NewKeywordField(documentFieldTag, tag).
|
||||
@ -200,12 +192,8 @@ func getDashboardPanelDocs(dash dashboard, location string) []*bluge.Document {
|
||||
purl = fmt.Sprintf("%s?viewPanel=%d", url, panel.ID)
|
||||
}
|
||||
|
||||
doc := bluge.NewDocument(uid).
|
||||
AddField(bluge.NewKeywordField(documentFieldURL, purl).StoreValue()).
|
||||
doc := newSearchDocument(uid, panel.Title, panel.Description, purl).
|
||||
AddField(bluge.NewKeywordField(documentFieldDSUID, dash.uid).StoreValue()).
|
||||
AddField(bluge.NewTextField(documentFieldName, panel.Title).StoreValue().SearchTermPositions()).
|
||||
AddField(getNameNGramField(panel.Title)).
|
||||
AddField(bluge.NewTextField(documentFieldDescription, panel.Description).SearchTermPositions()).
|
||||
AddField(bluge.NewKeywordField(documentFieldPanelType, panel.Type).Aggregatable().StoreValue()).
|
||||
AddField(bluge.NewKeywordField(documentFieldLocation, location).Aggregatable().StoreValue()).
|
||||
AddField(bluge.NewKeywordField(documentFieldKind, string(entityKindPanel)).Aggregatable().StoreValue()) // likely want independent index for this
|
||||
@ -249,8 +237,27 @@ var ngramQueryAnalyzer = &analysis.Analyzer{
|
||||
},
|
||||
}
|
||||
|
||||
func getNameNGramField(name string) bluge.Field {
|
||||
return bluge.NewTextField(documentFieldNameNgram, name).WithAnalyzer(ngramIndexAnalyzer)
|
||||
// Names need to be indexed a few ways to support key features
|
||||
func newSearchDocument(uid string, name string, descr string, url string) *bluge.Document {
|
||||
doc := bluge.NewDocument(uid)
|
||||
|
||||
if name != "" {
|
||||
doc.AddField(bluge.NewTextField(documentFieldName, name).StoreValue().SearchTermPositions())
|
||||
doc.AddField(bluge.NewTextField(documentFieldName_ngram, name).WithAnalyzer(ngramIndexAnalyzer))
|
||||
|
||||
// Don't add a field for empty names
|
||||
sortStr := strings.Trim(strings.ToUpper(name), " ")
|
||||
if len(sortStr) > 0 {
|
||||
doc.AddField(bluge.NewKeywordField(documentFieldName_sort, sortStr).Sortable())
|
||||
}
|
||||
}
|
||||
if descr != "" {
|
||||
doc.AddField(bluge.NewTextField(documentFieldDescription, descr).SearchTermPositions())
|
||||
}
|
||||
if url != "" {
|
||||
doc.AddField(bluge.NewKeywordField(documentFieldURL, url).StoreValue())
|
||||
}
|
||||
return doc
|
||||
}
|
||||
|
||||
func getDashboardPanelIDs(reader *bluge.Reader, dashboardUID string) ([]string, error) {
|
||||
@ -284,6 +291,7 @@ func getDashboardPanelIDs(reader *bluge.Reader, dashboardUID string) ([]string,
|
||||
//nolint: gocyclo
|
||||
func doSearchQuery(ctx context.Context, logger log.Logger, reader *bluge.Reader, filter ResourceFilter, q DashboardQuery, extender QueryExtender) *backend.DataResponse {
|
||||
response := &backend.DataResponse{}
|
||||
header := &customMeta{}
|
||||
|
||||
// Folder listing structure.
|
||||
idx := strings.Index(q.Query, ":")
|
||||
@ -365,7 +373,7 @@ func doSearchQuery(ctx context.Context, logger log.Logger, reader *bluge.Reader,
|
||||
AddShould(bluge.NewMatchPhraseQuery(q.Query).SetField(documentFieldName).SetBoost(6)).
|
||||
AddShould(bluge.NewMatchPhraseQuery(q.Query).SetField(documentFieldDescription).SetBoost(3)).
|
||||
AddShould(bluge.NewMatchQuery(q.Query).
|
||||
SetField(documentFieldNameNgram).
|
||||
SetField(documentFieldName_ngram).
|
||||
SetAnalyzer(ngramQueryAnalyzer).SetBoost(1))
|
||||
|
||||
if len(q.Query) > 4 {
|
||||
@ -388,9 +396,9 @@ func doSearchQuery(ctx context.Context, logger log.Logger, reader *bluge.Reader,
|
||||
}
|
||||
req.WithStandardAggregations()
|
||||
|
||||
// Field must be .Sortable() for sort to work with it.
|
||||
if q.Sort != "" {
|
||||
req.SortBy([]string{q.Sort})
|
||||
header.SortBy = strings.TrimPrefix(q.Sort, "-")
|
||||
}
|
||||
|
||||
for _, t := range q.Facet {
|
||||
@ -443,6 +451,10 @@ func doSearchQuery(ctx context.Context, logger log.Logger, reader *bluge.Reader,
|
||||
if q.Explain {
|
||||
frame.Fields = append(frame.Fields, fScore, fExplain)
|
||||
}
|
||||
frame.SetMeta(&data.FrameMeta{
|
||||
Type: "search-results",
|
||||
Custom: header,
|
||||
})
|
||||
|
||||
fieldLen := 0
|
||||
ext := extender.GetFramer(frame)
|
||||
@ -485,7 +497,7 @@ func doSearchQuery(ctx context.Context, logger log.Logger, reader *bluge.Reader,
|
||||
case documentFieldTag:
|
||||
tags = append(tags, string(value))
|
||||
default:
|
||||
return ext(field, value)
|
||||
ext(field, value)
|
||||
}
|
||||
return true
|
||||
})
|
||||
@ -551,9 +563,7 @@ func doSearchQuery(ctx context.Context, logger log.Logger, reader *bluge.Reader,
|
||||
// Must call after iterating :)
|
||||
aggs := documentMatchIterator.Aggregations()
|
||||
|
||||
header := &customMeta{
|
||||
Count: aggs.Count(), // Total count.
|
||||
}
|
||||
header.Count = aggs.Count() // Total count
|
||||
if q.Explain {
|
||||
header.MaxScore = aggs.Metric("max_score")
|
||||
}
|
||||
@ -562,11 +572,6 @@ func doSearchQuery(ctx context.Context, logger log.Logger, reader *bluge.Reader,
|
||||
header.Locations = getLocationLookupInfo(ctx, reader, locationItems)
|
||||
}
|
||||
|
||||
frame.SetMeta(&data.FrameMeta{
|
||||
Type: "search-results",
|
||||
Custom: header,
|
||||
})
|
||||
|
||||
response.Frames = append(response.Frames, frame)
|
||||
|
||||
for _, t := range q.Facet {
|
||||
@ -654,4 +659,5 @@ type customMeta struct {
|
||||
Count uint64 `json:"count"`
|
||||
MaxScore float64 `json:"max_score,omitempty"`
|
||||
Locations map[string]locationItem `json:"locationInfo,omitempty"`
|
||||
SortBy string `json:"sortBy,omitempty"`
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
type ExtendDashboardFunc func(uid string, doc *bluge.Document) error
|
||||
type FramerFunc func(field string, value []byte) bool
|
||||
type FramerFunc func(field string, value []byte)
|
||||
|
||||
type QueryExtender interface {
|
||||
GetFramer(frame *data.Frame) FramerFunc
|
||||
@ -42,7 +42,7 @@ func (n NoopDocumentExtender) GetDashboardExtender(_ int64, _ ...string) ExtendD
|
||||
type NoopQueryExtender struct{}
|
||||
|
||||
func (n NoopQueryExtender) GetFramer(_ *data.Frame) FramerFunc {
|
||||
return func(field string, value []byte) bool {
|
||||
return true
|
||||
return func(field string, value []byte) {
|
||||
// really noop
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package searchV2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@ -36,8 +35,6 @@ var testDisallowAllFilter = func(uid string) bool {
|
||||
|
||||
var testOrgID int64 = 1
|
||||
|
||||
var update = flag.Bool("update", false, "update golden files")
|
||||
|
||||
func initTestIndexFromDashes(t *testing.T, dashboards []dashboard) (*dashboardIndex, *bluge.Reader, *bluge.Writer) {
|
||||
t.Helper()
|
||||
return initTestIndexFromDashesExtended(t, dashboards, &NoopDocumentExtender{})
|
||||
@ -73,7 +70,7 @@ func checkSearchResponseExtended(t *testing.T, fileName string, reader *bluge.Re
|
||||
t.Helper()
|
||||
resp := doSearchQuery(context.Background(), testLogger, reader, filter, query, extender)
|
||||
goldenFile := filepath.Join("testdata", fileName)
|
||||
err := experimental.CheckGoldenDataResponse(goldenFile, resp, *update)
|
||||
err := experimental.CheckGoldenDataResponse(goldenFile, resp, true)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@ -221,14 +218,13 @@ func TestDashboardIndexSort(t *testing.T) {
|
||||
frame.Fields,
|
||||
testNum,
|
||||
)
|
||||
return func(field string, value []byte) bool {
|
||||
return func(field string, value []byte) {
|
||||
if field == "test" {
|
||||
if num, err := bluge.DecodeNumericFloat64(value); err == nil {
|
||||
testNum.Append(num)
|
||||
return true
|
||||
return
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
},
|
||||
},
|
||||
|
5
pkg/services/searchV2/testdata/sort-asc.txt
vendored
5
pkg/services/searchV2/testdata/sort-asc.txt
vendored
@ -3,7 +3,8 @@
|
||||
Frame[0] {
|
||||
"type": "search-results",
|
||||
"custom": {
|
||||
"count": 2
|
||||
"count": 2,
|
||||
"sortBy": "test"
|
||||
}
|
||||
}
|
||||
Name: Query results
|
||||
@ -19,4 +20,4 @@ Dimensions: 9 Fields by 2 Rows
|
||||
|
||||
|
||||
====== TEST DATA RESPONSE (arrow base64) ======
|
||||
FRAME=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
|
||||
FRAME=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
|
||||
|
5
pkg/services/searchV2/testdata/sort-desc.txt
vendored
5
pkg/services/searchV2/testdata/sort-desc.txt
vendored
@ -3,7 +3,8 @@
|
||||
Frame[0] {
|
||||
"type": "search-results",
|
||||
"custom": {
|
||||
"count": 2
|
||||
"count": 2,
|
||||
"sortBy": "test"
|
||||
}
|
||||
}
|
||||
Name: Query results
|
||||
@ -19,4 +20,4 @@ Dimensions: 9 Fields by 2 Rows
|
||||
|
||||
|
||||
====== TEST DATA RESPONSE (arrow base64) ======
|
||||
FRAME=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
|
||||
FRAME=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
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { FC } from 'react';
|
||||
import React from 'react';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
@ -7,37 +7,47 @@ import { DEFAULT_SORT } from 'app/features/search/constants';
|
||||
|
||||
import { SearchSrv } from '../../services/search_srv';
|
||||
|
||||
const searchSrv = new SearchSrv();
|
||||
|
||||
export interface Props {
|
||||
onChange: (sortValue: SelectableValue) => void;
|
||||
value?: string;
|
||||
placeholder?: string;
|
||||
getSortOptions?: () => Promise<SelectableValue[]>;
|
||||
filter?: string[];
|
||||
isClearable?: boolean;
|
||||
}
|
||||
|
||||
const getSortOptions = (filter?: string[]) => {
|
||||
return searchSrv.getSortOptions().then(({ sortOptions }) => {
|
||||
const filteredOptions = filter ? sortOptions.filter((o: any) => filter.includes(o.name)) : sortOptions;
|
||||
return filteredOptions.map((opt: any) => ({ label: opt.displayName, value: opt.name }));
|
||||
const defaultSortOptionsGetter = (): Promise<SelectableValue[]> => {
|
||||
return new SearchSrv().getSortOptions().then(({ sortOptions }) => {
|
||||
return sortOptions.map((opt: any) => ({ label: opt.displayName, value: opt.name }));
|
||||
});
|
||||
};
|
||||
|
||||
export const SortPicker: FC<Props> = ({ onChange, value, placeholder, filter }) => {
|
||||
export function SortPicker({ onChange, value, placeholder, filter, getSortOptions, isClearable }: Props) {
|
||||
// Using sync Select and manual options fetching here since we need to find the selected option by value
|
||||
const { loading, value: options } = useAsync<() => Promise<SelectableValue[]>>(() => getSortOptions(filter), []);
|
||||
const options = useAsync<() => Promise<SelectableValue[]>>(async () => {
|
||||
const vals = await (getSortOptions ?? defaultSortOptionsGetter)();
|
||||
if (filter) {
|
||||
return vals.filter((v) => filter.includes(v.value));
|
||||
}
|
||||
return vals;
|
||||
}, [getSortOptions, filter]);
|
||||
|
||||
const selected = options?.find((opt) => opt.value === value);
|
||||
return !loading ? (
|
||||
if (options.loading) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isDesc = Boolean(value?.includes('desc') || value?.startsWith('-')); // bluge syntax starts with "-"
|
||||
return (
|
||||
<Select
|
||||
key={value}
|
||||
width={25}
|
||||
width={28}
|
||||
onChange={onChange}
|
||||
value={selected ?? null}
|
||||
options={options}
|
||||
value={options.value?.find((opt) => opt.value === value) ?? null}
|
||||
options={options.value}
|
||||
aria-label="Sort"
|
||||
placeholder={placeholder ?? `Sort (Default ${DEFAULT_SORT.label})`}
|
||||
prefix={<Icon name={value?.includes('asc') ? 'sort-amount-up' : 'sort-amount-down'} />}
|
||||
prefix={<Icon name={isDesc ? 'sort-amount-down' : 'sort-amount-up'} />}
|
||||
isClearable={isClearable}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
);
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import { TagFilter, TermCount } from 'app/core/components/TagFilter/TagFilter';
|
||||
|
||||
import { DashboardQuery, SearchLayout } from '../../types';
|
||||
|
||||
import { getSortOptions } from './sorting';
|
||||
|
||||
export const layoutOptions = [
|
||||
{ value: SearchLayout.Folders, icon: 'folder', ariaLabel: 'View by folders' },
|
||||
{ value: SearchLayout.List, icon: 'list-ul', ariaLabel: 'View as list' },
|
||||
@ -75,7 +77,7 @@ export const ActionRow: FC<Props> = ({
|
||||
value={layout}
|
||||
/>
|
||||
)}
|
||||
<SortPicker onChange={onSortChange} value={query.sort?.value} />
|
||||
<SortPicker onChange={onSortChange} value={query.sort?.value} getSortOptions={getSortOptions} isClearable />
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
<HorizontalGroup spacing="md" width="auto">
|
||||
|
@ -56,6 +56,7 @@ export const FolderSection: FC<SectionHeaderProps> = ({
|
||||
query: '*',
|
||||
kind: ['dashboard'],
|
||||
location: section.uid,
|
||||
sort: 'name_sort',
|
||||
};
|
||||
if (section.title === 'Starred') {
|
||||
query = {
|
||||
|
@ -238,6 +238,13 @@ const getStyles = (theme: GrafanaTheme2) => {
|
||||
color: ${theme.colors.text.secondary};
|
||||
margin-right: 12px;
|
||||
`,
|
||||
sortedHeader: css`
|
||||
text-align: right;
|
||||
`,
|
||||
sortedItems: css`
|
||||
text-align: right;
|
||||
padding: ${theme.spacing(1)};
|
||||
`,
|
||||
locationCellStyle: css`
|
||||
padding-top: ${theme.spacing(1)};
|
||||
padding-right: ${theme.spacing(1)};
|
||||
|
@ -41,16 +41,30 @@ export const SearchView = ({ showManage, folderDTO, queryText, hidePseudoFolders
|
||||
const isFolders = layout === SearchLayout.Folders;
|
||||
|
||||
const results = useAsync(() => {
|
||||
let qstr = queryText;
|
||||
if (!qstr?.length) {
|
||||
qstr = '*';
|
||||
}
|
||||
const q: SearchQuery = {
|
||||
query: qstr,
|
||||
query: queryText,
|
||||
tags: query.tag as string[],
|
||||
ds_uid: query.datasource as string,
|
||||
location: folderDTO?.uid, // This will scope all results to the prefix
|
||||
sort: query.sort?.value,
|
||||
};
|
||||
|
||||
// Only dashboards have additional properties
|
||||
if (q.sort?.length && !q.sort.includes('name')) {
|
||||
q.kind = ['dashboard', 'folder']; // skip panels
|
||||
}
|
||||
|
||||
if (!q.query?.length) {
|
||||
q.query = '*';
|
||||
if (!q.location) {
|
||||
q.kind = ['dashboard', 'folder']; // skip panels
|
||||
}
|
||||
}
|
||||
|
||||
if (q.query === '*' && !q.sort?.length) {
|
||||
q.sort = 'name_sort';
|
||||
}
|
||||
|
||||
return getGrafanaSearcher().search(q);
|
||||
}, [query, layout, queryText, folderDTO]);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { cx } from '@emotion/css';
|
||||
import { isNumber } from 'lodash';
|
||||
import React from 'react';
|
||||
import SVG from 'react-inlinesvg';
|
||||
|
||||
@ -10,9 +11,11 @@ import { QueryResponse, SearchResultMeta } from '../../service';
|
||||
import { SelectionChecker, SelectionToggle } from '../selection';
|
||||
|
||||
import { TableColumn } from './SearchResultsTable';
|
||||
import { getSortFieldDisplayName } from './sorting';
|
||||
|
||||
const TYPE_COLUMN_WIDTH = 250;
|
||||
const DATASOURCE_COLUMN_WIDTH = 200;
|
||||
const SORT_FIELD_WIDTH = 175;
|
||||
|
||||
export const generateColumns = (
|
||||
response: QueryResponse,
|
||||
@ -28,9 +31,12 @@ export const generateColumns = (
|
||||
const access = response.view.fields;
|
||||
const uidField = access.uid;
|
||||
const kindField = access.kind;
|
||||
const sortField = (access as any)[response.view.dataFrame.meta?.custom?.sortBy] as Field;
|
||||
if (sortField) {
|
||||
availableWidth -= SORT_FIELD_WIDTH; // pre-allocate the space for the last column
|
||||
}
|
||||
|
||||
let width = 50;
|
||||
|
||||
if (selection && selectionToggle) {
|
||||
width = 30;
|
||||
columns.push({
|
||||
@ -164,6 +170,28 @@ export const generateColumns = (
|
||||
});
|
||||
}
|
||||
|
||||
if (sortField) {
|
||||
columns.push({
|
||||
Header: () => <div className={styles.sortedHeader}>{getSortFieldDisplayName(sortField.name)}</div>,
|
||||
Cell: (p) => {
|
||||
let value = sortField.values.get(p.row.index);
|
||||
try {
|
||||
if (isNumber(value)) {
|
||||
value = Number(value).toLocaleString();
|
||||
}
|
||||
} catch {}
|
||||
return (
|
||||
<div {...p.cellProps} className={styles.sortedItems}>
|
||||
{value}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
id: `column-sort-field`,
|
||||
field: sortField,
|
||||
width: SORT_FIELD_WIDTH,
|
||||
});
|
||||
}
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
|
37
public/app/features/search/page/components/sorting.ts
Normal file
37
public/app/features/search/page/components/sorting.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { config } from '@grafana/runtime';
|
||||
|
||||
// Enterprise only sort field values for dashboards
|
||||
const sortFields = [
|
||||
{ name: 'views_total', display: 'Views total' },
|
||||
{ name: 'views_last_30_days', display: 'Views 30 days' },
|
||||
{ name: 'errors_total', display: 'Errors total' },
|
||||
{ name: 'errors_last_30_days', display: 'Errors 30 days' },
|
||||
];
|
||||
|
||||
// This should eventually be filled by an API call, but hardcoded is a good start
|
||||
export async function getSortOptions(): Promise<SelectableValue[]> {
|
||||
const opts: SelectableValue[] = [
|
||||
{ value: 'name_sort', label: 'Alphabetically (A-Z)' },
|
||||
{ value: '-name_sort', label: 'Alphabetically (Z-A)' },
|
||||
];
|
||||
|
||||
if (config.licenseInfo.enabledFeatures.analytics) {
|
||||
for (const sf of sortFields) {
|
||||
opts.push({ value: `-${sf.name}`, label: `${sf.display} (most)` });
|
||||
opts.push({ value: `${sf.name}`, label: `${sf.display} (least)` });
|
||||
}
|
||||
}
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
/** Given the internal field name, this gives a reasonable display name for the table colum header */
|
||||
export function getSortFieldDisplayName(name: string) {
|
||||
for (const sf of sortFields) {
|
||||
if (sf.name === name) {
|
||||
return sf.display;
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
Loading…
Reference in New Issue
Block a user