CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/admin/users/user-search.tsx
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
Functionality and UI to ensure a user with given email (or account_id) is sync'd with stripe.
8
*/
9
10
import { List } from "immutable";
11
import { DebounceInput } from "react-debounce-input";
12
import { Button, Col, Row } from "@cocalc/frontend/antd-bootstrap";
13
import {
14
Component,
15
rclass,
16
Rendered,
17
rtypes,
18
} from "@cocalc/frontend/app-framework";
19
import { User } from "@cocalc/frontend/frame-editors/generic/client";
20
import { actions } from "./actions";
21
import { User as UserMap } from "./store";
22
import { UserResult } from "./user";
23
24
interface ReduxProps {
25
state?: "edit" | "running";
26
status?: string;
27
query?: string;
28
result?: List<UserMap>;
29
}
30
31
class UserSearch extends Component<ReduxProps> {
32
static reduxProps() {
33
return {
34
"admin-users": {
35
state: rtypes.string,
36
status: rtypes.string,
37
query: rtypes.string,
38
result: rtypes.immutable.List,
39
},
40
};
41
}
42
43
render_form(): Rendered {
44
return (
45
<Row style={{ marginBottom: "15px" }}>
46
<Col md={6}>
47
<DebounceInput
48
style={{
49
border: "1px solid lightgrey",
50
borderRadius: "3px",
51
padding: "5px",
52
width: "90%",
53
}}
54
value={this.props.query}
55
placeholder="Search for users by partial name, email, account id or project id..."
56
onChange={(e) => actions.set_query(e.target.value)}
57
onKeyDown={(e) => {
58
if (e.keyCode === 13) {
59
actions.search();
60
}
61
}}
62
/>
63
</Col>
64
<Col md={6}>
65
<Button
66
disabled={this.props.query == ""}
67
onClick={() => actions.search()}
68
>
69
Search for Users
70
</Button>
71
</Col>
72
</Row>
73
);
74
}
75
76
render_status(): Rendered {
77
if (!this.props.status) {
78
return;
79
}
80
return (
81
<div>
82
<pre>{this.props.status}</pre>
83
<Button onClick={() => actions.clear_status()}>Clear</Button>
84
</div>
85
);
86
}
87
88
render_user_header(): Rendered {
89
return (
90
<UserResult
91
key={"header"}
92
header={true}
93
first_name="First"
94
last_name="Last"
95
email_address="Email"
96
created="Created"
97
last_active="Active"
98
account_id="Account ID"
99
/>
100
);
101
}
102
103
render_user(user: User): Rendered {
104
return <UserResult key={user.account_id} {...user} />;
105
}
106
107
render_result() {
108
if (!this.props.result || this.props.result.size == 0) {
109
return null;
110
}
111
const v: Rendered[] = [this.render_user_header()];
112
this.props.result.forEach((user) => {
113
v.push(this.render_user(user.toJS()));
114
});
115
return v;
116
}
117
118
render(): Rendered {
119
return (
120
<div style={{ margin: "0 30px" }}>
121
<div>
122
{this.render_form()}
123
{this.render_status()}
124
{this.render_result()}
125
</div>
126
</div>
127
);
128
}
129
}
130
131
const c = rclass(UserSearch);
132
export { c as UserSearch };
133
134