Skip to content

Commit 666b67a

Browse files
committed
refactoring snapshot info
1 parent 73f1db3 commit 666b67a

File tree

10 files changed

+190
-182
lines changed

10 files changed

+190
-182
lines changed

src/packages/backend/conat/test/files/file-server.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
client as createFileClient,
55
} from "@cocalc/conat/files/file-server";
66
import { uuid } from "@cocalc/util/misc";
7+
import { type SnapshotCounts } from "@cocalc/util/db-schema/projects";
78

89
beforeAll(before);
910

@@ -118,12 +119,7 @@ describe("create basic mocked file server and test it out", () => {
118119

119120
updateSnapshots: async (_opts: {
120121
project_id: string;
121-
counts?: {
122-
frequent?: number;
123-
daily?: number;
124-
weekly?: number;
125-
monthly?: number;
126-
};
122+
counts?: Partial<SnapshotCounts>;
127123
limit?: number;
128124
}): Promise<void> => {},
129125
});

src/packages/conat/files/file-server.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Additional functionality:
2323

2424
import { type Client } from "@cocalc/conat/core/client";
2525
import { conat } from "@cocalc/conat/client";
26+
import { type SnapshotCounts } from "@cocalc/util/db-schema/projects";
2627
import { type CopyOptions } from "./fs";
2728
export { type CopyOptions };
2829

@@ -102,12 +103,7 @@ export interface Fileserver {
102103
deleteSnapshot: (opts: { project_id: string; name: string }) => Promise<void>;
103104
updateSnapshots: (opts: {
104105
project_id: string;
105-
counts?: {
106-
frequent?: number;
107-
daily?: number;
108-
weekly?: number;
109-
monthly?: number;
110-
};
106+
counts?: Partial<SnapshotCounts>;
111107
// global limit, same as with createSnapshot above; can prevent new snapshots from being
112108
// made if counts are too large!
113109
limit?: number;

src/packages/conat/hub/api/projects.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { authFirstRequireAccount } from "./util";
2-
import { type CreateProjectOptions } from "@cocalc/util/db-schema/projects";
2+
import {
3+
type CreateProjectOptions,
4+
type SnapshotCounts,
5+
} from "@cocalc/util/db-schema/projects";
36
import { type CopyOptions } from "@cocalc/conat/files/fs";
47

58
export const projects = {
@@ -132,12 +135,7 @@ export interface Projects {
132135
updateSnapshots: (opts: {
133136
account_id?: string;
134137
project_id: string;
135-
counts?: {
136-
frequent?: number;
137-
daily?: number;
138-
weekly?: number;
139-
monthly?: number;
140-
};
138+
counts?: Partial<SnapshotCounts>;
141139
}) => Promise<void>;
142140

143141
getSnapshotQuota: (opts: {

src/packages/file-server/btrfs/snapshots.ts

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,17 @@
11
import { type SubvolumeSnapshots } from "./subvolume-snapshots";
2+
import {
3+
SNAPSHOT_INTERVALS_MS,
4+
DEFAULT_SNAPSHOT_COUNTS,
5+
type SnapshotCounts,
6+
} from "@cocalc/util/db-schema/projects";
27
import getLogger from "@cocalc/backend/logger";
38

9+
export { type SnapshotCounts };
10+
411
const logger = getLogger("file-server:btrfs:snapshots");
512

613
const DATE_REGEXP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
714

8-
// Lengths of time in minutes to keep snapshots
9-
// (code below assumes these are listed in ORDER from shortest to longest)
10-
export const SNAPSHOT_INTERVALS_MS = {
11-
frequent: 15 * 1000 * 60,
12-
daily: 60 * 24 * 1000 * 60,
13-
weekly: 60 * 24 * 7 * 1000 * 60,
14-
monthly: 60 * 24 * 7 * 4 * 1000 * 60,
15-
};
16-
17-
// How many of each type of snapshot to retain
18-
export const DEFAULT_SNAPSHOT_COUNTS = {
19-
frequent: 24,
20-
daily: 14,
21-
weekly: 7,
22-
monthly: 4,
23-
} as SnapshotCounts;
24-
25-
// We have at least one snapshot for each interval, assuming
26-
// there are actual changes since the last snapshot, and at
27-
// most the listed number.
28-
export interface SnapshotCounts {
29-
frequent: number;
30-
daily: number;
31-
weekly: number;
32-
monthly: number;
33-
}
34-
3515
export async function updateRollingSnapshots({
3616
snapshots,
3717
counts,

src/packages/frontend/project/snapshots.tsx renamed to src/packages/frontend/project/snapshots/create.tsx

Lines changed: 1 addition & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,8 @@ import { Icon } from "@cocalc/frontend/components/icon";
1414
import ShowError from "@cocalc/frontend/components/error";
1515
import { useProjectContext } from "@cocalc/frontend/project/context";
1616
import { webapp_client } from "@cocalc/frontend/webapp-client";
17-
import { delay } from "awaiting";
1817

19-
export default function Snapshots() {
20-
return (
21-
<Space.Compact>
22-
<CreateSnapshot />
23-
<EditSchedule />
24-
</Space.Compact>
25-
);
26-
}
27-
28-
function CreateSnapshot() {
18+
export default function CreateSnapshot() {
2919
const { actions, project_id } = useProjectContext();
3020
const [loading, setLoading] = useState<boolean>(false);
3121
const [open, setOpen] = useState<boolean>(false);
@@ -77,7 +67,6 @@ function CreateSnapshot() {
7767
afterOpenChange={async (open) => {
7868
if (!open) return;
7969
setName(new Date().toISOString());
80-
await delay(1);
8170
inputRef.current?.focus({
8271
cursor: "all",
8372
});
@@ -156,115 +145,3 @@ function CreateSnapshot() {
156145
</>
157146
);
158147
}
159-
160-
function EditSchedule() {
161-
const { actions, project_id } = useProjectContext();
162-
const [loading, setLoading] = useState<boolean>(false);
163-
const [open, setOpen] = useState<boolean>(false);
164-
const [name, setName] = useState<string>("");
165-
const [error, setError] = useState<string>("");
166-
const inputRef = useRef<InputRef>(null);
167-
168-
useEffect(() => {
169-
if (!open) {
170-
return;
171-
}
172-
actions?.setState({ disableExplorerKeyhandler: true });
173-
return () => {
174-
actions?.setState({ disableExplorerKeyhandler: false });
175-
};
176-
}, [open]);
177-
178-
if (!project_id) {
179-
return null;
180-
}
181-
182-
async function createSnapshot() {
183-
try {
184-
setLoading(true);
185-
setError("");
186-
await webapp_client.conat_client.hub.projects.createSnapshot({
187-
project_id,
188-
name,
189-
});
190-
setName("");
191-
setOpen(false);
192-
} catch (err) {
193-
setError(err);
194-
} finally {
195-
setLoading(false);
196-
}
197-
}
198-
199-
return (
200-
<>
201-
<Button
202-
disabled={open}
203-
onClick={() => {
204-
setOpen(!open);
205-
}}
206-
>
207-
<Icon name="clock" /> Schedule
208-
</Button>
209-
<Modal
210-
afterOpenChange={(open) => {
211-
if (!open) return;
212-
setName(new Date().toISOString());
213-
inputRef.current?.focus({
214-
cursor: "all",
215-
});
216-
}}
217-
title={
218-
<>
219-
<Icon name="clock" /> Edit Schedule{" "}
220-
{loading && <Spin style={{ float: "right" }} />}
221-
</>
222-
}
223-
open={open}
224-
onOk={() => {
225-
setName("");
226-
setOpen(false);
227-
}}
228-
onCancel={() => {
229-
setName("");
230-
setOpen(false);
231-
}}
232-
footer={[
233-
<Button
234-
key="cancel"
235-
onClick={() => {
236-
setOpen(false);
237-
setName("");
238-
}}
239-
>
240-
Cancel
241-
</Button>,
242-
<Button
243-
key="create"
244-
type="primary"
245-
onClick={createSnapshot}
246-
disabled={!name.trim()}
247-
>
248-
Create Snapshot
249-
</Button>,
250-
]}
251-
>
252-
<Flex style={{ width: "100%" }}>
253-
<Input
254-
ref={inputRef}
255-
style={{ flex: 1 }}
256-
value={name}
257-
onChange={(e) => setName(e.target.value)}
258-
placeholder="Name of snapshot..."
259-
onPressEnter={createSnapshot}
260-
/>
261-
</Flex>
262-
<ShowError
263-
style={{ marginTop: "10px" }}
264-
error={error}
265-
setError={setError}
266-
/>
267-
</Modal>
268-
</>
269-
);
270-
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { useEffect, useRef, useState } from "react";
2+
import { Button, Flex, Input, Modal, Space, Spin } from "antd";
3+
import { Icon } from "@cocalc/frontend/components/icon";
4+
import ShowError from "@cocalc/frontend/components/error";
5+
import { useProjectContext } from "@cocalc/frontend/project/context";
6+
import { webapp_client } from "@cocalc/frontend/webapp-client";
7+
8+
export default function EditSchedule() {
9+
const { actions, project_id } = useProjectContext();
10+
const [loading, setLoading] = useState<boolean>(false);
11+
const [open, setOpen] = useState<boolean>(false);
12+
const [error, setError] = useState<string>("");
13+
14+
useEffect(() => {
15+
if (!open) {
16+
return;
17+
}
18+
actions?.setState({ disableExplorerKeyhandler: true });
19+
return () => {
20+
actions?.setState({ disableExplorerKeyhandler: false });
21+
};
22+
}, [open]);
23+
24+
if (!project_id) {
25+
return null;
26+
}
27+
28+
async function setSchedule() {
29+
try {
30+
setLoading(true);
31+
setError("");
32+
await webapp_client.conat_client.hub.projects.createSnapshot({
33+
project_id,
34+
name,
35+
});
36+
setName("");
37+
setOpen(false);
38+
} catch (err) {
39+
setError(err);
40+
} finally {
41+
setLoading(false);
42+
}
43+
}
44+
45+
return (
46+
<>
47+
<Button
48+
disabled={open}
49+
onClick={() => {
50+
setOpen(!open);
51+
}}
52+
>
53+
<Icon name="clock" /> Schedule
54+
</Button>
55+
<Modal
56+
afterOpenChange={(open) => {
57+
if (!open) return;
58+
setName(new Date().toISOString());
59+
inputRef.current?.focus({
60+
cursor: "all",
61+
});
62+
}}
63+
title={
64+
<>
65+
<Icon name="clock" /> Edit Schedule{" "}
66+
{loading && <Spin style={{ float: "right" }} />}
67+
</>
68+
}
69+
open={open}
70+
onOk={() => {
71+
setName("");
72+
setOpen(false);
73+
}}
74+
onCancel={() => {
75+
setName("");
76+
setOpen(false);
77+
}}
78+
footer={[
79+
<Button
80+
key="cancel"
81+
onClick={() => {
82+
setOpen(false);
83+
setName("");
84+
}}
85+
>
86+
Cancel
87+
</Button>,
88+
<Button
89+
key="create"
90+
type="primary"
91+
onClick={createSnapshot}
92+
disabled={!name.trim()}
93+
>
94+
Create Snapshot
95+
</Button>,
96+
]}
97+
>
98+
<Flex style={{ width: "100%" }}>
99+
<Input
100+
ref={inputRef}
101+
style={{ flex: 1 }}
102+
value={name}
103+
onChange={(e) => setName(e.target.value)}
104+
placeholder="Name of snapshot..."
105+
onPressEnter={createSnapshot}
106+
/>
107+
</Flex>
108+
<ShowError
109+
style={{ marginTop: "10px" }}
110+
error={error}
111+
setError={setError}
112+
/>
113+
</Modal>
114+
</>
115+
);
116+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
The Snapshots button pops up a model that let you:
3+
4+
- create a new snapshot
5+
- edit the automatic snapshot schedule
6+
*/
7+
8+
import { Space } from "antd";
9+
import CreateSnapshot from "./create";
10+
import EditSchedule from "./edit-schedule";
11+
12+
export default function Snapshots() {
13+
return (
14+
<Space.Compact>
15+
<CreateSnapshot />
16+
<EditSchedule />
17+
</Space.Compact>
18+
);
19+
}

0 commit comments

Comments
 (0)