Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/frontend/compute/cloud-filesystem/bucket.tsx
Views: 687
import { getCity, getDataStoragePriceRange } from "./util";1import { Alert, Checkbox, Select, Spin } from "antd";2import {3GOOGLE_CLOUD_BUCKET_STORAGE_CLASSES,4GOOGLE_CLOUD_BUCKET_STORAGE_CLASSES_DESC,5GOOGLE_CLOUD_MULTIREGIONS,6GOOGLE_CLOUD_REGIONS,7DEFAULT_CONFIGURATION,8} from "@cocalc/util/db-schema/cloud-filesystems";9import { useEffect, useMemo, useState } from "react";10import { A, Icon } from "@cocalc/frontend/components";11import { EXTERNAL, NO_CHANGE } from "./create";12import { getRecentRegions } from "./regions";13import { currency } from "@cocalc/util/misc";14import { markup } from "@cocalc/util/compute/cloud/google-cloud/compute-cost";15import { useGoogleCloudPriceData } from "@cocalc/frontend/compute/api";16import { filterOption } from "@cocalc/frontend/compute/util";1718export function BucketStorageClass({ configuration, setConfiguration }) {19const [priceData] = useGoogleCloudPriceData();2021if (priceData == null) {22return <Spin />;23}24return (25<div style={{ marginTop: "10px" }}>26<b style={{ fontSize: "13pt" }}>27<A href="https://cloud.google.com/storage/docs/storage-classes">28{EXTERNAL} Storage Class29</A>30</b>31<br />32The bucket storage class determines how much it costs to store and access33your data, but has minimal impact on speed. You can change this later, but34the change only impacts newly saved data. With nearline, coldline and35archive storage classes, you have to pay to store any data for at least 3036days, 90 days, and 1 year, respectively.37<Alert38style={{ margin: "10px" }}39showIcon40type="info"41message={`Recommendation: Autoclass`}42description={43<>44Unless you understand why a different choice is better for your45data, use{" "}46<A href="https://cloud.google.com/storage/docs/autoclass">47autoclass48</A>49, because the management fee is minimal, there is no extra early50delete fee, and data you don't touch gets automatically stored51efficiently, down to a few dollars per TERABYTE after a year. Data52you frequently access costs the same as standard storage. The53monthly management fee is only{" "}54{currency(55markup({56cost: 2.5,57priceData,58}),59)}{" "}60per million blocks (there are 65,536 blocks of size 16 MB in 1 TB of61data).62</>63}64/>65<Select66style={{ width: "100%", marginTop: "5px", height: "auto" }}67options={GOOGLE_CLOUD_BUCKET_STORAGE_CLASSES.map(68(bucket_storage_class) => {69const { min, max } = getDataStoragePriceRange({70...configuration,71priceData,72bucket_storage_class,73});74return {75value: bucket_storage_class,76key: bucket_storage_class,77label: (78<div>79<div>80{GOOGLE_CLOUD_BUCKET_STORAGE_CLASSES_DESC[81bucket_storage_class82]?.desc ?? bucket_storage_class}83</div>84<div style={{ fontFamily: "monospace" }}>85{min ? currency(min, 5) : null}86{min != max && min && max ? ` - ${currency(max, 5)}` : null}87{min && max ? " per GB per month at rest" : null}88</div>89</div>90),91};92},93)}94value={configuration.bucket_storage_class}95onChange={(bucket_storage_class) =>96setConfiguration({ ...configuration, bucket_storage_class })97}98/>99{configuration.bucket_storage_class.includes("auto") && (100<Alert101style={{ margin: "10px 0" }}102showIcon103type="warning"104message={105<>106<A href="https://cloud.google.com/storage/docs/autoclass">107Autoclass buckets108</A>{" "}109incur a monthly management fee of{" "}110{currency(111markup({112cost: 2.5,113priceData,114}),115)}{" "}116for every million objects stored in them.117</>118}119/>120)}121</div>122);123}124125export function BucketLocation({ configuration, setConfiguration }) {126const [multiregion, setMultiregion] = useState<boolean>(127configuration.bucket_location &&128!configuration.bucket_location?.includes("-"),129);130const [priceData] = useGoogleCloudPriceData();131132const [recentRegions, setRecentRegions] = useState<string[] | null>(null);133useEffect(() => {134if (!configuration.project_id) return;135(async () => {136const recent = await getRecentRegions(configuration.project_id);137setRecentRegions(recent);138})();139}, [configuration.project_id]);140141useEffect(() => {142if (!configuration.bucket_location && recentRegions != null) {143let bucket_location;144if (multiregion) {145if (recentRegions[0]?.startsWith("europe")) {146bucket_location = "eu";147} else if (recentRegions[0]?.startsWith("asia")) {148bucket_location = "asia";149} else {150bucket_location = "us";151}152} else {153bucket_location =154recentRegions[0] ?? DEFAULT_CONFIGURATION.bucket_location;155}156setConfiguration({157...configuration,158bucket_location,159});160}161}, [recentRegions, configuration.bucket_location]);162163const options = useMemo(() => {164let regions = multiregion165? GOOGLE_CLOUD_MULTIREGIONS166: GOOGLE_CLOUD_REGIONS;167168if (multiregion) {169if (recentRegions?.[0]?.startsWith("europe")) {170regions = ["eu"].concat(regions.filter((x) => x != "eu"));171} else if (recentRegions?.[0]?.startsWith("asia")) {172regions = ["asia"].concat(regions.filter((x) => x != "asia"));173}174}175const options = regions.map((region) => {176let location;177const { min, max } = getDataStoragePriceRange({178...configuration,179priceData,180bucket_location: region,181});182if (multiregion) {183location = `${region.toUpperCase()} (Multiregion)`;184} else {185location = region;186}187const city = getCity({ region, priceData });188const label = (189<div style={{ display: "flex" }}>190<div style={{ flex: 0.6 }}>191{location} ({city})192</div>193<div style={{ flex: 1, fontFamily: "monospace" }}>194{min ? currency(min, 5) : null}195{min != max && min && max ? ` - ${currency(max, 5)}` : null}196{min && max ? " / GB / month at rest" : null}197</div>198</div>199);200return {201value: region,202label,203key: region,204price: { min, max },205search: `${city} ${location}`,206};207});208if (!multiregion && (recentRegions?.length ?? 0) > 0) {209const z = new Set(recentRegions);210const m: { [region: string]: any } = {};211for (const x of options) {212if (z.has(x.value)) {213m[x.value] = x;214}215}216const recent: any[] = [];217for (const region of recentRegions ?? []) {218recent.push({ ...m[region], key: `recent-${region}` });219}220221return [222{223label: "Your Recent Compute Servers are in These Regions",224options: recent,225},226{ label: "All Regions", options },227];228}229return options as any[];230}, [multiregion, priceData, configuration.bucket_storage_class]);231232return (233<div style={{ marginTop: "10px" }}>234<b style={{ fontSize: "13pt", color: "#666" }}>235<A href="https://cloud.google.com/storage/docs/locations">236{EXTERNAL} Location237</A>238</b>239{NO_CHANGE}240You can use your cloud file system from any compute server in the world,241in any cloud or self hosted. However, data transfer and operations are{" "}242<b>faster and cheaper</b> when the file system and compute server are in243the same region. <br />244<div style={{ display: "flex", margin: "10px 0" }}>245<Select246showSearch247style={{ flex: 1, width: "300px", marginTop: "5px" }}248options={options}249value={configuration.bucket_location}250onChange={(bucket_location) => {251setConfiguration({ ...configuration, bucket_location });252setMultiregion(!bucket_location?.includes("-"));253}}254optionFilterProp="children"255filterOption={filterOption}256/>257<div258style={{259display: "flex",260textAlign: "center",261alignItems: "center",262justifyContent: "center",263padding: "0 15px",264}}265>266<Checkbox267onChange={(e) => {268if (e.target.checked) {269setMultiregion(true);270setConfiguration({271...configuration,272bucket_location: "",273});274} else {275setMultiregion(false);276setConfiguration({277...configuration,278bucket_location: "",279});280}281}}282checked={multiregion}283>284<Icon name="global" /> Multiregion285</Checkbox>286</div>287</div>288</div>289);290}291292293