Skip to content

Commit 06ac987

Browse files
committed
Merge branch '657-display-all-branches' into 'master'
feat: display all branches including ambiguous ones and filter snapshots by dataset (#657) Closes #657 See merge request postgres-ai/database-lab!1059
2 parents f259f8b + e9faee8 commit 06ac987

File tree

12 files changed

+104
-33
lines changed

12 files changed

+104
-33
lines changed

engine/internal/provision/thinclones/zfs/branching.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,13 +267,15 @@ func (m *Manager) ListAllBranches(poolList []string) ([]models.BranchEntity, err
267267
continue
268268
}
269269

270+
dataset := branching.ParseBaseDatasetFromSnapshot(fields[1])
271+
270272
if !strings.Contains(fields[0], branchSep) {
271-
branches = append(branches, models.BranchEntity{Name: fields[0], SnapshotID: fields[1]})
273+
branches = append(branches, models.BranchEntity{Name: fields[0], Dataset: dataset, SnapshotID: fields[1]})
272274
continue
273275
}
274276

275277
for _, branchName := range strings.Split(fields[0], branchSep) {
276-
branches = append(branches, models.BranchEntity{Name: branchName, SnapshotID: fields[1]})
278+
branches = append(branches, models.BranchEntity{Name: branchName, Dataset: dataset, SnapshotID: fields[1]})
277279
}
278280
}
279281

