Skip to content

Commit

Permalink
Merge pull request #16385 from [BEAM-13535] [Playground] add cancel e…
Browse files Browse the repository at this point in the history
…xecution button

* [BEAM-13535] playground - add cancel execution button

* [BEAM-13535] fix merging cancel button

* [BEAM-13535] fix hash code to recommended

* [BEAM-13535] cancel pipeline execution log

* [BEAM-13535] playground - fix merge conflicts
  • Loading branch information
ElessarST committed Jan 13, 2022
1 parent bd22c65 commit 7deb105
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 56 deletions.
12 changes: 12 additions & 0 deletions playground/frontend/lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
"@run": {
"description": "Title for the run button"
},
"cancel": "Cancel",
"@cancel": {
"description": "Title for the cancel button"
},
"cancelExecution": "Cancel Execution",
"@cancelExecution": {
"description": "Title for the cancel execution notification"
},
"unknownExample": "Unknown Example",
"@unknownExample": {
"description": "Unknown example text part"
},
"log": "Log",
"@log": {
"description": "Title for the log section"
Expand Down
20 changes: 14 additions & 6 deletions playground/frontend/lib/modules/editor/components/run_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import 'package:flutter/material.dart';
import 'package:playground/config/theme.dart';
import 'package:playground/constants/sizes.dart';
import 'package:playground/modules/shortcuts/components/shortcut_tooltip.dart';
import 'package:playground/modules/shortcuts/constants/global_shortcuts.dart';
Expand All @@ -30,9 +31,14 @@ const kSecondsFractions = 1;
class RunButton extends StatelessWidget {
final bool isRunning;
final VoidCallback runCode;
final VoidCallback cancelRun;

const RunButton({Key? key, required this.isRunning, required this.runCode})
: super(key: key);
const RunButton({
Key? key,
required this.isRunning,
required this.runCode,
required this.cancelRun,
}) : super(key: key);

@override
Widget build(BuildContext context) {
Expand All @@ -44,7 +50,7 @@ class RunButton extends StatelessWidget {
width: kIconSizeSm,
height: kIconSizeSm,
child: CircularProgressIndicator(
color: Theme.of(context).primaryColor,
color: ThemeColors.of(context).primaryBackgroundTextColor,
),
)
: const Icon(Icons.play_arrow),
Expand All @@ -53,14 +59,16 @@ class RunButton extends StatelessWidget {
builder: (context, AsyncSnapshot<int> state) {
final seconds = (state.data ?? 0) / kMsToSec;
final runText = AppLocalizations.of(context)!.run;
final cancelText = AppLocalizations.of(context)!.cancel;
final buttonText = isRunning ? cancelText : runText;
if (seconds > 0) {
return Text(
'$runText (${seconds.toStringAsFixed(kSecondsFractions)} s)',
'$buttonText (${seconds.toStringAsFixed(kSecondsFractions)} s)',
);
}
return Text(runText);
return Text(buttonText);
}),
onPressed: !isRunning ? runCode : null,
onPressed: !isRunning ? runCode : cancelRun,
),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import 'package:playground/modules/editor/repository/code_repository/run_code_re
abstract class CodeClient {
Future<RunCodeResponse> runCode(RunCodeRequestWrapper request);

Future<void> cancelExecution(String pipelineUuid);

Future<CheckStatusResponse> checkStatus(
String pipelineUuid,
RunCodeRequestWrapper request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ class GrpcCodeClient implements CodeClient {
.then((response) => RunCodeResponse(response.pipelineUuid)));
}

@override
Future<void> cancelExecution(String pipelineUuid) {
return _runSafely(() => _defaultClient
.cancel(grpc.CancelRequest(pipelineUuid: pipelineUuid)));
}

@override
Future<CheckStatusResponse> checkStatus(
String pipelineUuid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class CodeRepository {
}
}

Future<void> cancelExecution(String pipelineUuid) {
return _client.cancelExecution(pipelineUuid);
}

Stream<RunCodeResult> _checkPipelineExecution(
String pipelineUuid,
RunCodeRequestWrapper request, {
Expand All @@ -88,6 +92,7 @@ class CodeRepository {
}
} on RunCodeError catch (error) {
yield RunCodeResult(
pipelineUuid: prevResult?.pipelineUuid,
status: RunCodeStatus.unknownError,
errorMessage: error.message ?? kUnknownErrorText,
output: error.message ?? kUnknownErrorText,
Expand All @@ -110,25 +115,29 @@ class CodeRepository {
request,
);
return RunCodeResult(
pipelineUuid: pipelineUuid,
status: status,
output: compileOutput.output,
log: prevLog,
);
case RunCodeStatus.timeout:
return RunCodeResult(
pipelineUuid: pipelineUuid,
status: status,
errorMessage: kTimeoutErrorText,
output: kTimeoutErrorText,
);
case RunCodeStatus.runError:
final output = await _client.getRunErrorOutput(pipelineUuid, request);
return RunCodeResult(
pipelineUuid: pipelineUuid,
status: status,
output: output.output,
log: prevLog,
);
case RunCodeStatus.unknownError:
return RunCodeResult(
pipelineUuid: pipelineUuid,
status: status,
errorMessage: kUnknownErrorText,
output: kUnknownErrorText,
Expand All @@ -143,12 +152,16 @@ class CodeRepository {
final output = responses[0];
final log = responses[1];
return RunCodeResult(
pipelineUuid: pipelineUuid,
status: status,
output: prevOutput + output.output,
log: prevLog + log.output,
);
default:
return RunCodeResult(status: status);
return RunCodeResult(
pipelineUuid: pipelineUuid,
status: status,
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
* limitations under the License.
*/

import 'package:flutter/material.dart';

enum RunCodeStatus {
unspecified,
preparation,
Expand All @@ -38,12 +40,14 @@ const kFinishedStatuses = [

class RunCodeResult {
final RunCodeStatus status;
final String? pipelineUuid;
final String? output;
final String? log;
final String? errorMessage;

RunCodeResult({
required this.status,
this.pipelineUuid,
this.output,
this.log,
this.errorMessage,
Expand All @@ -58,17 +62,18 @@ class RunCodeResult {
identical(this, other) ||
other is RunCodeResult &&
runtimeType == other.runtimeType &&
pipelineUuid == other.pipelineUuid &&
status == other.status &&
output == other.output &&
log == other.log &&
errorMessage == other.errorMessage;

@override
int get hashCode =>
status.hashCode ^ output.hashCode ^ log.hashCode ^ errorMessage.hashCode;
hashValues(pipelineUuid, status, output, log, errorMessage);

@override
String toString() {
return 'RunCodeResult{status: $status, output: $output, log: $log, errorMessage: $errorMessage}';
return 'RunCodeResult{pipelineId: $pipelineUuid, status: $status, output: $output, log: $log, errorMessage: $errorMessage}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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:flutter/material.dart';
import 'package:playground/pages/playground/states/playground_state.dart';
import 'dart:html' as html;

import 'package:provider/provider.dart';

class CloseListener extends StatefulWidget {
final Widget child;

const CloseListener({Key? key, required this.child}) : super(key: key);

@override
State<CloseListener> createState() => _CloseListenerState();
}

class _CloseListenerState extends State<CloseListener> {
@override
void initState() {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
html.window.onBeforeUnload.listen((event) async {
Provider.of<PlaygroundState>(context, listen: false).cancelRun();
});
});
super.initState();
}

@override
Widget build(BuildContext context) {
return widget.child;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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:flutter/material.dart';

class CloseListener extends StatelessWidget {
final Widget child;
const CloseListener({Key? key, required this.child}) : super(key: key);

@override
Widget build(BuildContext context) {
return child;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import 'package:playground/modules/sdk/models/sdk.dart';
import 'package:playground/pages/playground/states/playground_state.dart';
import 'package:provider/provider.dart';

const kUnknownExamplePrefix = 'Unknown Example';

class CodeTextAreaWrapper extends StatelessWidget {
const CodeTextAreaWrapper({Key? key}) : super(key: key);

Expand Down Expand Up @@ -67,13 +65,22 @@ class CodeTextAreaWrapper extends StatelessWidget {
height: kRunButtonHeight,
child: RunButton(
isRunning: state.isCodeRunning,
cancelRun: () {
state.cancelRun().catchError(
(_) => NotificationManager.showError(
context,
AppLocalizations.of(context)!.runCode,
AppLocalizations.of(context)!.cancelExecution,
),
);
},
runCode: () {
final stopwatch = Stopwatch()..start();
state.runCode(
onFinish: () {
AnalyticsService.get(context).trackRunTimeEvent(
state.selectedExample?.path ??
'$kUnknownExamplePrefix, sdk ${state.sdk.displayName}',
'${AppLocalizations.of(context)!.unknownExample}, sdk ${state.sdk.displayName}',
stopwatch.elapsedMilliseconds,
);
},
Expand Down Expand Up @@ -122,5 +129,5 @@ class EditorKeyObject {
resetKey == other.resetKey;

@override
int get hashCode => sdk.hashCode ^ example.hashCode ^ resetKey.hashCode;
int get hashCode => hashValues(sdk, example, resetKey);
}
Loading

0 comments on commit 7deb105

Please sign in to comment.