mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-16 23:04:22 +01:00
fix: disable command menu doesnt work (#852)
This commit is contained in:
@@ -1,20 +1,52 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:icons_plus/icons_plus.dart';
|
||||||
import 'package:server_box/core/extension/context/locale.dart';
|
import 'package:server_box/core/extension/context/locale.dart';
|
||||||
import 'package:server_box/data/model/app/scripts/script_consts.dart';
|
import 'package:server_box/data/model/app/scripts/script_consts.dart';
|
||||||
import 'package:server_box/data/model/server/system.dart';
|
import 'package:server_box/data/model/server/system.dart';
|
||||||
|
|
||||||
|
/// Enum representing different command types for various systems
|
||||||
|
enum CmdTypeSys {
|
||||||
|
linux('Linux'),
|
||||||
|
bsd('BSD'),
|
||||||
|
windows('Windows');
|
||||||
|
|
||||||
|
final String sign;
|
||||||
|
const CmdTypeSys(this.sign);
|
||||||
|
|
||||||
|
IconData get icon {
|
||||||
|
return switch (this) {
|
||||||
|
CmdTypeSys.linux => MingCute.linux_line,
|
||||||
|
CmdTypeSys.bsd => LineAwesome.freebsd,
|
||||||
|
CmdTypeSys.windows => MingCute.windows_line,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Base class for all command type enums
|
/// Base class for all command type enums
|
||||||
abstract class CommandType implements Enum {
|
sealed class ShellCmdType implements Enum {
|
||||||
String get cmd;
|
String get cmd;
|
||||||
|
|
||||||
/// Get command-specific separator
|
/// Get command-specific separator
|
||||||
String get separator;
|
String get separator;
|
||||||
|
|
||||||
/// Get command-specific divider (separator with echo and formatting)
|
/// Get command-specific divider (separator with echo and formatting)
|
||||||
String get divider;
|
String get divider;
|
||||||
|
|
||||||
|
/// Get corresponding system type
|
||||||
|
CmdTypeSys get sysType;
|
||||||
|
|
||||||
|
static Set<ShellCmdType> get all {
|
||||||
|
return {...StatusCmdType.values, ...BSDStatusCmdType.values, ...WindowsStatusCmdType.values};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ShellCmdTypeX on ShellCmdType {
|
||||||
|
/// Display name of the command type
|
||||||
|
String get displayName => '${sysType.sign}.$name';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Linux/Unix status commands
|
/// Linux/Unix status commands
|
||||||
enum StatusCmdType implements CommandType {
|
enum StatusCmdType implements ShellCmdType {
|
||||||
echo('echo ${SystemType.linuxSign}'),
|
echo('echo ${SystemType.linuxSign}'),
|
||||||
time('date +%s'),
|
time('date +%s'),
|
||||||
net('cat /proc/net/dev'),
|
net('cat /proc/net/dev'),
|
||||||
@@ -90,16 +122,19 @@ enum StatusCmdType implements CommandType {
|
|||||||
final String cmd;
|
final String cmd;
|
||||||
|
|
||||||
const StatusCmdType(this.cmd);
|
const StatusCmdType(this.cmd);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get separator => ScriptConstants.getCmdSeparator(name);
|
String get separator => ScriptConstants.getCmdSeparator(name);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get divider => ScriptConstants.getCmdDivider(name);
|
String get divider => ScriptConstants.getCmdDivider(name);
|
||||||
|
|
||||||
|
@override
|
||||||
|
CmdTypeSys get sysType => CmdTypeSys.linux;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BSD/macOS status commands
|
/// BSD/macOS status commands
|
||||||
enum BSDStatusCmdType implements CommandType {
|
enum BSDStatusCmdType implements ShellCmdType {
|
||||||
echo('echo ${SystemType.bsdSign}'),
|
echo('echo ${SystemType.bsdSign}'),
|
||||||
time('date +%s'),
|
time('date +%s'),
|
||||||
net('netstat -ibn'),
|
net('netstat -ibn'),
|
||||||
@@ -115,16 +150,19 @@ enum BSDStatusCmdType implements CommandType {
|
|||||||
final String cmd;
|
final String cmd;
|
||||||
|
|
||||||
const BSDStatusCmdType(this.cmd);
|
const BSDStatusCmdType(this.cmd);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get separator => ScriptConstants.getCmdSeparator(name);
|
String get separator => ScriptConstants.getCmdSeparator(name);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get divider => ScriptConstants.getCmdDivider(name);
|
String get divider => ScriptConstants.getCmdDivider(name);
|
||||||
|
|
||||||
|
@override
|
||||||
|
CmdTypeSys get sysType => CmdTypeSys.bsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Windows PowerShell status commands
|
/// Windows PowerShell status commands
|
||||||
enum WindowsStatusCmdType implements CommandType {
|
enum WindowsStatusCmdType implements ShellCmdType {
|
||||||
echo('echo ${SystemType.windowsSign}'),
|
echo('echo ${SystemType.windowsSign}'),
|
||||||
time('[DateTimeOffset]::UtcNow.ToUnixTimeSeconds()'),
|
time('[DateTimeOffset]::UtcNow.ToUnixTimeSeconds()'),
|
||||||
|
|
||||||
@@ -244,12 +282,15 @@ enum WindowsStatusCmdType implements CommandType {
|
|||||||
final String cmd;
|
final String cmd;
|
||||||
|
|
||||||
const WindowsStatusCmdType(this.cmd);
|
const WindowsStatusCmdType(this.cmd);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get separator => ScriptConstants.getCmdSeparator(name);
|
String get separator => ScriptConstants.getCmdSeparator(name);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get divider => ScriptConstants.getCmdDivider(name);
|
String get divider => ScriptConstants.getCmdDivider(name);
|
||||||
|
|
||||||
|
@override
|
||||||
|
CmdTypeSys get sysType => CmdTypeSys.windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extensions for StatusCmdType
|
/// Extensions for StatusCmdType
|
||||||
@@ -266,7 +307,7 @@ extension StatusCmdTypeX on StatusCmdType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extension for CommandType to find content in parsed map
|
/// Extension for CommandType to find content in parsed map
|
||||||
extension CommandTypeX on CommandType {
|
extension CommandTypeX on ShellCmdType {
|
||||||
/// Find the command output from the parsed script output map
|
/// Find the command output from the parsed script output map
|
||||||
String findInMap(Map<String, String> parsedOutput) {
|
String findInMap(Map<String, String> parsedOutput) {
|
||||||
return parsedOutput[name] ?? '';
|
return parsedOutput[name] ?? '';
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ switch (\$args[0]) {
|
|||||||
|
|
||||||
/// Get Windows status command with command-specific separators
|
/// Get Windows status command with command-specific separators
|
||||||
String _getWindowsStatusCommand({required List<String> disabledCmdTypes}) {
|
String _getWindowsStatusCommand({required List<String> disabledCmdTypes}) {
|
||||||
final cmdTypes = WindowsStatusCmdType.values.where((e) => !disabledCmdTypes.contains(e.name));
|
final cmdTypes = WindowsStatusCmdType.values.where((e) => !disabledCmdTypes.contains(e.displayName));
|
||||||
return cmdTypes.map((e) => '${e.divider}${e.cmd}').join('').trimRight(); // Remove trailing divider
|
return cmdTypes.map((e) => '${e.divider}${e.cmd}').join('').trimRight(); // Remove trailing divider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,10 +196,10 @@ esac''');
|
|||||||
/// Get Unix status command with OS detection
|
/// Get Unix status command with OS detection
|
||||||
String _getUnixStatusCommand({required List<String> disabledCmdTypes}) {
|
String _getUnixStatusCommand({required List<String> disabledCmdTypes}) {
|
||||||
// Generate command lists with command-specific separators, filtering disabled commands
|
// Generate command lists with command-specific separators, filtering disabled commands
|
||||||
final filteredLinuxCmdTypes = StatusCmdType.values.where((e) => !disabledCmdTypes.contains(e.name));
|
final filteredLinuxCmdTypes = StatusCmdType.values.where((e) => !disabledCmdTypes.contains(e.displayName));
|
||||||
final linuxCommands = filteredLinuxCmdTypes.map((e) => '${e.divider}${e.cmd}').join('').trimRight();
|
final linuxCommands = filteredLinuxCmdTypes.map((e) => '${e.divider}${e.cmd}').join('').trimRight();
|
||||||
|
|
||||||
final filteredBsdCmdTypes = BSDStatusCmdType.values.where((e) => !disabledCmdTypes.contains(e.name));
|
final filteredBsdCmdTypes = BSDStatusCmdType.values.where((e) => !disabledCmdTypes.contains(e.displayName));
|
||||||
final bsdCommands = filteredBsdCmdTypes.map((e) => '${e.divider}${e.cmd}').join('').trimRight();
|
final bsdCommands = filteredBsdCmdTypes.map((e) => '${e.divider}${e.cmd}').join('').trimRight();
|
||||||
|
|
||||||
return '''
|
return '''
|
||||||
|
|||||||
@@ -597,21 +597,16 @@ extension on _ServerEditPageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onTapDisabledCmdTypes() async {
|
void _onTapDisabledCmdTypes() async {
|
||||||
final allCmdTypes = <String>{};
|
final allCmdTypes = ShellCmdType.all;
|
||||||
allCmdTypes.addAll(StatusCmdType.values.map((e) => e.name));
|
|
||||||
allCmdTypes.addAll(BSDStatusCmdType.values.map((e) => e.name));
|
|
||||||
allCmdTypes.addAll(WindowsStatusCmdType.values.map((e) => e.name));
|
|
||||||
|
|
||||||
// [TimeSeq] depends on the `time` cmd type, so it should be removed from the list
|
// [TimeSeq] depends on the `time` cmd type, so it should be removed from the list
|
||||||
allCmdTypes.remove(StatusCmdType.time.name);
|
allCmdTypes.remove(StatusCmdType.time);
|
||||||
|
|
||||||
final selected = await _showCmdTypesDialog(allCmdTypes);
|
await _showCmdTypesDialog(allCmdTypes);
|
||||||
if (selected == null) return;
|
|
||||||
_disabledCmdTypes.value = selected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Set<String>?> _showCmdTypesDialog(Set<String> allCmdTypes) {
|
Future<void> _showCmdTypesDialog(Set<ShellCmdType> allCmdTypes) {
|
||||||
return context.showRoundDialog<Set<String>>(
|
return context.showRoundDialog(
|
||||||
title: '${libL10n.disabled} ${l10n.cmd}',
|
title: '${libL10n.disabled} ${l10n.cmd}',
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 270,
|
width: 270,
|
||||||
@@ -622,16 +617,30 @@ extension on _ServerEditPageState {
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final cmdType = allCmdTypes.elementAtOrNull(index);
|
final cmdType = allCmdTypes.elementAtOrNull(index);
|
||||||
if (cmdType == null) return UIs.placeholder;
|
if (cmdType == null) return UIs.placeholder;
|
||||||
return CheckboxListTile(
|
final display = cmdType.displayName;
|
||||||
title: Text(cmdType),
|
return ListTile(
|
||||||
value: disabled.contains(cmdType),
|
leading: Icon(cmdType.sysType.icon, size: 20),
|
||||||
onChanged: (value) {
|
title: Text(cmdType.name, style: const TextStyle(fontSize: 16)),
|
||||||
if (value == null) return;
|
trailing: Checkbox(
|
||||||
if (value) {
|
value: disabled.contains(display),
|
||||||
_disabledCmdTypes.value.add(cmdType);
|
onChanged: (value) {
|
||||||
|
if (value == null) return;
|
||||||
|
if (value) {
|
||||||
|
_disabledCmdTypes.value.add(display);
|
||||||
|
} else {
|
||||||
|
_disabledCmdTypes.value.remove(display);
|
||||||
|
}
|
||||||
|
_disabledCmdTypes.notify();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
final isDisabled = disabled.contains(display);
|
||||||
|
if (isDisabled) {
|
||||||
|
_disabledCmdTypes.value.remove(display);
|
||||||
} else {
|
} else {
|
||||||
_disabledCmdTypes.value.remove(cmdType);
|
_disabledCmdTypes.value.add(display);
|
||||||
}
|
}
|
||||||
|
_disabledCmdTypes.notify();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -764,6 +773,10 @@ extension on _ServerEditPageState {
|
|||||||
_scriptDirCtrl.text = spi.custom?.scriptDir ?? '';
|
_scriptDirCtrl.text = spi.custom?.scriptDir ?? '';
|
||||||
|
|
||||||
_systemType.value = spi.customSystemType;
|
_systemType.value = spi.customSystemType;
|
||||||
_disabledCmdTypes.value = spi.disabledCmdTypes?.toSet() ?? {};
|
|
||||||
|
final disabledCmdTypes = spi.disabledCmdTypes?.toSet() ?? {};
|
||||||
|
final allAvailableCmdTypes = ShellCmdType.all.map((e) => e.displayName);
|
||||||
|
disabledCmdTypes.removeWhere((e) => !allAvailableCmdTypes.contains(e));
|
||||||
|
_disabledCmdTypes.value = disabledCmdTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
119
test/disabled_cmd_types_test.dart
Normal file
119
test/disabled_cmd_types_test.dart
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:server_box/data/model/app/scripts/cmd_types.dart';
|
||||||
|
import 'package:server_box/data/model/app/scripts/shell_func.dart';
|
||||||
|
import 'package:server_box/data/model/server/system.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('disabledCmdTypes filtering', () {
|
||||||
|
test('filters Linux status commands when disabled', () {
|
||||||
|
final disabled = <String>{
|
||||||
|
StatusCmdType.net.displayName,
|
||||||
|
StatusCmdType.sys.displayName,
|
||||||
|
}.toList();
|
||||||
|
|
||||||
|
final script = ShellFuncManager.allScript(
|
||||||
|
null,
|
||||||
|
systemType: SystemType.linux,
|
||||||
|
disabledCmdTypes: disabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Linux-specific commands should be removed
|
||||||
|
expect(script, isNot(contains('cat /proc/net/dev'))); // net
|
||||||
|
expect(script, isNot(contains('cat /etc/*-release | grep ^PRETTY_NAME'))); // sys
|
||||||
|
|
||||||
|
// Other commands should remain
|
||||||
|
expect(script, contains('uptime'));
|
||||||
|
expect(script, contains('date +%s'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('filters BSD status commands when disabled', () {
|
||||||
|
final disabled = <String>{
|
||||||
|
BSDStatusCmdType.sys.displayName,
|
||||||
|
BSDStatusCmdType.mem.displayName,
|
||||||
|
}.toList();
|
||||||
|
|
||||||
|
final script = ShellFuncManager.allScript(
|
||||||
|
null,
|
||||||
|
systemType: SystemType.linux, // Unix builder is used for Linux/BSD
|
||||||
|
disabledCmdTypes: disabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
// BSD-specific commands should be removed
|
||||||
|
expect(script, isNot(contains('uname -or'))); // sys
|
||||||
|
expect(script, isNot(contains('top -l 1 | grep PhysMem'))); // mem
|
||||||
|
|
||||||
|
// Linux equivalents should remain
|
||||||
|
expect(script, contains('cat /etc/*-release | grep ^PRETTY_NAME'));
|
||||||
|
expect(script, contains("cat /proc/meminfo | grep -E 'Mem|Swap'"));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('filters Windows status commands when disabled', () {
|
||||||
|
final disabled = <String>{
|
||||||
|
WindowsStatusCmdType.net.displayName,
|
||||||
|
WindowsStatusCmdType.uptime.displayName,
|
||||||
|
WindowsStatusCmdType.temp.displayName,
|
||||||
|
}.toList();
|
||||||
|
|
||||||
|
final script = ShellFuncManager.allScript(
|
||||||
|
null,
|
||||||
|
systemType: SystemType.windows,
|
||||||
|
disabledCmdTypes: disabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Windows-specific commands should be removed
|
||||||
|
expect(script, isNot(contains('LastBootUpTime'))); // uptime
|
||||||
|
expect(script, isNot(contains('MSAcpi_ThermalZoneTemperature'))); // temp
|
||||||
|
|
||||||
|
// Other Windows commands should remain
|
||||||
|
expect(script, contains('Get-Process'));
|
||||||
|
expect(script, contains('Get-WmiObject -Class Win32_OperatingSystem'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ignores disabled names for other platforms', () {
|
||||||
|
final disabled = <String>{
|
||||||
|
WindowsStatusCmdType.sys.displayName,
|
||||||
|
WindowsStatusCmdType.net.displayName,
|
||||||
|
}.toList();
|
||||||
|
|
||||||
|
final script = ShellFuncManager.allScript(
|
||||||
|
null,
|
||||||
|
systemType: SystemType.linux,
|
||||||
|
disabledCmdTypes: disabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Linux commands should not be affected by Windows-only disables
|
||||||
|
expect(script, contains('cat /etc/*-release | grep ^PRETTY_NAME'));
|
||||||
|
expect(script, contains('cat /proc/net/dev'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('disabling all status commands removes separators', () {
|
||||||
|
final allUnixDisabled = <String>{
|
||||||
|
...StatusCmdType.values.map((e) => e.displayName),
|
||||||
|
...BSDStatusCmdType.values.map((e) => e.displayName),
|
||||||
|
}.toList();
|
||||||
|
|
||||||
|
final unixScript = ShellFuncManager.allScript(
|
||||||
|
null,
|
||||||
|
systemType: SystemType.linux,
|
||||||
|
disabledCmdTypes: allUnixDisabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
// No status separators for Unix script
|
||||||
|
expect(unixScript, isNot(contains('SrvBoxSep.')));
|
||||||
|
|
||||||
|
final allWinDisabled = <String>{
|
||||||
|
...WindowsStatusCmdType.values.map((e) => e.displayName),
|
||||||
|
}.toList();
|
||||||
|
|
||||||
|
final windowsScript = ShellFuncManager.allScript(
|
||||||
|
null,
|
||||||
|
systemType: SystemType.windows,
|
||||||
|
disabledCmdTypes: allWinDisabled,
|
||||||
|
);
|
||||||
|
|
||||||
|
// No status separators for Windows script
|
||||||
|
expect(windowsScript, isNot(contains('SrvBoxSep.')));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user