engine/internal/srv/branch.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,6 @@ func (s *Server) listBranches(w http.ResponseWriter, r *http.Request) {
4747

4848
branchDetails := make([]models.BranchView, 0, len(branches))
4949

50-
// branchRegistry is used to display the "main" branch with only the most recent snapshot.
51-
branchRegistry := make(map[string]int, 0)
52-
5350
for _, branchEntity := range branches {
5451
snapshotDetails, ok := repo.Snapshots[branchEntity.SnapshotID]
5552
if !ok {
@@ -60,22 +57,14 @@ func (s *Server) listBranches(w http.ResponseWriter, r *http.Request) {
6057

6158
branchView := models.BranchView{
6259
Name: branchEntity.Name,
60+
BaseDataset: branchEntity.Dataset,
6361
Parent: parentSnapshot,
6462
DataStateAt: snapshotDetails.DataStateAt,
6563
SnapshotID: snapshotDetails.ID,
6664
Dataset: snapshotDetails.Dataset,
6765
NumSnapshots: numSnapshots,
6866
}
6967

70-
if position, ok := branchRegistry[branchEntity.Name]; ok {
71-
if branchView.DataStateAt > branchDetails[position].DataStateAt {
72-
branchDetails[position] = branchView
73-
}
74-
75-
continue
76-
}
77-
78-
branchRegistry[branchView.Name] = len(branchDetails)
7968
branchDetails = append(branchDetails, branchView)
8069
}
8170

@@ -136,15 +125,36 @@ func containsString(slice []string, s string) bool {
136125
}
137126

138127
func (s *Server) getFSManagerForBranch(branchName string) (pool.FSManager, error) {
128+
return s.getFSManagerForBranchAndDataset(branchName, "")
129+
}
130+
131+
func (s *Server) getFSManagerForBranchAndDataset(branchName, dataset string) (pool.FSManager, error) {
139132
allBranches, err := s.getAllAvailableBranches(s.pm.First())
140133
if err != nil {
141134
return nil, fmt.Errorf("failed to get branch list: %w", err)
142135
}
143136

144137
for _, branchEntity := range allBranches {
145-
if branchEntity.Name == branchName { // TODO: filter by pool name as well because branch name is ambiguous.
138+
if branchEntity.Name != branchName {
139+
continue
140+
}
141+
142+
if dataset == "" {
146143
return s.getFSManagerForSnapshot(branchEntity.SnapshotID)
147144
}
145+
146+
fsm, err := s.getFSManagerForSnapshot(branchEntity.SnapshotID)
147+
if err != nil {
148+
continue
149+
}
150+
151+
if fsm.Pool().Name == dataset {
152+
return fsm, nil
153+
}
154+
}
155+
156+
if dataset != "" {
157+
return nil, fmt.Errorf("failed to find dataset %s of the branch: %s", dataset, branchName)
148158
}
149159

150160
return nil, fmt.Errorf("failed to found dataset of the branch: %s", branchName)
@@ -469,6 +479,18 @@ func filterSnapshotsByBranch(pool *resources.Pool, branch string, snapshots []mo
469479
return filtered
470480
}
471481

482+
func filterSnapshotsByDataset(dataset string, snapshots []models.Snapshot) []models.Snapshot {
483+
filtered := make([]models.Snapshot, 0)
484+
485+
for _, sn := range snapshots {
486+
if sn.Pool == dataset {
487+
filtered = append(filtered, sn)
488+
}
489+
}
490+
491+
return filtered
492+
}
493+
472494
func (s *Server) log(w http.ResponseWriter, r *http.Request) {
473495
branchName := mux.Vars(r)["branchName"]
474496

engine/internal/srv/routes.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,11 @@ func (s *Server) getSnapshots(w http.ResponseWriter, r *http.Request) {
108108
return
109109
}
110110

111-
if branchRequest := r.URL.Query().Get("branch"); branchRequest != "" {
112-
fsm, err := s.getFSManagerForBranch(branchRequest)
111+
branchRequest := r.URL.Query().Get("branch")
112+
datasetRequest := r.URL.Query().Get("dataset")
113+
114+
if branchRequest != "" {
115+
fsm, err := s.getFSManagerForBranchAndDataset(branchRequest, datasetRequest)
113116
if err != nil {
114117
api.SendBadRequestError(w, r, err.Error())
115118
return
@@ -123,6 +126,10 @@ func (s *Server) getSnapshots(w http.ResponseWriter, r *http.Request) {
123126
snapshots = filterSnapshotsByBranch(fsm.Pool(), branchRequest, snapshots)
124127
}
125128

129+
if branchRequest == "" && datasetRequest != "" {
130+
snapshots = filterSnapshotsByDataset(datasetRequest, snapshots)
131+
}
132+
126133
if err = api.WriteJSON(w, http.StatusOK, snapshots); err != nil {
127134
api.SendError(w, r, err)
128135
return

engine/pkg/models/branch.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type SnapshotDetails struct {
3535
// BranchView describes branch view.
3636
type BranchView struct {
3737
Name string `json:"name"`
38+
BaseDataset string `json:"baseDataset"`
3839
Parent string `json:"parent"`
3940
DataStateAt string `json:"dataStateAt"`
4041
SnapshotID string `json:"snapshotID"`
@@ -45,5 +46,6 @@ type BranchView struct {
4546
// BranchEntity defines a branch-snapshot pair.
4647
type BranchEntity struct {
4748
Name string
49+
Dataset string
4850
SnapshotID string
4951
}

engine/pkg/util/branching/branching.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,15 @@ func ParseBranchNameFromSnapshot(snapshot, poolName string) string {
117117

118118
return branch
119119
}
120+
121+
// ParseBaseDatasetFromSnapshot parses base dataset from the snapshot ID.
122+
func ParseBaseDatasetFromSnapshot(snapshot string) string {
123+
fullDataset, _, found := strings.Cut(snapshot, "@")
124+
if !found {
125+
return ""
126+
}
127+
128+
dataset, _, _ := strings.Cut(fullDataset, "/"+BranchDir+"/")
129+
130+
return dataset
131+
}

ui/packages/ce/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@postgres.ai/ce",
3-
"version": "4.0.1",
3+
"version": "4.0.2",
44
"private": true,
55
"dependencies": {
66
"@craco/craco": "^6.4.3",

ui/packages/ce/src/api/snapshots/getSnapshots.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ import {
1313
import { request } from 'helpers/request'
1414

1515
export const getSnapshots: GetSnapshots = async (req) => {
16-
const url = `/snapshots${req.branchName ? `?branch=${req.branchName}` : ''}`;
16+
const params = new URLSearchParams()
17+
if (req.branchName) {
18+
params.append('branch', req.branchName)
19+
}
20+
if (req.dataset) {
21+
params.append('dataset', req.dataset)
22+
}
23+
const url = `/snapshots${params.toString() ? `?${params.toString()}` : ''}`;
1724
const response = await request(url);
1825

1926
return {

ui/packages/shared/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@postgres.ai/shared",
3-
"version": "4.0.1",
3+
"version": "4.0.2",
44
"scripts": {
55
"build": "tsc -p tsconfig.build.json && node scripts/copy-assets.js",
66
"pack": "node scripts/pack.js"

ui/packages/shared/pages/CreateBranch/index.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export const CreateBranchPage = observer(
107107
const classes = useStyles()
108108
const history = useHistory()
109109
const [branchSnapshots, setBranchSnapshots] = useState<Snapshot[]>([])
110+
const [selectedBranchKey, setSelectedBranchKey] = useState<string>('main|')
110111

111112
const {
112113
load,
@@ -131,8 +132,8 @@ export const CreateBranchPage = observer(
131132
})
132133
}
133134

134-
const fetchSnapshots = async (branchName: string) => {
135-
await getSnapshots(instanceId, branchName).then((response) => {
135+
const fetchSnapshots = async (branchName: string, dataset?: string) => {
136+
await getSnapshots(instanceId, branchName, dataset).then((response) => {
136137
if (response) {
137138
setBranchSnapshots(response)
138139
formik.setFieldValue('snapshotID', response[0]?.id)
@@ -143,17 +144,28 @@ export const CreateBranchPage = observer(
143144
const handleParentBranchChange = async (
144145
e: React.ChangeEvent<HTMLInputElement>,
145146
) => {
146-
const branchName = e.target.value
147+
const compositeKey = e.target.value
148+
const [branchName, dataset] = compositeKey.split('|')
149+
150+
setSelectedBranchKey(compositeKey)
147151
formik.setFieldValue('baseBranch', branchName)
148-
await fetchSnapshots(branchName)
152+
await fetchSnapshots(branchName, dataset)
149153
}
150154

151155
const [{ formik }] = useForm(handleSubmit)
152156

153-
useEffect(() => {
154-
load(instanceId)
155-
fetchSnapshots(formik.values.baseBranch)
156-
}, [formik.values.baseBranch])
157+
useEffect(() => {
158+
load(instanceId);
159+
}, [instanceId]);
160+
161+
useEffect(() => {
162+
if (!branchesList?.length) return;
163+
const selected = branchesList.find(b => b.name === formik.values.baseBranch);
164+
if (!selected) return;
165+
const compositeKey = `${selected.name}|${selected.baseDataset || ''}`;
166+
setSelectedBranchKey(compositeKey);
167+
fetchSnapshots(selected.name, selected.baseDataset);
168+
}, [branchesList]);
157169

158170
if (isBranchesLoading) {
159171
return <StubSpinner />
@@ -207,16 +219,20 @@ export const CreateBranchPage = observer(
207219
<Select
208220
fullWidth
209221
label="Parent branch"
210-
value={formik.values.baseBranch}
222+
value={selectedBranchKey}
211223
disabled={!branchesList || formik.isSubmitting}
212224
onChange={handleParentBranchChange}
213225
error={Boolean(formik.errors.baseBranch)}
214226
items={
215227
branchesList
216228
? branchesList.map((branch) => {
229+
const displayName = branch.baseDataset
230+
? `${branch.name} (${branch.baseDataset})`
231+
: branch.name
232+
const compositeValue = `${branch.name}|${branch.baseDataset || ''}`
217233
return {
218-
value: branch.name,
219-
children: branch.name,
234+
value: compositeValue,
235+
children: displayName,
220236
}
221237
})
222238
: []

ui/packages/shared/pages/CreateBranch/stores/Main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,13 @@ export class MainStore {
8181
return response
8282
}
8383

84-
getSnapshots = async (instanceId: string, branchName?: string) => {
84+
getSnapshots = async (instanceId: string, branchName?: string, dataset?: string) => {
8585
if (!this.api.getSnapshots) return
8686

8787
const { response, error } = await this.api.getSnapshots({
8888
instanceId,
8989
branchName,
90+
dataset,
9091
})
9192

9293
if (error) {

0 commit comments

Comments
 (0)