ui/lib/modules/my_services/service_detail.dart (192 lines of code) (raw):
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import 'package:cloudprovision/modules/catalog/data/build_repository.dart';
import 'package:cloudprovision/modules/my_services/widgets/workstation_widget.dart';
import 'package:cloudprovision/widgets/summary_item.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../app_appbar.dart';
import '../../app_drawer.dart';
import 'data/services_repository.dart';
import 'models/service.dart';
import 'widgets/build_history_widget.dart';
import 'widgets/button_launch_in_cloud_shell.dart';
import 'widgets/recommendations_widget.dart';
import 'widgets/service_resources_widget.dart';
import 'widgets/service_summary.dart';
import 'widgets/template_details_widget.dart';
import 'widgets/vulnerabilities.dart';
class ServiceDetail extends ConsumerStatefulWidget {
final String _serviceID;
ServiceDetail(this._serviceID, {super.key});
@override
ConsumerState<ServiceDetail> createState() => _ServiceDetailState(_serviceID);
}
class _ServiceDetailState extends ConsumerState<ServiceDetail> {
final String serviceID;
_ServiceDetailState(this.serviceID);
bool _serviceUses(Service service, List<String> types) {
for (int i = 0; i < types.length; i++) {
if (service.params['tags'].toString().toLowerCase().contains(
types[i].toLowerCase(),
)) return true;
}
return false;
}
@override
Widget build(BuildContext context) {
final asyncValue = ref.watch(serviceByDocIdProvider(serviceID));
return asyncValue.when(
loading: () {
return Container();
},
data: (service) {
return Scaffold(
appBar: App_AppBar(),
drawer: AppDrawer(),
body: _buildPage(context, service),
);
},
error: (err, st) {
print("${st}");
return Scaffold(body: Text("Error"));
},
);
}
Widget _buildPage(BuildContext context, Service service) {
return Stack(
children: [
_buildSubHead(context),
Positioned(
top: 50,
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(25.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${service.name}",
style: Theme.of(context).textTheme.titleMedium,
),
SizedBox(height: 12),
_buildDetailsSection(service, context),
],
),
),
),
),
),
],
);
}
_buildSubHead(BuildContext context) {
return Column(
children: [
Divider(color: Colors.black38),
Container(
padding: EdgeInsets.only(left: 20),
height: 32,
child: Row(
children: [
InkWell(
onTap: () {
context.go('/services');
},
child: Text(
'My Services',
style: Theme.of(context).textTheme.titleMedium,
)
),
SizedBox(
width: 5,
),
Text(
'/',
style: Theme.of(context).textTheme.titleMedium,
),
SizedBox(
width: 5,
),
Text(
"Service Detail",
style: Theme.of(context).textTheme.titleMedium,
),
],
),
),
Divider(color: Colors.black38),
],
);
}
Widget _buildDetailsSection(Service service, BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// << SERVICE SUMMARY >>
ServiceSummary(service: service),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// << REPO LINK >>
SummaryItem(
label: "Repository",
child: Text.rich(
TextSpan(
style: TextStyle(
color: Theme.of(context).primaryColor,
decoration: TextDecoration.underline),
text: service.instanceRepo,
recognizer: TapGestureRecognizer()
..onTap = () async {
launchUrl(Uri.parse(service.instanceRepo));
},
),
),
),
],
),
Divider(),
// << CLOUD SHELL || WORKSTATION BUTTON >>
service.workstationConfig.isNotEmpty
? WorkStationWidget(service)
: LaunchInCloudShellButton(service: service),
Divider(),
// << VULNERABILITIES >>
VulnerabilityWidget(service: service),
Divider(),
// << RECOMMENDATIONS >>
if (_serviceUses(service, ["cloudrun"]))
RecommendationsWidget(service: service),
Divider(),
// << BUILD HISTORY >>
BuildHistoryWidget(service: service),
// << RESOURCES >>
ServiceResourcesWidget(service: service),
// << TEMPLATE DETAILS >>
TemplateDetailsWidget(service: service),
Divider(),
// << DELETE BUTTON >>
IconButton(
tooltip: 'Delete',
onPressed: () async {
String result = await ref
.read(buildRepositoryProvider)
.deleteService(service);
if (result != "") {
await ref
.read(servicesRepositoryProvider)
.deleteService(service);
ref.invalidate(servicesProvider);
}
context.go("/services");
},
icon: Icon(
Icons.delete,
color: Colors.red,
),
),
],
);
}
}