Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/insights/download/DownloadInsights.tsx
2501 views
1
/**
2
* Copyright (c) 2024 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { useCallback, useEffect, useMemo, useState } from "react";
8
import { AlertTriangle } from "lucide-react";
9
import prettyBytes from "pretty-bytes";
10
import { Button } from "@podkit/buttons/Button";
11
import { useDownloadSessionsCSV } from "./download-sessions";
12
import { Timestamp } from "@bufbuild/protobuf";
13
import saveAs from "file-saver";
14
15
type Props = {
16
from: Timestamp;
17
to: Timestamp;
18
organizationId: string;
19
organizationName: string;
20
};
21
export const DownloadInsightsToast = ({ organizationId, from, to, organizationName }: Props) => {
22
const [progress, setProgress] = useState(0);
23
24
const queryArgs = useMemo(
25
() => ({
26
organizationName,
27
organizationId,
28
from,
29
to,
30
onProgress: setProgress,
31
}),
32
[from, organizationId, organizationName, to],
33
);
34
const { data, error, isLoading, abort, remove } = useDownloadSessionsCSV(queryArgs);
35
36
const saveFile = useCallback(() => {
37
if (!data || !data.blob) {
38
return;
39
}
40
41
saveAs(data.blob, data.filename);
42
}, [data]);
43
44
useEffect(() => {
45
return () => {
46
abort();
47
remove();
48
};
49
// eslint-disable-next-line react-hooks/exhaustive-deps
50
}, []);
51
52
if (isLoading) {
53
return (
54
<div>
55
<span>Preparing insights export</span>
56
<br />
57
<span className="text-sm">Exporting page {progress}</span>
58
</div>
59
);
60
}
61
62
if (error) {
63
return (
64
<div className="flex flex-row items-start space-x-2">
65
<AlertTriangle className="w-5 h-5 mt-0.5" />
66
<div>
67
<span>Error exporting your insights data:</span>
68
<pre className="mt-2 whitespace-normal text-sm">{error.message}</pre>
69
</div>
70
</div>
71
);
72
}
73
74
if (!data || !data.blob || data.count === 0) {
75
return <span>No insights data for the selected period.</span>;
76
}
77
78
const readableSize = prettyBytes(data.blob.size);
79
const formattedCount = Intl.NumberFormat().format(data.count);
80
81
return (
82
<div className="flex flex-row items-start justify-between space-x-2">
83
<div>
84
<span>Insights export complete.</span>
85
<p className="text-pk-content-invert-primary/90">
86
{readableSize} &middot; {formattedCount} {data.count !== 1 ? "entries" : "entry"} exported
87
</p>
88
</div>
89
<div>
90
<Button onClick={saveFile} className="text-left text-base">
91
Download CSV
92
</Button>
93
</div>
94
</div>
95
);
96
};
97
98