fix(pve): Fix connection issues and add more error handlings (#1081)
* feat(PVE): Added display of PVE connection loading steps Added a detailed display of loading steps during the PVE connection process, including stages such as establishing an SSH tunnel, authentication, and data retrieval Also optimized the sorting of PVE storage content and the logic for handling connection errors * feat(pve): Added error handling and prompts for PVE two-factor authentication Added error handling for PVE servers when two-factor authentication is enabled, along with relevant error types and localized prompts * feat(PVE): Added support for PVE passwords during key-based authentication - Added the `pvePwd` field to the `ServerCustom` model - Added a PVE password input field to the edit page (displayed only during key-based authentication) - Updated multilingual files to support PVE-related loading states and password prompts - Optimized PVE connection logic to support password verification during key-based authentication
This commit is contained in:
@@ -56,7 +56,7 @@ class WebdavErr extends Err<WebdavErrType> {
|
||||
String? get solution => null;
|
||||
}
|
||||
|
||||
enum PveErrType { unknown, net, loginFailed }
|
||||
enum PveErrType { unknown, net, loginFailed, needTfa }
|
||||
|
||||
class PveErr extends Err<PveErrType> {
|
||||
const PveErr({required super.type, super.message});
|
||||
|
||||
@@ -11,6 +11,8 @@ final class ServerCustom {
|
||||
|
||||
final bool pveIgnoreCert;
|
||||
|
||||
final String? pvePwd;
|
||||
|
||||
/// {"title": "cmd"}
|
||||
final Map<String, String>? cmds;
|
||||
|
||||
@@ -28,6 +30,7 @@ final class ServerCustom {
|
||||
//this.temperature,
|
||||
this.pveAddr,
|
||||
this.pveIgnoreCert = false,
|
||||
this.pvePwd,
|
||||
this.cmds,
|
||||
this.preferTempDev,
|
||||
this.logoUrl,
|
||||
@@ -45,6 +48,7 @@ final class ServerCustom {
|
||||
//other.temperature == temperature &&
|
||||
other.pveAddr == pveAddr &&
|
||||
other.pveIgnoreCert == pveIgnoreCert &&
|
||||
other.pvePwd == pvePwd &&
|
||||
other.cmds == cmds &&
|
||||
other.preferTempDev == preferTempDev &&
|
||||
other.logoUrl == logoUrl &&
|
||||
@@ -57,6 +61,7 @@ final class ServerCustom {
|
||||
//temperature.hashCode ^
|
||||
pveAddr.hashCode ^
|
||||
pveIgnoreCert.hashCode ^
|
||||
pvePwd.hashCode ^
|
||||
cmds.hashCode ^
|
||||
preferTempDev.hashCode ^
|
||||
logoUrl.hashCode ^
|
||||
|
||||
@@ -9,6 +9,7 @@ part of 'custom.dart';
|
||||
ServerCustom _$ServerCustomFromJson(Map<String, dynamic> json) => ServerCustom(
|
||||
pveAddr: json['pveAddr'] as String?,
|
||||
pveIgnoreCert: json['pveIgnoreCert'] as bool? ?? false,
|
||||
pvePwd: json['pvePwd'] as String?,
|
||||
cmds: (json['cmds'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, e as String),
|
||||
),
|
||||
@@ -22,6 +23,7 @@ Map<String, dynamic> _$ServerCustomToJson(ServerCustom instance) =>
|
||||
<String, dynamic>{
|
||||
'pveAddr': ?instance.pveAddr,
|
||||
'pveIgnoreCert': instance.pveIgnoreCert,
|
||||
'pvePwd': ?instance.pvePwd,
|
||||
'cmds': ?instance.cmds,
|
||||
'preferTempDev': ?instance.preferTempDev,
|
||||
'logoUrl': ?instance.logoUrl,
|
||||
|
||||
@@ -293,6 +293,10 @@ final class PveStorage extends PveResIface implements PveCtrlIface {
|
||||
});
|
||||
|
||||
static PveStorage fromJson(Map<String, dynamic> json) {
|
||||
final rawContent = json['content'] as String?;
|
||||
final contentParts = rawContent?.split(',');
|
||||
contentParts?.sort();
|
||||
final content = contentParts?.join(',') ?? rawContent ?? '';
|
||||
return PveStorage(
|
||||
id: json['id'],
|
||||
type: PveResType.storage,
|
||||
@@ -300,7 +304,7 @@ final class PveStorage extends PveResIface implements PveCtrlIface {
|
||||
node: json['node'],
|
||||
status: json['status'],
|
||||
plugintype: json['plugintype'],
|
||||
content: json['content'],
|
||||
content: content,
|
||||
shared: json['shared'],
|
||||
disk: json['disk'],
|
||||
maxdisk: json['maxdisk'],
|
||||
|
||||
@@ -58,7 +58,7 @@ final class ContainerNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$containerNotifierHash() => r'85457ec75264199c284572ee45beeaccba2044a1';
|
||||
String _$containerNotifierHash() => r'2f8eb969f0e66e28f60b6fc11169e8f28315ed32';
|
||||
|
||||
final class ContainerNotifierFamily extends $Family
|
||||
with
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:dio/io.dart';
|
||||
import 'package:fl_lib/fl_lib.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:server_box/core/extension/context/locale.dart';
|
||||
import 'package:server_box/data/model/app/error.dart';
|
||||
import 'package:server_box/data/model/server/pve.dart';
|
||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||
@@ -19,6 +18,13 @@ part 'pve.g.dart';
|
||||
|
||||
typedef PveCtrlFunc = Future<bool> Function(String node, String id);
|
||||
|
||||
enum PveLoadingStep {
|
||||
none,
|
||||
forwarding,
|
||||
loggingIn,
|
||||
fetchingData,
|
||||
}
|
||||
|
||||
@freezed
|
||||
abstract class PveState with _$PveState {
|
||||
const factory PveState({
|
||||
@@ -27,43 +33,51 @@ abstract class PveState with _$PveState {
|
||||
@Default(null) String? release,
|
||||
@Default(false) bool isBusy,
|
||||
@Default(false) bool isConnected,
|
||||
@Default(PveLoadingStep.none) PveLoadingStep loadingStep,
|
||||
}) = _PveState;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class PveNotifier extends _$PveNotifier {
|
||||
late final Spi spi;
|
||||
late String addr;
|
||||
late final SSHClient _client;
|
||||
late final ServerSocket _serverSocket;
|
||||
String? addr;
|
||||
ServerSocket? _serverSocket;
|
||||
final List<SSHForwardChannel> _forwards = [];
|
||||
int _localPort = 0;
|
||||
late final Dio session;
|
||||
late final bool _ignoreCert;
|
||||
Dio? _session;
|
||||
bool _ignoreCert = false;
|
||||
|
||||
Dio get session => _session!;
|
||||
String get addrValue => addr!;
|
||||
|
||||
SSHClient get _client {
|
||||
final serverState = ref.read(serverProvider(spiParam.id));
|
||||
final client = serverState.client;
|
||||
if (client == null) {
|
||||
throw PveErr(type: PveErrType.net, message: 'Server client is null');
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
@override
|
||||
PveState build(Spi spiParam) {
|
||||
spi = spiParam;
|
||||
final serverState = ref.watch(serverProvider(spi.id));
|
||||
final client = serverState.client;
|
||||
if (client == null) {
|
||||
return const PveState(error: PveErr(type: PveErrType.net, message: 'Server client is null'));
|
||||
ref.onDispose(() => dispose());
|
||||
final serverState = ref.watch(serverProvider(spiParam.id));
|
||||
if (serverState.client == null) {
|
||||
return const PveState(loadingStep: PveLoadingStep.forwarding);
|
||||
}
|
||||
_client = client;
|
||||
final addr = spi.custom?.pveAddr;
|
||||
if (addr == null) {
|
||||
final pveAddr = spiParam.custom?.pveAddr;
|
||||
if (pveAddr == null) {
|
||||
return PveState(error: PveErr(type: PveErrType.net, message: 'PVE address is null'));
|
||||
}
|
||||
this.addr = addr;
|
||||
_ignoreCert = spi.custom?.pveIgnoreCert ?? false;
|
||||
addr = pveAddr;
|
||||
_ignoreCert = spiParam.custom?.pveIgnoreCert ?? false;
|
||||
_initSession();
|
||||
// Async initialization
|
||||
Future.microtask(() => _init());
|
||||
return const PveState();
|
||||
return const PveState(loadingStep: PveLoadingStep.forwarding);
|
||||
}
|
||||
|
||||
void _initSession() {
|
||||
session = Dio()
|
||||
_session = Dio()
|
||||
..httpClientAdapter = IOHttpClientAdapter(
|
||||
createHttpClient: () {
|
||||
final client = HttpClient();
|
||||
@@ -79,35 +93,53 @@ class PveNotifier extends _$PveNotifier {
|
||||
|
||||
bool get onlyOneNode => state.data?.nodes.length == 1;
|
||||
|
||||
Future<void> reconnect() async {
|
||||
state = state.copyWith(error: null, isConnected: false, loadingStep: PveLoadingStep.forwarding);
|
||||
await _init();
|
||||
}
|
||||
|
||||
Future<void> _init() async {
|
||||
try {
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(loadingStep: PveLoadingStep.forwarding);
|
||||
await _forward();
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(loadingStep: PveLoadingStep.loggingIn);
|
||||
await _login();
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(loadingStep: PveLoadingStep.fetchingData);
|
||||
await _getRelease();
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(isConnected: true);
|
||||
} on PveErr {
|
||||
state = state.copyWith(error: PveErr(type: PveErrType.loginFailed, message: l10n.pveLoginFailed));
|
||||
await list();
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(loadingStep: PveLoadingStep.none);
|
||||
} on PveErr catch (e) {
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(error: e, loadingStep: PveLoadingStep.none);
|
||||
} catch (e, s) {
|
||||
if (!ref.mounted) return;
|
||||
Loggers.app.warning('PVE init failed', e, s);
|
||||
state = state.copyWith(error: PveErr(type: PveErrType.unknown, message: e.toString()));
|
||||
state = state.copyWith(error: PveErr(type: PveErrType.unknown, message: e.toString()), loadingStep: PveLoadingStep.none);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _forward() async {
|
||||
final url = Uri.parse(addr);
|
||||
final url = Uri.parse(addrValue);
|
||||
if (_localPort == 0) {
|
||||
_serverSocket = await ServerSocket.bind('localhost', 0);
|
||||
_localPort = _serverSocket.port;
|
||||
_serverSocket.listen((socket) async {
|
||||
final forward = await _client.forwardLocal(url.host, url.port);
|
||||
_forwards.add(forward);
|
||||
forward.stream.cast<List<int>>().pipe(socket);
|
||||
socket.cast<List<int>>().pipe(forward.sink);
|
||||
_localPort = _serverSocket!.port;
|
||||
_serverSocket!.listen((socket) async {
|
||||
try {
|
||||
final forward = await _client.forwardLocal(url.host, url.port);
|
||||
_forwards.add(forward);
|
||||
forward.stream.cast<List<int>>().pipe(socket);
|
||||
socket.cast<List<int>>().pipe(forward.sink);
|
||||
} catch (e, s) {
|
||||
Loggers.app.warning('PVE forward failed', e, s);
|
||||
socket.destroy();
|
||||
}
|
||||
});
|
||||
final newUrl = Uri.parse(
|
||||
addr,
|
||||
).replace(host: 'localhost', port: _localPort).toString();
|
||||
dprint('Forwarding $newUrl to $addr');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,15 +148,6 @@ class PveNotifier extends _$PveNotifier {
|
||||
String? proxyHost,
|
||||
int? proxyPort,
|
||||
) async {
|
||||
/* final serverSocket = await ServerSocket.bind(InternetAddress.anyIPv4, 0);
|
||||
final _localPort = serverSocket.port;
|
||||
serverSocket.listen((socket) async {
|
||||
final forward = await _client.forwardLocal(url.host, url.port);
|
||||
forwards.add(forward);
|
||||
forward.stream.cast<List<int>>().pipe(socket);
|
||||
socket.cast<List<int>>().pipe(forward.sink);
|
||||
});*/
|
||||
|
||||
if (url.isScheme('https')) {
|
||||
return SecureSocket.startConnect(
|
||||
'localhost',
|
||||
@@ -137,11 +160,16 @@ class PveNotifier extends _$PveNotifier {
|
||||
}
|
||||
|
||||
Future<void> _login() async {
|
||||
final useKeyAuth = spiParam.keyId != null;
|
||||
final password = useKeyAuth ? spiParam.custom?.pvePwd : spiParam.pwd;
|
||||
if (password == null) {
|
||||
throw PveErr(type: PveErrType.loginFailed, message: 'PVE password is required. Please set it in server settings.');
|
||||
}
|
||||
final resp = await session.post(
|
||||
'$addr/api2/extjs/access/ticket',
|
||||
'$addrValue/api2/extjs/access/ticket',
|
||||
data: {
|
||||
'username': spi.user,
|
||||
'password': spi.pwd,
|
||||
'username': spiParam.user,
|
||||
'password': password,
|
||||
'realm': 'pam',
|
||||
'new-format': '1',
|
||||
},
|
||||
@@ -149,21 +177,26 @@ class PveNotifier extends _$PveNotifier {
|
||||
headers: {HttpHeaders.contentTypeHeader: Headers.jsonContentType},
|
||||
),
|
||||
);
|
||||
try {
|
||||
final ticket = resp.data['data']['ticket'];
|
||||
session.options.headers['CSRFPreventionToken'] =
|
||||
resp.data['data']['CSRFPreventionToken'];
|
||||
session.options.headers['Cookie'] = 'PVEAuthCookie=$ticket';
|
||||
} catch (e) {
|
||||
throw PveErr(type: PveErrType.loginFailed, message: e.toString());
|
||||
|
||||
final data = resp.data['data'];
|
||||
if (data['NeedTFA'] == 1) {
|
||||
throw PveErr(type: PveErrType.needTfa, message: 'Two-factor authentication is not supported yet. Please disable OTP on the PVE server and try again.');
|
||||
}
|
||||
|
||||
_setAuthHeaders(data);
|
||||
}
|
||||
|
||||
void _setAuthHeaders(Map<String, dynamic> data) {
|
||||
final ticket = data['ticket'];
|
||||
session.options.headers['CSRFPreventionToken'] = data['CSRFPreventionToken'];
|
||||
session.options.headers['Cookie'] = 'PVEAuthCookie=$ticket';
|
||||
}
|
||||
|
||||
/// Returns true if the PVE version is 8.0 or later
|
||||
Future<void> _getRelease() async {
|
||||
final resp = await session.get('$addr/api2/extjs/version');
|
||||
final resp = await session.get('$addrValue/api2/extjs/version');
|
||||
final version = resp.data['data']['release'] as String?;
|
||||
if (version != null) {
|
||||
if (version != null && ref.mounted) {
|
||||
state = state.copyWith(release: version);
|
||||
}
|
||||
}
|
||||
@@ -172,25 +205,29 @@ class PveNotifier extends _$PveNotifier {
|
||||
if (!state.isConnected || state.isBusy) return;
|
||||
state = state.copyWith(isBusy: true);
|
||||
try {
|
||||
final resp = await session.get('$addr/api2/json/cluster/resources');
|
||||
final resp = await session.get('$addrValue/api2/json/cluster/resources');
|
||||
final res = resp.data['data'] as List;
|
||||
final result = await Computer.shared.start(PveRes.parse, (
|
||||
res,
|
||||
state.data,
|
||||
));
|
||||
if (!ref.mounted) return;
|
||||
state = state.copyWith(data: result, error: null);
|
||||
} catch (e) {
|
||||
if (!ref.mounted) return;
|
||||
Loggers.app.warning('PVE list failed', e);
|
||||
state = state.copyWith(error: PveErr(type: PveErrType.unknown, message: e.toString()));
|
||||
} finally {
|
||||
state = state.copyWith(isBusy: false);
|
||||
if (ref.mounted) {
|
||||
state = state.copyWith(isBusy: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> reboot(String node, String id) async {
|
||||
if (!state.isConnected) return false;
|
||||
final resp = await session.post(
|
||||
'$addr/api2/json/nodes/$node/$id/status/reboot',
|
||||
'$addrValue/api2/json/nodes/$node/$id/status/reboot',
|
||||
);
|
||||
final success = _isCtrlSuc(resp);
|
||||
if (success) await list(); // Refresh data
|
||||
@@ -200,7 +237,7 @@ class PveNotifier extends _$PveNotifier {
|
||||
Future<bool> start(String node, String id) async {
|
||||
if (!state.isConnected) return false;
|
||||
final resp = await session.post(
|
||||
'$addr/api2/json/nodes/$node/$id/status/start',
|
||||
'$addrValue/api2/json/nodes/$node/$id/status/start',
|
||||
);
|
||||
final success = _isCtrlSuc(resp);
|
||||
if (success) await list(); // Refresh data
|
||||
@@ -210,7 +247,7 @@ class PveNotifier extends _$PveNotifier {
|
||||
Future<bool> stop(String node, String id) async {
|
||||
if (!state.isConnected) return false;
|
||||
final resp = await session.post(
|
||||
'$addr/api2/json/nodes/$node/$id/status/stop',
|
||||
'$addrValue/api2/json/nodes/$node/$id/status/stop',
|
||||
);
|
||||
final success = _isCtrlSuc(resp);
|
||||
if (success) await list(); // Refresh data
|
||||
@@ -220,7 +257,7 @@ class PveNotifier extends _$PveNotifier {
|
||||
Future<bool> shutdown(String node, String id) async {
|
||||
if (!state.isConnected) return false;
|
||||
final resp = await session.post(
|
||||
'$addr/api2/json/nodes/$node/$id/status/shutdown',
|
||||
'$addrValue/api2/json/nodes/$node/$id/status/shutdown',
|
||||
);
|
||||
final success = _isCtrlSuc(resp);
|
||||
if (success) await list(); // Refresh data
|
||||
@@ -233,7 +270,7 @@ class PveNotifier extends _$PveNotifier {
|
||||
|
||||
Future<void> dispose() async {
|
||||
try {
|
||||
await _serverSocket.close();
|
||||
await _serverSocket?.close();
|
||||
} catch (e, s) {
|
||||
Loggers.app.warning('Failed to close server socket', e, s);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
|
||||
/// @nodoc
|
||||
mixin _$PveState {
|
||||
|
||||
PveErr? get error; PveRes? get data; String? get release; bool get isBusy; bool get isConnected;
|
||||
PveErr? get error; PveRes? get data; String? get release; bool get isBusy; bool get isConnected; PveLoadingStep get loadingStep;
|
||||
/// Create a copy of PveState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@@ -25,16 +25,16 @@ $PveStateCopyWith<PveState> get copyWith => _$PveStateCopyWithImpl<PveState>(thi
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PveState&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)&&(identical(other.release, release) || other.release == release)&&(identical(other.isBusy, isBusy) || other.isBusy == isBusy)&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is PveState&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)&&(identical(other.release, release) || other.release == release)&&(identical(other.isBusy, isBusy) || other.isBusy == isBusy)&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.loadingStep, loadingStep) || other.loadingStep == loadingStep));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,error,data,release,isBusy,isConnected);
|
||||
int get hashCode => Object.hash(runtimeType,error,data,release,isBusy,isConnected,loadingStep);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PveState(error: $error, data: $data, release: $release, isBusy: $isBusy, isConnected: $isConnected)';
|
||||
return 'PveState(error: $error, data: $data, release: $release, isBusy: $isBusy, isConnected: $isConnected, loadingStep: $loadingStep)';
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract mixin class $PveStateCopyWith<$Res> {
|
||||
factory $PveStateCopyWith(PveState value, $Res Function(PveState) _then) = _$PveStateCopyWithImpl;
|
||||
@useResult
|
||||
$Res call({
|
||||
PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected
|
||||
PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected, PveLoadingStep loadingStep
|
||||
});
|
||||
|
||||
|
||||
@@ -62,14 +62,15 @@ class _$PveStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PveState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? error = freezed,Object? data = freezed,Object? release = freezed,Object? isBusy = null,Object? isConnected = null,}) {
|
||||
@pragma('vm:prefer-inline') @override $Res call({Object? error = freezed,Object? data = freezed,Object? release = freezed,Object? isBusy = null,Object? isConnected = null,Object? loadingStep = null,}) {
|
||||
return _then(_self.copyWith(
|
||||
error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as PveErr?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
|
||||
as PveRes?,release: freezed == release ? _self.release : release // ignore: cast_nullable_to_non_nullable
|
||||
as String?,isBusy: null == isBusy ? _self.isBusy : isBusy // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
as bool,loadingStep: null == loadingStep ? _self.loadingStep : loadingStep // ignore: cast_nullable_to_non_nullable
|
||||
as PveLoadingStep,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -154,10 +155,10 @@ return $default(_that);case _:
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected, PveLoadingStep loadingStep)? $default,{required TResult orElse(),}) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PveState() when $default != null:
|
||||
return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnected);case _:
|
||||
return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnected,_that.loadingStep);case _:
|
||||
return orElse();
|
||||
|
||||
}
|
||||
@@ -175,10 +176,10 @@ return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnec
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected) $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected, PveLoadingStep loadingStep) $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PveState():
|
||||
return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnected);case _:
|
||||
return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnected,_that.loadingStep);case _:
|
||||
throw StateError('Unexpected subclass');
|
||||
|
||||
}
|
||||
@@ -195,10 +196,10 @@ return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnec
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected)? $default,) {final _that = this;
|
||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected, PveLoadingStep loadingStep)? $default,) {final _that = this;
|
||||
switch (_that) {
|
||||
case _PveState() when $default != null:
|
||||
return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnected);case _:
|
||||
return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnected,_that.loadingStep);case _:
|
||||
return null;
|
||||
|
||||
}
|
||||
@@ -210,7 +211,7 @@ return $default(_that.error,_that.data,_that.release,_that.isBusy,_that.isConnec
|
||||
|
||||
|
||||
class _PveState implements PveState {
|
||||
const _PveState({this.error = null, this.data = null, this.release = null, this.isBusy = false, this.isConnected = false});
|
||||
const _PveState({this.error = null, this.data = null, this.release = null, this.isBusy = false, this.isConnected = false, this.loadingStep = PveLoadingStep.none});
|
||||
|
||||
|
||||
@override@JsonKey() final PveErr? error;
|
||||
@@ -218,6 +219,7 @@ class _PveState implements PveState {
|
||||
@override@JsonKey() final String? release;
|
||||
@override@JsonKey() final bool isBusy;
|
||||
@override@JsonKey() final bool isConnected;
|
||||
@override@JsonKey() final PveLoadingStep loadingStep;
|
||||
|
||||
/// Create a copy of PveState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@@ -229,16 +231,16 @@ _$PveStateCopyWith<_PveState> get copyWith => __$PveStateCopyWithImpl<_PveState>
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PveState&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)&&(identical(other.release, release) || other.release == release)&&(identical(other.isBusy, isBusy) || other.isBusy == isBusy)&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected));
|
||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _PveState&&(identical(other.error, error) || other.error == error)&&(identical(other.data, data) || other.data == data)&&(identical(other.release, release) || other.release == release)&&(identical(other.isBusy, isBusy) || other.isBusy == isBusy)&&(identical(other.isConnected, isConnected) || other.isConnected == isConnected)&&(identical(other.loadingStep, loadingStep) || other.loadingStep == loadingStep));
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,error,data,release,isBusy,isConnected);
|
||||
int get hashCode => Object.hash(runtimeType,error,data,release,isBusy,isConnected,loadingStep);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PveState(error: $error, data: $data, release: $release, isBusy: $isBusy, isConnected: $isConnected)';
|
||||
return 'PveState(error: $error, data: $data, release: $release, isBusy: $isBusy, isConnected: $isConnected, loadingStep: $loadingStep)';
|
||||
}
|
||||
|
||||
|
||||
@@ -249,7 +251,7 @@ abstract mixin class _$PveStateCopyWith<$Res> implements $PveStateCopyWith<$Res>
|
||||
factory _$PveStateCopyWith(_PveState value, $Res Function(_PveState) _then) = __$PveStateCopyWithImpl;
|
||||
@override @useResult
|
||||
$Res call({
|
||||
PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected
|
||||
PveErr? error, PveRes? data, String? release, bool isBusy, bool isConnected, PveLoadingStep loadingStep
|
||||
});
|
||||
|
||||
|
||||
@@ -266,14 +268,15 @@ class __$PveStateCopyWithImpl<$Res>
|
||||
|
||||
/// Create a copy of PveState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? error = freezed,Object? data = freezed,Object? release = freezed,Object? isBusy = null,Object? isConnected = null,}) {
|
||||
@override @pragma('vm:prefer-inline') $Res call({Object? error = freezed,Object? data = freezed,Object? release = freezed,Object? isBusy = null,Object? isConnected = null,Object? loadingStep = null,}) {
|
||||
return _then(_PveState(
|
||||
error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable
|
||||
as PveErr?,data: freezed == data ? _self.data : data // ignore: cast_nullable_to_non_nullable
|
||||
as PveRes?,release: freezed == release ? _self.release : release // ignore: cast_nullable_to_non_nullable
|
||||
as String?,isBusy: null == isBusy ? _self.isBusy : isBusy // ignore: cast_nullable_to_non_nullable
|
||||
as bool,isConnected: null == isConnected ? _self.isConnected : isConnected // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
as bool,loadingStep: null == loadingStep ? _self.loadingStep : loadingStep // ignore: cast_nullable_to_non_nullable
|
||||
as PveLoadingStep,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ final class PveNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$pveNotifierHash() => r'1e71faadee074b9c07bee731ef4ae6505e791967';
|
||||
String _$pveNotifierHash() => r'a66699f64eae680064a1904f475d0a241d6cb3f8';
|
||||
|
||||
final class PveNotifierFamily extends $Family
|
||||
with $ClassFamilyOverride<PveNotifier, PveState, PveState, PveState, Spi> {
|
||||
|
||||
@@ -41,7 +41,7 @@ final class ServersNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$serversNotifierHash() => r'dc5da44f9bd8d8dcfba3e6e932cca3e2f379e582';
|
||||
String _$serversNotifierHash() => r'277d1b219235f14bcc1b82a1e16260c2f28decdb';
|
||||
|
||||
abstract class _$ServersNotifier extends $Notifier<ServersState> {
|
||||
ServersState build();
|
||||
|
||||
@@ -58,7 +58,7 @@ final class ServerNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$serverNotifierHash() => r'04b1beef4d96242fd10d5b523c6f5f17eb774bae';
|
||||
String _$serverNotifierHash() => r'1bda6d0a9688ab843cf30803dafe3400379dc5c3';
|
||||
|
||||
final class ServerNotifierFamily extends $Family
|
||||
with
|
||||
|
||||
@@ -58,7 +58,7 @@ final class SystemdNotifierProvider
|
||||
}
|
||||
}
|
||||
|
||||
String _$systemdNotifierHash() => r'030d556efc3d897419cd3462d37cb705813e24c7';
|
||||
String _$systemdNotifierHash() => r'd8b36c60dff036e98196ad4d084e4b2ae3a65e32';
|
||||
|
||||
final class SystemdNotifierFamily extends $Family
|
||||
with
|
||||
|
||||
@@ -151,6 +151,7 @@ abstract final class GithubIds {
|
||||
'Yinhono',
|
||||
'kuvaldini',
|
||||
'aliferne',
|
||||
'canronglan',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user