Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow more powerful queries for Realms/Users tables #1147

Merged
merged 3 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 2 additions & 117 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@
"faker": "^4.1.0",
"file-loader": "^3.0.1",
"hard-source-webpack-plugin": "^0.13.1",
"husky": "^1.3.1",
"js-yaml": "^3.13.1",
"jsdom": "^13.2.0",
"lint-staged": "^8.1.5",
Expand Down Expand Up @@ -254,10 +253,5 @@
},
"engines": {
"node": "^8"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of this change @nirinchev.
Having a pre-commit hook makes it easier to help contributors remember to run linting.

If you think this was really necessary, I think it should have been a separate PR to make it easier to revert in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't commit due to an error that I showed you some time ago. While I agree it could have been done in a separate PR, it didn't seem worth the effort. I'll create an issue to track enabling it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☝️ did you create an issue to track enabling it @nirinchev? I can't seem to find it ..

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course - #1166 - it's the latest issue in the repo 😝

}
}
24 changes: 23 additions & 1 deletion src/ui/ServerAdministration/RealmsTable/RealmsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//
////////////////////////////////////////////////////////////////////////////

import * as electron from 'electron';
import * as React from 'react';
import { Column } from 'react-virtualized';
import { Button } from 'reactstrap';
Expand All @@ -39,6 +40,22 @@ const FilterableRealmTable: React.ComponentType<
IFilterableTableProps<RealmFile>
> = FilterableTable;

const onQueryHelp = () => {
const url =
'https://realm.io/docs/javascript/latest/api/tutorial-query-language.html';
electron.shell.openExternal(url);
};

const queryHelpTooltip = (
<div style={{ textAlign: 'left' }}>
Start a query with ! to pass in a verbatim realm-js query. For example:
<ul>
<li>!path = "/default"</li>
<li>!userId ENDSWITH "123"</li>
</ul>
</div>
);

export const RealmsTable = ({
deletionProgress,
getRealmPermissions,
Expand All @@ -52,6 +69,7 @@ export const RealmsTable = ({
onSearchStringChange,
realms,
searchString,
queryError,
selectedRealms,
onRealmSizeRecalculate,
shouldShowRealmSize,
Expand All @@ -68,6 +86,7 @@ export const RealmsTable = ({
onSearchStringChange: (query: string) => void;
realms: Realm.Results<RealmFile>;
searchString: string;
queryError?: Error;
selectedRealms: RealmFile[];
onRealmSizeRecalculate: (realm: RealmFile) => void;
shouldShowRealmSize: boolean;
Expand All @@ -81,8 +100,11 @@ export const RealmsTable = ({
onElementDoubleClick={onRealmOpened}
onElementsDeselection={onRealmsDeselection}
onSearchStringChange={onSearchStringChange}
searchPlaceholder="Search Realms"
searchPlaceholder="Search Realms (start with ! to write a verbatim realm-js query)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this placeholder is a bit (too) cryptic - perhaps we could move this explanation, with a couple of examples to a tooltip which is shown when pressing "?" button at the end of the input field or perhaps a placeholder in the table when the query doesn't return any results?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nirinchev I see now that my comment doesn't make that much sense, as you did in-fact add a tooltip with examples 😄I think this placeholder can be greatly simplified as we have that.

onQueryHelp={onQueryHelp}
queryHelpTooltip={queryHelpTooltip}
searchString={searchString}
queryError={queryError}
selectedElements={selectedRealms}
isElementsEqual={(a, b) => a.path === b.path}
>
Expand Down
14 changes: 9 additions & 5 deletions src/ui/ServerAdministration/RealmsTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
IRealmStateSize,
MetricsRealmProvider,
} from '../MetricsRealm';
import { querySomeFieldContainsText } from '../utils';
import { getQueryForFields } from '../utils';

import { RealmsTable } from './RealmsTable';

Expand Down Expand Up @@ -60,6 +60,7 @@ export interface IRealmTableContainerState {
/** Prevents spamming the server too badly */
deletionProgress?: IDeletionProgress;
searchString: string;
queryError?: Error;
// TODO: Update this once Realm JS has better support for Sets
selectedRealms: RealmFile[];
showPartialRealms: boolean;
Expand All @@ -84,19 +85,21 @@ class RealmsTableContainer extends React.Component<
showPartialRealms: boolean,
showSystemRealms: boolean,
) => {
let queryError: Error | undefined;
let realms = adminRealm
.objects<RealmFile>('RealmFile')
.sorted('createdAt');

// Filter if a search string is specified
if (searchString || searchString !== '') {
const filterQuery = querySomeFieldContainsText(
const filterQuery = getQueryForFields(
['path', 'realmType', 'owner.accounts.providerId'],
searchString,
);
try {
realms = realms.filtered(filterQuery);
} catch (err) {
queryError = err;
// tslint:disable-next-line:no-console
console.warn(`Could not filter on "${filterQuery}"`, err);
}
Expand All @@ -118,7 +121,7 @@ class RealmsTableContainer extends React.Component<
].join(' AND '),
);
}
return realms;
return { realms, queryError };
},
);

Expand Down Expand Up @@ -283,7 +286,7 @@ class RealmsTableContainer extends React.Component<
};

private renderTable() {
const realms = this.realms(
const { realms, queryError } = this.realms(
this.props.adminRealm,
this.state.searchString,
this.state.showPartialRealms,
Expand Down Expand Up @@ -311,6 +314,7 @@ class RealmsTableContainer extends React.Component<
onSearchStringChange={this.onSearchStringChange}
realms={realms}
searchString={this.state.searchString}
queryError={queryError}
selectedRealms={validSelectedRealms}
deletionProgress={this.state.deletionProgress}
onRealmSizeRecalculate={this.onRealmSizeRecalculate}
Expand Down Expand Up @@ -369,7 +373,7 @@ class RealmsTableContainer extends React.Component<
}

private getRealmsBetween(realmA: RealmFile, realmB: RealmFile) {
const realms = this.realms(
const { realms } = this.realms(
this.props.adminRealm,
this.state.searchString,
this.state.showPartialRealms,
Expand Down
5 changes: 4 additions & 1 deletion src/ui/ServerAdministration/UsersTable/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const UsersTable = ({
searchString,
selection,
users,
queryError,
}: {
getUsersRealms: (user: User) => Realm.Results<RealmFile>;
isChangePasswordOpen: boolean;
Expand All @@ -93,6 +94,7 @@ export const UsersTable = ({
users: Realm.Results<User>;
searchString: string;
onSearchStringChange: (query: string) => void;
queryError?: Error;
}) => {
return (
<div className="UsersTable">
Expand All @@ -103,9 +105,10 @@ export const UsersTable = ({
onElementClick={onUserClick}
onElementsDeselection={onUsersDeselection}
onSearchStringChange={onSearchStringChange}
searchPlaceholder="Search users"
searchPlaceholder="Search users (start with ! to write a verbatim realm-js query)"
searchString={searchString}
selectedElements={selection ? [selection.user] : []}
queryError={queryError}
>
<Column
label="Provider Id(s)"
Expand Down
11 changes: 7 additions & 4 deletions src/ui/ServerAdministration/UsersTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import * as ros from '../../../services/ros';
import { store } from '../../../store';
import { showError } from '../../reusable/errors';
import { withAdminRealm } from '../AdminRealm';
import { querySomeFieldContainsText } from '../utils';
import { getQueryForFields } from '../utils';
import { UsersTable } from './UsersTable';

export interface ISelection {
Expand Down Expand Up @@ -60,16 +60,18 @@ class UsersTableContainer extends React.Component<

protected users = memoize(
(adminRealm: Realm, searchString: string, showSystemUsers: boolean) => {
let queryError: Error | undefined;
let users = adminRealm.objects<ros.User>('User').sorted('userId');
// Filter if a search string is specified
if (searchString && searchString !== '') {
const filterQuery = querySomeFieldContainsText(
const filterQuery = getQueryForFields(
['userId', 'accounts.providerId', 'metadata.key', 'metadata.value'],
searchString,
);
try {
users = users.filtered(filterQuery);
} catch (err) {
queryError = err;
// tslint:disable-next-line:no-console
console.warn(`Could not filter on "${filterQuery}"`, err);
}
Expand All @@ -81,7 +83,7 @@ class UsersTableContainer extends React.Component<
"NOT userId == '__admin' AND NOT accounts.provider BEGINSWITH 'jwt/central'",
);
}
return users;
return { users, queryError };
},
);

Expand Down Expand Up @@ -110,7 +112,7 @@ class UsersTableContainer extends React.Component<
return null;
}

const users = this.users(
const { users, queryError } = this.users(
this.props.adminRealm,
this.state.searchString,
this.state.showSystemUsers,
Expand Down Expand Up @@ -142,6 +144,7 @@ class UsersTableContainer extends React.Component<
searchString={this.state.searchString}
selection={selection}
users={users}
queryError={queryError}
/>
);
}
Expand Down
Loading