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/course/common/multiple-add-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
import { Button } from "antd";
7
import { useState } from "react";
8
import { FormattedMessage, useIntl } from "react-intl";
9
10
import { Icon } from "@cocalc/frontend/components";
11
import { course } from "@cocalc/frontend/i18n";
12
import DirectorySelector from "@cocalc/frontend/project/directory-selector";
13
import { capitalize, plural } from "@cocalc/util/misc";
14
import { ItemName } from "./types";
15
16
interface MultipleAddSearchProps {
17
addSelected: (keys: string[]) => void; // Submit user selected results add_selected(['paths', 'of', 'folders'])
18
itemName: ItemName;
19
err?: string;
20
isExcluded: (path: string) => boolean;
21
defaultOpen?;
22
selectorStyle?;
23
closable: boolean;
24
}
25
26
// Multiple result selector
27
// use on_change and search to control the search bar.
28
// Coupled with Assignments Panel and Handouts Panel
29
export function MultipleAddSearch({
30
addSelected,
31
itemName = "assignment",
32
isExcluded,
33
defaultOpen,
34
selectorStyle,
35
closable,
36
}: MultipleAddSearchProps) {
37
const intl = useIntl();
38
const [selecting, setSelecting] = useState<boolean>(defaultOpen);
39
const [selectedItems, setSelectedItems] = useState<Set<string>>(new Set([]));
40
const n = selectedItems.size;
41
42
function clear() {
43
setSelecting(false);
44
setSelectedItems(new Set([]));
45
}
46
47
function label(): string {
48
switch (itemName) {
49
case "assignment":
50
return intl.formatMessage(course.assignment);
51
case "handout":
52
return intl.formatMessage(course.handout);
53
default:
54
return itemName;
55
}
56
}
57
58
function labelPlural(): string {
59
if (n === 1) return label();
60
switch (itemName) {
61
case "assignment":
62
return intl.formatMessage(course.assignments);
63
case "handout":
64
return intl.formatMessage(course.handouts);
65
default:
66
return plural(n, label());
67
}
68
}
69
70
const title = intl.formatMessage(
71
{
72
id: "course.multiple-add-search.directory-selector.title",
73
defaultMessage: `Select one or more {name} folders`,
74
},
75
{ name: label() },
76
);
77
78
return (
79
<div>
80
<Button
81
style={{ marginRight: "5px" }}
82
disabled={selecting}
83
onClick={() => setSelecting(true)}
84
>
85
<FormattedMessage
86
id="course.multiple-add-search.directory-selector.button"
87
defaultMessage={`Add {name}...`}
88
values={{ name: capitalize(label()) }}
89
/>
90
</Button>
91
{selecting && (
92
<DirectorySelector
93
multi
94
closable={closable}
95
style={{
96
width: "500px",
97
margin: "10px 0",
98
position: "absolute",
99
zIndex: 1,
100
boxShadow: "8px 8px 4px #888",
101
...selectorStyle,
102
}}
103
title={title}
104
onMultiSelect={setSelectedItems}
105
onClose={clear}
106
isExcluded={(path) => {
107
for (const cur of selectedItems) {
108
if (path.startsWith(cur + "/")) return true;
109
if (cur.startsWith(path + "/")) return true;
110
}
111
return isExcluded(path);
112
}}
113
/>
114
)}
115
{selecting && (
116
<Button
117
type="primary"
118
disabled={n == 0}
119
onClick={() => {
120
addSelected(Array.from(selectedItems));
121
clear();
122
}}
123
>
124
<Icon name="plus" />
125
<FormattedMessage
126
id="course.multiple-add-search.directory-selector.add_button"
127
defaultMessage={`{n, select,
128
0 {Select one or more directories}
129
other {Add {n} {name}}}`}
130
values={{
131
n,
132
name: labelPlural(),
133
}}
134
/>
135
</Button>
136
)}
137
</div>
138
);
139
}
140
141