• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / d-installer / 4512499803

pending completion
4512499803

Pull #501

github

Unknown Committer
Unknown Commit Message
Pull Request #501: [web] Add DASD UI - first version

462 of 863 branches covered (53.53%)

Branch coverage included in aggregate %.

64 of 235 new or added lines in 9 files covered. (27.23%)

14 existing lines in 1 file now uncovered.

4668 of 6129 relevant lines covered (76.16%)

10.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.17
/web/src/components/storage/DASDPage.jsx
1
/*
2
 * Copyright (c) [2023] SUSE LLC
3
 *
4
 * All Rights Reserved.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of version 2 of the GNU General Public License as published
8
 * by the Free Software Foundation.
9
 *
10
 * This program is distributed in the hope that it will be useful, but WITHOUT
11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13
 * more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, contact SUSE LLC.
17
 *
18
 * To contact SUSE LLC about this file by physical or electronic mail, you may
19
 * find current contact information at www.suse.com.
20
 */
21

22
import React, { useEffect, useReducer } from "react";
23
import { useNavigate } from "react-router-dom";
24
import { Button } from "@patternfly/react-core";
25
import { MainActions } from "~/components/layout";
26
import { If, Page } from "~/components/core";
27
import { DASDFormatProgress, DASDTable } from "~/components/storage";
28
import { useCancellablePromise } from "~/utils";
29
import { useInstallerClient } from "~/context/installer";
30

31
const reducer = (state, action) => {
14✔
NEW
32
  const { type, payload } = action;
×
33

NEW
34
  switch (type) {
×
35
    case "SET_DEVICES": {
NEW
36
      return { ...state, devices: payload.devices };
×
37
    }
38

39
    case "ADD_DEVICE": {
NEW
40
      const { device } = payload;
×
NEW
41
      if (state.devices.find(d => d.id === device.id)) return state;
×
42

NEW
43
      return { ...state, devices: [...state.devices, device] };
×
44
    }
45

46
    case "UPDATE_DEVICE": {
NEW
47
      const { device } = payload;
×
NEW
48
      const index = state.devices.findIndex(d => d.id === device.id);
×
NEW
49
      const devices = [...state.devices];
×
NEW
50
      index !== -1 ? devices[index] = device : devices.push(device);
×
51

NEW
52
      const selectedDevicesIds = state.selectedDevices.map(d => d.id);
×
NEW
53
      const selectedDevices = devices.filter(d => selectedDevicesIds.includes(d.id));
×
54

NEW
55
      return { ...state, devices, selectedDevices };
×
56
    }
57

58
    case "REMOVE_DEVICE": {
NEW
59
      const { device } = payload;
×
60

NEW
61
      return { ...state, devices: state.devices.filter(d => d.id !== device.id) };
×
62
    }
63

64
    case "SET_MIN_CHANNEL": {
NEW
65
      return { ...state, minChannel: payload.minChannel, selectedDevices: [] };
×
66
    }
67

68
    case "SET_MAX_CHANNEL": {
NEW
69
      return { ...state, maxChannel: payload.maxChannel, selectedDevices: [] };
×
70
    }
71

72
    case "SELECT_DEVICE": {
NEW
73
      const { device } = payload;
×
74

NEW
75
      return { ...state, selectedDevices: [...state.selectedDevices, device] };
×
76
    }
77

78
    case "UNSELECT_DEVICE": {
NEW
79
      const { device } = payload;
×
80

NEW
81
      return { ...state, selectedDevices: state.selectedDevices.filter(d => d.id !== device.id) };
×
82
    }
83

84
    case "SELECT_ALL_DEVICES": {
NEW
85
      return { ...state, selectedDevices: payload.devices };
×
86
    }
87

88
    case "UNSELECT_ALL_DEVICES": {
NEW
89
      return { ...state, selectedDevices: [] };
×
90
    }
91

92
    case "START_FORMAT_JOB": {
NEW
93
      const { data: formatJob } = payload;
×
94

NEW
95
      if (!formatJob.running) return state;
×
NEW
96
      const newState = { ...state, formatJob };
×
97

NEW
98
      return newState;
×
99
    }
100

101
    case "UPDATE_FORMAT_JOB": {
NEW
102
      const { data: formatJob } = payload;
×
103

NEW
104
      if (formatJob.path !== state.formatJob.path) return state;
×
105

NEW
106
      return { ...state, formatJob };
×
107
    }
108

109
    case "START_LOADING": {
NEW
110
      return { ...state, isLoading: true };
×
111
    }
112

113
    case "STOP_LOADING": {
NEW
114
      return { ...state, isLoading: false };
×
115
    }
116

117
    default: {
NEW
118
      return state;
×
119
    }
120
  }
121
};
122

