feat(ui): sort search bar icon [EE-3663] (#7205)

pull/7206/head
Chaim Lev-Ari 2022-07-06 17:05:17 +03:00 committed by GitHub
parent 88c4a43a19
commit ce840997bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 73 additions and 54 deletions

View File

@ -193,7 +193,7 @@ input:checked + .slider:before {
flex-wrap: nowarp;
}
.toolBar > .searchBar {
.toolBar .searchBar {
flex: right;
margin-right: 10px;
width: 500px;

View File

@ -40,10 +40,16 @@ angular.module('portainer.app').controller('GenericDatatableController', [
_.map(this.state.filteredDataSet, (item) => (item.Checked = false));
};
this.onTextFilterChange = function () {
DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter);
this.onTextFilterChangeGeneric = onTextFilterChangeGeneric;
this.onTextFilterChange = function onTextFilterChange() {
return this.onTextFilterChangeGeneric();
};
function onTextFilterChangeGeneric() {
DatatableService.setDataTableTextFilters(this.tableKey, this.state.textFilter);
}
this.changeOrderBy = function changeOrderBy(orderField) {
this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false;
this.state.orderBy = orderField;

View File

@ -2,7 +2,6 @@ import angular from 'angular';
import 'angular-utils-pagination';
import { datatableTitlebar } from './titlebar';
import { datatableSearchbar } from './searchbar';
import { datatableSortIcon } from './sort-icon';
import { datatablePagination } from './pagination';
import { datatableFilter } from './filter';
@ -10,7 +9,6 @@ import { datatableFilter } from './filter';
export default angular
.module('portainer.shared.datatable', ['angularUtils.directives.dirPagination'])
.component('datatableTitlebar', datatableTitlebar)
.component('datatableSearchbar', datatableSearchbar)
.component('datatableSortIcon', datatableSortIcon)
.component('datatablePagination', datatablePagination)
.component('datatableFilter', datatableFilter).name;

View File

@ -1,4 +0,0 @@
<div class="searchBar">
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
<input type="text" class="searchInput" ng-model="$ctrl.filter" ng-change="$ctrl.onChange($ctrl.filter)" placeholder="Search..." ng-model-options="{ debounce: 300 }" />
</div>

View File

@ -1,7 +0,0 @@
export const datatableSearchbar = {
bindings: {
onChange: '<',
ngModel: '<',
},
templateUrl: './datatable-searchbar.html',
};

View File

@ -3,19 +3,9 @@
<rd-widget-body classes="no-padding">
<div class="toolBar">
<div class="toolBarTitle"><i class="fa" ng-class="$ctrl.titleIcon" aria-hidden="true" style="margin-right: 2px"></i> {{ $ctrl.titleText }} </div>
<div class="searchBar">
<i class="fa fa-search searchIcon" aria-hidden="true"></i>
<input
type="text"
class="searchInput"
ng-model="$ctrl.state.textFilter"
ng-change="$ctrl.onTextFilterChange()"
placeholder="Search..."
auto-focus
ng-model-options="{ debounce: 300 }"
data-cy="stack-searchInput"
/>
</div>
<datatable-searchbar value="$ctrl.state.textFilter" placeholder="'Search...'" on-change="($ctrl.onTextFilterChange)" data-cy="stack-searchInput"></datatable-searchbar>
<div class="actionBar" ng-if="!$ctrl.offlineMode" authorization="PortainerStackCreate, PortainerStackDelete">
<button
type="button"

View File

@ -33,6 +33,13 @@ angular.module('portainer.app').controller('StacksDatatableController', [
DatatableService.setColumnVisibilitySettings(this.tableKey, this.columnVisibility);
}
this.onTextFilterChange = onTextFilterChange.bind(this);
function onTextFilterChange(value) {
this.state.textFilter = value;
this.onTextFilterChangeGeneric();
}
/**
* Do not allow external items
*/

View File

@ -11,6 +11,7 @@ import { PasswordCheckHint } from '@@/PasswordCheckHint';
import { ViewLoading } from '@@/ViewLoading';
import { Tooltip } from '@@/Tip/Tooltip';
import { DashboardItem } from '@@/DashboardItem';
import { SearchBar } from '@@/datatables/SearchBar';
import { fileUploadField } from './file-upload-field';
import { switchField } from './switch-field';
@ -43,4 +44,8 @@ export const componentsModule = angular
.component(
'dashboardItem',
r2a(DashboardItem, ['featherIcon', 'icon', 'type', 'value', 'children'])
)
.component(
'datatableSearchbar',
r2a(SearchBar, ['data-cy', 'onChange', 'value', 'placeholder'])
).name;

View File

@ -2,7 +2,7 @@
<rd-widget>
<rd-widget-body classes="no-padding">
<datatable-titlebar title="Activity Logs" icon="fa-history" feature="{{::$ctrl.feature}}"></datatable-titlebar>
<datatable-searchbar on-change="($ctrl.onChangeKeyword)" ng-model="$ctrl.keyword"></datatable-searchbar>
<datatable-searchbar on-change="($ctrl.onChangeKeyword)" value="$ctrl.keyword"></datatable-searchbar>
<div class="table-responsive">
<table class="table table-hover">
<thead>

View File

@ -3,8 +3,9 @@ import moment from 'moment';
import { FeatureId } from '@/portainer/feature-flags/enums';
export default class ActivityLogsViewController {
/* @ngInject */
constructor($async, Notifications) {
constructor($async, $scope, Notifications) {
this.$async = $async;
this.$scope = $scope;
this.Notifications = Notifications;
this.limitedFeature = FeatureId.ACTIVITY_AUDIT;
@ -54,9 +55,11 @@ export default class ActivityLogsViewController {
}
onChangeKeyword(keyword) {
return this.$scope.$evalAsync(() => {
this.state.page = 1;
this.state.keyword = keyword;
this.loadLogs();
});
}
onChangeDate({ startDate, endDate }) {
@ -65,16 +68,6 @@ export default class ActivityLogsViewController {
this.loadLogs();
}
async export() {
return this.$async(async () => {
try {
await this.UserActivityService.saveLogsAsCSV(this.state.sort, this.state.keyword, this.state.date, this.state.contextFilter);
} catch (err) {
this.Notifications.error('Failure', err, 'Failed loading user activity logs csv');
}
});
}
async loadLogs() {
return this.$async(async () => {
this.state.logs = null;

View File

@ -2,7 +2,7 @@
<rd-widget>
<rd-widget-body classes="no-padding">
<datatable-titlebar title="Authentication Events" icon="fa-history" feature="{{::$ctrl.feature}}"></datatable-titlebar>
<datatable-searchbar on-change="($ctrl.onChangeKeyword)" ng-model="$ctrl.keyword"></datatable-searchbar>
<datatable-searchbar on-change="($ctrl.onChangeKeyword)" value="$ctrl.keyword"></datatable-searchbar>
<div class="table-responsive">
<table class="table table-hover nowrap-cells">
<thead>

View File

@ -68,9 +68,11 @@ export default class AuthLogsViewController {
}
onChangeKeyword(keyword) {
return this.$scope.$evalAsync(() => {
this.state.page = 1;
this.state.keyword = keyword;
this.loadLogs();
});
}
onChangeDate({ startDate, endDate }) {

View File

@ -1,6 +1,11 @@
import { useLocalStorage } from '@/portainer/hooks/useLocalStorage';
import { Search } from 'react-feather';
import { useEffect, useMemo, useState } from 'react';
import _ from 'lodash';
interface Props {
import { useLocalStorage } from '@/portainer/hooks/useLocalStorage';
import { AutomationTestingProps } from '@/types';
interface Props extends AutomationTestingProps {
value: string;
placeholder?: string;
onChange(value: string): void;
@ -10,21 +15,45 @@ export function SearchBar({
value,
placeholder = 'Search...',
onChange,
'data-cy': dataCy,
}: Props) {
const [searchValue, setSearchValue] = useDebounce(value, onChange);
return (
<div className="searchBar">
<i className="fa fa-search searchIcon" aria-hidden="true" />
<div className="searchBar items-center flex">
<Search className="searchIcon feather" />
<input
type="text"
className="searchInput"
value={value}
onChange={(e) => onChange(e.target.value)}
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder={placeholder}
data-cy={dataCy}
/>
</div>
);
}
function useDebounce(defaultValue: string, onChange: (value: string) => void) {
const [searchValue, setSearchValue] = useState(defaultValue);
useEffect(() => {
setSearchValue(defaultValue);
}, [defaultValue]);
const onChangeDebounces = useMemo(
() => _.debounce(onChange, 300),
[onChange]
);
return [searchValue, handleChange] as const;
function handleChange(value: string) {
setSearchValue(value);
onChangeDebounces(value);
}
}
export function useSearchBarState(
key: string
): [string, (value: string) => void] {