mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
#42 new: docker logs
This commit is contained in:
@@ -581,6 +581,12 @@ abstract class S {
|
||||
/// **'Loading files...'**
|
||||
String get loadingFiles;
|
||||
|
||||
/// No description provided for @log.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Log'**
|
||||
String get log;
|
||||
|
||||
/// No description provided for @loss.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -267,6 +267,9 @@ class SDe extends S {
|
||||
@override
|
||||
String get loadingFiles => 'Lädt Dateien...';
|
||||
|
||||
@override
|
||||
String get log => 'Log';
|
||||
|
||||
@override
|
||||
String get loss => 'loss';
|
||||
|
||||
|
||||
@@ -267,6 +267,9 @@ class SEn extends S {
|
||||
@override
|
||||
String get loadingFiles => 'Loading files...';
|
||||
|
||||
@override
|
||||
String get log => 'Log';
|
||||
|
||||
@override
|
||||
String get loss => 'loss';
|
||||
|
||||
|
||||
@@ -267,6 +267,9 @@ class SZh extends S {
|
||||
@override
|
||||
String get loadingFiles => '正在加载目录。。。';
|
||||
|
||||
@override
|
||||
String get log => '日志';
|
||||
|
||||
@override
|
||||
String get loss => '丢包率';
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 313;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -368,7 +368,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.310;
|
||||
MARKETING_VERSION = 1.0.313;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -491,7 +491,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 313;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -499,7 +499,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.310;
|
||||
MARKETING_VERSION = 1.0.313;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@@ -516,7 +516,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 313;
|
||||
DEVELOPMENT_TEAM = BA88US33G6;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
|
||||
@@ -524,7 +524,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.310;
|
||||
MARKETING_VERSION = 1.0.313;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
||||
@@ -163,6 +163,14 @@ class DockerProvider extends BusyProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String> logs(String id) async {
|
||||
setBusyState();
|
||||
final cmd = _wrap('docker logs $id');
|
||||
final result = await client!.run(cmd);
|
||||
setBusyState(false);
|
||||
return result.string;
|
||||
}
|
||||
|
||||
// judge whether to use DOCKER_HOST / sudo
|
||||
String _wrap(String cmd) {
|
||||
final dockerHost = dockerStore.getDockerHost(hostId!);
|
||||
|
||||
@@ -64,14 +64,16 @@ class ServerProvider extends BusyProvider {
|
||||
serverOrder.addAll(serverOrder_.toSet());
|
||||
if (serverOrder.length != infos.length) {
|
||||
final missed = infos
|
||||
.where((e) => !serverOrder.contains(e.id))
|
||||
.map((e) => e.id)
|
||||
.toList();
|
||||
.where(
|
||||
(e) => !serverOrder.contains(e.id),
|
||||
)
|
||||
.map((e) => e.id);
|
||||
serverOrder.addAll(missed);
|
||||
}
|
||||
} else {
|
||||
serverOrder.addAll(_servers.keys);
|
||||
}
|
||||
_settingStore.serverOrder.put(serverOrder);
|
||||
setBusyState(false);
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
class BuildData {
|
||||
static const String name = "ServerBox";
|
||||
static const int build = 310;
|
||||
static const int build = 313;
|
||||
static const String engine = "3.10.0";
|
||||
static const String buildAt = "2023-05-14 17:02:42.374273";
|
||||
static const int modifications = 20;
|
||||
static const String buildAt = "2023-05-16 17:56:08.999957";
|
||||
static const int modifications = 6;
|
||||
}
|
||||
|
||||
@@ -1,45 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../../view/widget/dropdown_menu.dart';
|
||||
enum ServerTabMenuType {
|
||||
sftp,
|
||||
snippet,
|
||||
pkg,
|
||||
docker,
|
||||
edit;
|
||||
|
||||
class ServerTabMenuItems {
|
||||
static const List<DropdownBtnItem> firstItems = [sftp, snippet, pkg, docker];
|
||||
static const List<DropdownBtnItem> secondItems = [edit];
|
||||
|
||||
static const sftp =
|
||||
DropdownBtnItem(text: 'SFTP', icon: Icons.insert_drive_file);
|
||||
static const snippet = DropdownBtnItem(text: 'Snippet', icon: Icons.code);
|
||||
static const pkg =
|
||||
DropdownBtnItem(text: 'Pkg', icon: Icons.system_security_update);
|
||||
static const docker =
|
||||
DropdownBtnItem(text: 'Docker', icon: Icons.view_agenda);
|
||||
static const edit = DropdownBtnItem(text: 'Edit', icon: Icons.edit);
|
||||
}
|
||||
|
||||
class DockerMenuItems {
|
||||
static const rm = DropdownBtnItem(text: 'Remove', icon: Icons.delete);
|
||||
static const start = DropdownBtnItem(text: 'Start', icon: Icons.play_arrow);
|
||||
static const stop = DropdownBtnItem(text: 'Stop', icon: Icons.stop);
|
||||
static const restart =
|
||||
DropdownBtnItem(text: 'Restart', icon: Icons.restart_alt);
|
||||
}
|
||||
|
||||
String getDropdownBtnText(S s, String text) {
|
||||
switch (text) {
|
||||
case 'Snippet':
|
||||
return s.snippet;
|
||||
case 'Pkg':
|
||||
return s.pkg;
|
||||
case 'Remove':
|
||||
return s.delete;
|
||||
case 'Start':
|
||||
return s.start;
|
||||
case 'Stop':
|
||||
return s.stop;
|
||||
case 'Edit':
|
||||
return s.edit;
|
||||
default:
|
||||
return text;
|
||||
IconData get icon {
|
||||
switch (this) {
|
||||
case ServerTabMenuType.sftp:
|
||||
return Icons.insert_drive_file;
|
||||
case ServerTabMenuType.snippet:
|
||||
return Icons.code;
|
||||
case ServerTabMenuType.pkg:
|
||||
return Icons.system_security_update;
|
||||
case ServerTabMenuType.docker:
|
||||
return Icons.view_agenda;
|
||||
case ServerTabMenuType.edit:
|
||||
return Icons.edit;
|
||||
}
|
||||
}
|
||||
|
||||
String text(S s) {
|
||||
switch (this) {
|
||||
case ServerTabMenuType.sftp:
|
||||
return 'SFTP';
|
||||
case ServerTabMenuType.snippet:
|
||||
return s.snippet;
|
||||
case ServerTabMenuType.pkg:
|
||||
return s.pkg;
|
||||
case ServerTabMenuType.docker:
|
||||
return 'Docker';
|
||||
case ServerTabMenuType.edit:
|
||||
return s.edit;
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenuItem<ServerTabMenuType> build(S s) => _build(this, icon, text(s));
|
||||
}
|
||||
|
||||
enum DockerMenuType {
|
||||
start,
|
||||
stop,
|
||||
restart,
|
||||
rm,
|
||||
logs;
|
||||
|
||||
static List<DockerMenuType> items(bool running) {
|
||||
if (running) {
|
||||
return [stop, restart, rm, logs];
|
||||
} else {
|
||||
return [start, rm, logs];
|
||||
}
|
||||
}
|
||||
|
||||
IconData get icon {
|
||||
switch (this) {
|
||||
case DockerMenuType.start:
|
||||
return Icons.play_arrow;
|
||||
case DockerMenuType.stop:
|
||||
return Icons.stop;
|
||||
case DockerMenuType.restart:
|
||||
return Icons.restart_alt;
|
||||
case DockerMenuType.rm:
|
||||
return Icons.delete;
|
||||
case DockerMenuType.logs:
|
||||
return Icons.logo_dev;
|
||||
}
|
||||
}
|
||||
|
||||
String text(S s) {
|
||||
switch (this) {
|
||||
case DockerMenuType.start:
|
||||
return s.start;
|
||||
case DockerMenuType.stop:
|
||||
return s.stop;
|
||||
case DockerMenuType.restart:
|
||||
return s.restart;
|
||||
case DockerMenuType.rm:
|
||||
return s.delete;
|
||||
case DockerMenuType.logs:
|
||||
return s.log;
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenuItem<DockerMenuType> build(S s) => _build(this, icon, text(s));
|
||||
}
|
||||
|
||||
PopupMenuItem<T> _build<T>(T t, IconData icon, String text) {
|
||||
return PopupMenuItem<T>(
|
||||
value: t,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text(text),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
"license": "Lizenzen",
|
||||
"light": "Hell",
|
||||
"loadingFiles": "Lädt Dateien...",
|
||||
"log": "Log",
|
||||
"loss": "loss",
|
||||
"madeWithLove": "Erstellt mit ❤️ von {myGithub}",
|
||||
"max": "max",
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
"license": "License",
|
||||
"light": "Light",
|
||||
"loadingFiles": "Loading files...",
|
||||
"log": "Log",
|
||||
"loss": "loss",
|
||||
"madeWithLove": "Made with ❤️ by {myGithub}",
|
||||
"max": "max",
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
"license": "开源证书",
|
||||
"light": "亮",
|
||||
"loadingFiles": "正在加载目录。。。",
|
||||
"log": "日志",
|
||||
"loss": "丢包率",
|
||||
"madeWithLove": "用❤️制作 by {myGithub}",
|
||||
"max": "最大",
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:toolbox/core/extension/navigator.dart';
|
||||
import 'package:toolbox/core/utils/misc.dart';
|
||||
import 'package:toolbox/view/widget/input_field.dart';
|
||||
|
||||
import '../../core/utils/ui.dart';
|
||||
@@ -15,7 +16,6 @@ import '../../data/res/ui.dart';
|
||||
import '../../data/res/url.dart';
|
||||
import '../../data/store/docker.dart';
|
||||
import '../../locator.dart';
|
||||
import '../widget/dropdown_menu.dart';
|
||||
import '../widget/popup_menu.dart';
|
||||
import '../widget/round_rect_card.dart';
|
||||
import '../widget/two_line_text.dart';
|
||||
@@ -469,30 +469,16 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
||||
}
|
||||
|
||||
Widget _buildMoreBtn(DockerPsItem dItem, bool busy) {
|
||||
final item = dItem.running ? DockerMenuItems.stop : DockerMenuItems.start;
|
||||
return PopupMenu(
|
||||
items: [
|
||||
PopupMenuItem<DropdownBtnItem>(
|
||||
value: item,
|
||||
child: item.build(_s),
|
||||
),
|
||||
PopupMenuItem<DropdownBtnItem>(
|
||||
value: DockerMenuItems.rm,
|
||||
child: DockerMenuItems.rm.build(_s),
|
||||
),
|
||||
PopupMenuItem<DropdownBtnItem>(
|
||||
value: DockerMenuItems.restart,
|
||||
child: DockerMenuItems.restart.build(_s),
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
items:
|
||||
DockerMenuType.items(dItem.running).map((e) => e.build(_s)).toList(),
|
||||
onSelected: (DockerMenuType item) async {
|
||||
if (busy) {
|
||||
showSnackBar(context, Text(_s.isBusy));
|
||||
return;
|
||||
}
|
||||
final item = value as DropdownBtnItem;
|
||||
switch (item) {
|
||||
case DockerMenuItems.rm:
|
||||
case DockerMenuType.rm:
|
||||
showRoundDialog(
|
||||
context: context,
|
||||
child: Text(_s.sureDelete(dItem.name)),
|
||||
@@ -507,12 +493,30 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
||||
],
|
||||
);
|
||||
break;
|
||||
case DockerMenuItems.start:
|
||||
case DockerMenuType.start:
|
||||
_docker.start(dItem.containerId);
|
||||
break;
|
||||
case DockerMenuItems.stop:
|
||||
case DockerMenuType.stop:
|
||||
_docker.stop(dItem.containerId);
|
||||
break;
|
||||
case DockerMenuType.logs:
|
||||
final logs = await _docker.logs(dItem.containerId);
|
||||
showRoundDialog(
|
||||
context: context,
|
||||
child: SingleChildScrollView(
|
||||
child: Text(logs),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => copy2Clipboard(logs),
|
||||
child: Text(_s.copy),
|
||||
)
|
||||
],
|
||||
);
|
||||
break;
|
||||
case DockerMenuType.restart:
|
||||
_docker.restart(dItem.containerId);
|
||||
break;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
@@ -19,7 +19,6 @@ import '../../../data/res/ui.dart';
|
||||
import '../../../data/res/url.dart';
|
||||
import '../../../data/store/setting.dart';
|
||||
import '../../../locator.dart';
|
||||
import '../../widget/dropdown_menu.dart';
|
||||
import '../../widget/popup_menu.dart';
|
||||
import '../../widget/round_rect_card.dart';
|
||||
import '../../widget/url_text.dart';
|
||||
@@ -264,30 +263,16 @@ class _ServerPageState extends State<ServerPage>
|
||||
|
||||
Widget _buildMoreBtn(ServerPrivateInfo spi) {
|
||||
return PopupMenu(
|
||||
items: <PopupMenuEntry>[
|
||||
...ServerTabMenuItems.firstItems.map(
|
||||
(item) => PopupMenuItem<DropdownBtnItem>(
|
||||
value: item,
|
||||
child: item.build(_s),
|
||||
),
|
||||
),
|
||||
const PopupMenuDivider(height: 1),
|
||||
...ServerTabMenuItems.secondItems.map(
|
||||
(item) => PopupMenuItem<DropdownBtnItem>(
|
||||
value: item,
|
||||
child: item.build(_s),
|
||||
),
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
switch (value as DropdownBtnItem) {
|
||||
case ServerTabMenuItems.pkg:
|
||||
items: ServerTabMenuType.values.map((e) => e.build(_s)).toList(),
|
||||
onSelected: (ServerTabMenuType value) {
|
||||
switch (value) {
|
||||
case ServerTabMenuType.pkg:
|
||||
AppRoute(PkgManagePage(spi), 'pkg manage').go(context);
|
||||
break;
|
||||
case ServerTabMenuItems.sftp:
|
||||
case ServerTabMenuType.sftp:
|
||||
AppRoute(SFTPPage(spi), 'SFTP').go(context);
|
||||
break;
|
||||
case ServerTabMenuItems.snippet:
|
||||
case ServerTabMenuType.snippet:
|
||||
showSnippetDialog(context, _s, (s) async {
|
||||
final result = await _serverProvider.runSnippet(spi.id, s);
|
||||
showRoundDialog(
|
||||
@@ -302,10 +287,10 @@ class _ServerPageState extends State<ServerPage>
|
||||
);
|
||||
});
|
||||
break;
|
||||
case ServerTabMenuItems.edit:
|
||||
case ServerTabMenuType.edit:
|
||||
AppRoute(ServerEditPage(spi: spi), 'Edit server info').go(context);
|
||||
break;
|
||||
case ServerTabMenuItems.docker:
|
||||
case ServerTabMenuType.docker:
|
||||
AppRoute(DockerManagePage(spi), 'Docker manage').go(context);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/l10n.dart';
|
||||
|
||||
import '../../data/res/menu.dart';
|
||||
|
||||
class DropdownBtnItem {
|
||||
final String text;
|
||||
final IconData icon;
|
||||
|
||||
const DropdownBtnItem({
|
||||
required this.text,
|
||||
required this.icon,
|
||||
});
|
||||
|
||||
Widget build(S s) => Row(
|
||||
children: [
|
||||
Icon(icon),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text(
|
||||
getDropdownBtnText(s, text),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -475,9 +475,9 @@
|
||||
baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 313;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0.310;
|
||||
MARKETING_VERSION = 1.0.313;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -490,9 +490,9 @@
|
||||
baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 313;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0.310;
|
||||
MARKETING_VERSION = 1.0.313;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -505,9 +505,9 @@
|
||||
baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CURRENT_PROJECT_VERSION = 310;
|
||||
CURRENT_PROJECT_VERSION = 313;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0.310;
|
||||
MARKETING_VERSION = 1.0.313;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
||||
Reference in New Issue
Block a user