123
const initialState = {
14✔
124
  devices: [],
125
  selectedDevices: [],
126
  minChannel: "",
127
  maxChannel: "",
128
  isLoading: true,
129
  formatJob: {},
130
};
131

132
export default function DASDPage() {
NEW
133
  const { storage: client } = useInstallerClient();
×
NEW
134
  const navigate = useNavigate();
×
NEW
135
  const { cancellablePromise } = useCancellablePromise();
×
NEW
136
  const [state, dispatch] = useReducer(reducer, initialState);
×
137

NEW
138
  useEffect(() => {
×
NEW
139
    const loadDevices = async () => {
×
NEW
140
      dispatch({ type: "START_LOADING" });
×
NEW
141
      const devices = await cancellablePromise(client.dasd.getDevices());
×
NEW
142
      dispatch({ type: "SET_DEVICES", payload: { devices } });
×
NEW
143
      dispatch({ type: "STOP_LOADING" });
×
144
    };
145

NEW
146
    const loadJobs = async () => {
×
NEW
147
      const jobs = await cancellablePromise(client.dasd.getJobs());
×
NEW
148
      if (jobs.length > 0) {
×
NEW
149
        dispatch({ type: "START_FORMAT_JOB", payload: { data: jobs[0] } });
×
150
      }
151
    };
152

NEW
153
    loadDevices().catch(console.error);
×
NEW
154
    loadJobs().catch(console.error);
×
155
  }, [client.dasd, cancellablePromise]);
156

NEW
157
  useEffect(() => {
×
NEW
158
    const subscriptions = [];
×
159

NEW
160
    const subscribe = async () => {
×
NEW
161
      const action = (type, device) => dispatch({ type, payload: { device } });
×
162

NEW
163
      subscriptions.push(
×
NEW
164
        await client.dasd.deviceEventListener("added", d => action("ADD_DEVICE", d)),
×
NEW
165
        await client.dasd.deviceEventListener("removed", d => action("REMOVE_DEVICE", d)),
×
NEW
166
        await client.dasd.deviceEventListener("changed", d => action("UPDATE_DEVICE", d))
×
167
      );
168

NEW
169
      await client.dasd.onJobAdded((data) => dispatch({ type: "START_FORMAT_JOB", payload: { data } }));
×
NEW
170
      await client.dasd.onJobChanged((data) => dispatch({ type: "UPDATE_FORMAT_JOB", payload: { data } }));
×
171
    };
172

NEW
173
    const unsubscribe = () => {
×
NEW
174
      subscriptions.forEach(fn => fn());
×
175
    };
176

NEW
177
    subscribe();
×
NEW
178
    return unsubscribe;
×
179
  }, [client.dasd]);
180

NEW
181
  return (
×
182
    <Page title="Storage DASD" icon="hard_drive">
183
      <MainActions>
NEW
184
        <Button isLarge variant="secondary" onClick={() => navigate("/storage")}>Back</Button>
×
185
      </MainActions>
186

187
      <DASDTable state={state} dispatch={dispatch} />
188

189
      <If
190
        condition={state.formatJob.running}
191
        then={<DASDFormatProgress job={state.formatJob} devices={state.devices} />}
192
      />
193
    </Page>
194
  );
195
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc