Skip to content

Commit d5ea4b7

Browse files
committed
Help users understand origin of displayed compilation result ✨
Help users understand where the currently displayed compilation result comes from: + Stop displaying a compilation result if the user has opened another file in the meantime: Expand the state to remember the file path to the entry point used for compilation. Check for equality of these paths in the view function. + Display a warning message when the user has changed the file in the editor since the last compilation: Compare the file contents in the view function to enable visibility of the warning message.
1 parent 7699222 commit d5ea4b7

File tree

1 file changed

+137
-82
lines changed
  • implement/example-apps/elm-editor/src/FrontendWeb

1 file changed

+137
-82
lines changed

implement/example-apps/elm-editor/src/FrontendWeb/Main.elm

Lines changed: 137 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ port receiveMessageFromMonacoFrame : (Json.Encode.Value -> msg) -> Sub msg
4141

4242

4343
type alias ElmMakeRequestStructure =
44-
FrontendBackendInterface.ElmMakeRequestStructure
44+
{ requestToBackend : FrontendBackendInterface.ElmMakeRequestStructure
45+
, entryPointFilePath : List String
46+
}
4547

4648

4749
type alias ElmMakeResponseStructure =
@@ -56,15 +58,14 @@ type alias State =
5658
, fileInEditor : Maybe ( List String, String )
5759
, decodeMessageFromMonacoEditorError : Maybe Json.Decode.Error
5860
, lastElmMakeRequest : Maybe { time : Time.Posix, request : ElmMakeRequestStructure }
59-
, elmMakeResult : Maybe (Result Http.Error ElmMakeResultStructure)
61+
, elmMakeResult : Maybe ( ElmMakeRequestStructure, Result Http.Error ElmMakeResultStructure )
6062
, elmFormatResult : Maybe (Result Http.Error FrontendBackendInterface.FormatElmModuleTextResponseStructure)
6163
, modalDialog : Maybe ModalDialogState
6264
}
6365

6466

6567
type alias ElmMakeResultStructure =
66-
{ request : ElmMakeRequestStructure
67-
, response : ElmMakeResponseStructure
68+
{ response : ElmMakeResponseStructure
6869
, compiledHtmlDocument : Maybe String
6970
}
7071

@@ -218,7 +219,7 @@ update event stateBefore =
218219
Just fileInEditor ->
219220
let
220221
( state, compileCmd ) =
221-
update UserInputCompile stateBefore
222+
userInputCompileFileOpenedInEditor stateBefore
222223
in
223224
( state
224225
, [ fileInEditor |> Tuple.second |> setTextInMonacoEditorCmd
@@ -236,7 +237,7 @@ update event stateBefore =
236237
update UserInputFormat stateBefore
237238

238239
FrontendWeb.MonacoEditor.EditorActionCompileEvent ->
239-
update UserInputCompile stateBefore
240+
userInputCompileFileOpenedInEditor stateBefore
240241

241242
TimeHasArrived time ->
242243
( { stateBefore | time = Just time }, Cmd.none )
@@ -245,7 +246,7 @@ update event stateBefore =
245246
( stateBefore, elmFormatCmd stateBefore )
246247

247248
UserInputCompile ->
248-
userInputCompile stateBefore
249+
userInputCompileFileOpenedInEditor stateBefore
249250

250251
BackendElmFormatResponseEvent formatResponseEvent ->
251252
if Just formatResponseEvent.filePath /= Maybe.map Tuple.first stateBefore.fileInEditor then
@@ -297,13 +298,14 @@ update event stateBefore =
297298
|> Maybe.withDefault ("Error decoding base64: " ++ newFile.contentBase64)
298299
|> Just
299300
in
300-
{ request = elmMakeRequest
301-
, response = elmMakeResponse
301+
{ response = elmMakeResponse
302302
, compiledHtmlDocument = compiledHtmlDocument
303303
}
304304
)
305305
in
306-
( { stateBefore | elmMakeResult = Just elmMakeResult }, Cmd.none )
306+
( { stateBefore | elmMakeResult = Just ( elmMakeRequest, elmMakeResult ) }
307+
, Cmd.none
308+
)
307309

308310
UrlChange url ->
309311
let
@@ -508,12 +510,40 @@ elmFormatCmd state =
508510
(\result -> BackendElmFormatResponseEvent { filePath = filePath, result = result })
509511

510512

511-
userInputCompile : State -> ( State, Cmd Event )
512-
userInputCompile stateBefore =
513-
case stateBefore.fileInEditor of
513+
userInputCompileFileOpenedInEditor : State -> ( State, Cmd Event )
514+
userInputCompileFileOpenedInEditor stateBefore =
515+
case elmMakeRequestForFileOpenedInEditor stateBefore of
514516
Nothing ->
515517
( stateBefore, Cmd.none )
516518

519+
Just elmMakeRequest ->
520+
let
521+
jsonDecoder backendResponse =
522+
case backendResponse of
523+
FrontendBackendInterface.ElmMakeResponse elmMakeResponse ->
524+
Json.Decode.succeed elmMakeResponse
525+
526+
_ ->
527+
Json.Decode.fail "Unexpected response"
528+
in
529+
( { stateBefore
530+
| lastElmMakeRequest =
531+
stateBefore.time |> Maybe.map (\time -> { time = time, request = elmMakeRequest })
532+
, elmMakeResult = Nothing
533+
}
534+
, requestToApiCmd
535+
(FrontendBackendInterface.ElmMakeRequest elmMakeRequest.requestToBackend)
536+
jsonDecoder
537+
(BackendElmMakeResponseEvent elmMakeRequest)
538+
)
539+
540+
541+
elmMakeRequestForFileOpenedInEditor : State -> Maybe ElmMakeRequestStructure
542+
elmMakeRequestForFileOpenedInEditor state =
543+
case state.fileInEditor of
544+
Nothing ->
545+
Nothing
546+
517547
Just ( filePath, _ ) ->
518548
let
519549
base64FromBytes : Bytes.Bytes -> String
@@ -523,11 +553,12 @@ userInputCompile stateBefore =
523553

524554
entryPointFilePath =
525555
filePath
526-
527-
elmMakeRequest =
556+
in
557+
Just
558+
{ requestToBackend =
528559
{ commandLineArguments = "make " ++ (entryPointFilePath |> String.join "/") ++ " --output=" ++ elmMakeOutputFileName
529560
, files =
530-
stateBefore.projectFiles
561+
state.projectFiles
531562
|> Dict.toList
532563
|> List.map
533564
(\( path, content ) ->
@@ -536,25 +567,8 @@ userInputCompile stateBefore =
536567
}
537568
)
538569
}
539-
540-
request =
541-
elmMakeRequest |> FrontendBackendInterface.ElmMakeRequest
542-
543-
jsonDecoder backendResponse =
544-
case backendResponse of
545-
FrontendBackendInterface.ElmMakeResponse elmMakeResponse ->
546-
Json.Decode.succeed elmMakeResponse
547-
548-
_ ->
549-
Json.Decode.fail "Unexpected response"
550-
in
551-
( { stateBefore
552-
| lastElmMakeRequest =
553-
stateBefore.time |> Maybe.map (\time -> { time = time, request = elmMakeRequest })
554-
, elmMakeResult = Nothing
555-
}
556-
, requestToApiCmd request jsonDecoder (BackendElmMakeResponseEvent elmMakeRequest)
557-
)
570+
, entryPointFilePath = entryPointFilePath
571+
}
558572

559573

560574
requestToApiCmd :
@@ -702,8 +716,8 @@ view state =
702716
, Element.height Element.fill
703717
]
704718

705-
Just _ ->
706-
viewWhenEditorOpen state
719+
Just fileInEditor ->
720+
viewWhenEditorOpen fileInEditor state
707721

708722
popupAttributes =
709723
case state.modalDialog of
@@ -989,62 +1003,103 @@ popupAttributesFromProperties { title, guide, contentElement } =
9891003
]
9901004

9911005

992-
viewWhenEditorOpen : State -> Element.Element Event
993-
viewWhenEditorOpen state =
1006+
viewWhenEditorOpen : ( List String, String ) -> State -> Element.Element Event
1007+
viewWhenEditorOpen ( fileOpenedInEditorPath, _ ) state =
9941008
let
1009+
elmMakeResultForFileOpenedInEditor =
1010+
state.elmMakeResult
1011+
|> Maybe.andThen
1012+
(\elmMakeRequestAndResult ->
1013+
if (elmMakeRequestAndResult |> Tuple.first |> .entryPointFilePath) == fileOpenedInEditorPath then
1014+
Just elmMakeRequestAndResult
1015+
1016+
else
1017+
Nothing
1018+
)
1019+
9951020
resultElement =
996-
case state.lastElmMakeRequest of
1021+
case elmMakeResultForFileOpenedInEditor of
9971022
Nothing ->
998-
[ "No compilation started so far. You can use the 'Compile' button to check program text for errors and see your app in action."
999-
|> Element.text
1000-
]
1001-
|> Element.paragraph [ Element.padding defaultFontSize ]
1002-
1003-
Just lastElmMakeRequest ->
1004-
case state.elmMakeResult of
1023+
case state.lastElmMakeRequest of
10051024
Nothing ->
1025+
[ "No compilation started so far. You can use the 'Compile' button to check program text for errors and see your app in action."
1026+
|> Element.text
1027+
]
1028+
|> Element.paragraph [ Element.padding defaultFontSize ]
1029+
1030+
Just _ ->
10061031
Element.text "Compiling..." |> Element.el [ Element.padding defaultFontSize ]
10071032

1008-
Just (Err elmMakeError) ->
1033+
Just ( elmMakeRequest, elmMakeResult ) ->
1034+
case elmMakeResult of
1035+
Err elmMakeError ->
10091036
("Error: " ++ describeHttpError elmMakeError) |> Element.text
10101037

1011-
Just (Ok elmMakeOk) ->
1012-
case elmMakeOk.compiledHtmlDocument of
1013-
Nothing ->
1014-
[ ( "standard error", elmMakeOk.response.processOutput.standardError )
1015-
, ( "standard output", elmMakeOk.response.processOutput.standardOutput )
1016-
]
1017-
|> List.map
1018-
(\( channel, output ) ->
1019-
[ channel |> Element.text |> Element.el (headingAttributes 3)
1020-
, [ Html.text output
1021-
|> Element.html
1022-
|> Element.el [ Element.htmlAttribute (HA.style "white-space" "pre-wrap") ]
1023-
]
1024-
|> Element.paragraph
1025-
[ Element.htmlAttribute attributeMonospaceFont ]
1026-
|> indentOneLevel
1027-
]
1028-
|> Element.column
1029-
[ Element.spacing (defaultFontSize // 2)
1030-
, Element.width Element.fill
1031-
]
1032-
)
1033-
|> Element.column
1034-
[ Element.spacing defaultFontSize
1035-
, Element.width Element.fill
1036-
, Element.height Element.fill
1037-
, Element.scrollbarY
1038+
Ok elmMakeOk ->
1039+
let
1040+
elmMakeRequestFromCurrentState =
1041+
elmMakeRequestForFileOpenedInEditor state
1042+
1043+
currentFileContentIsStillSame =
1044+
Just elmMakeRequest.requestToBackend.files
1045+
== (elmMakeRequestFromCurrentState |> Maybe.map (.requestToBackend >> .files))
1046+
1047+
warningFileContentChangedElement =
1048+
"⚠️ The file contents were changed since compiling"
1049+
|> Element.text
1050+
|> Element.el
1051+
[ Element.transparent currentFileContentIsStillSame
10381052
, Element.padding (defaultFontSize // 2)
10391053
]
10401054

1041-
Just compiledHtmlDocument ->
1042-
Html.iframe
1043-
[ HA.srcdoc compiledHtmlDocument
1044-
, HA.style "height" "100%"
1045-
]
1046-
[]
1047-
|> Element.html
1055+
compileResultElement =
1056+
case elmMakeOk.compiledHtmlDocument of
1057+
Nothing ->
1058+
[ ( "standard error", elmMakeOk.response.processOutput.standardError )
1059+
, ( "standard output", elmMakeOk.response.processOutput.standardOutput )
1060+
]
1061+
|> List.map
1062+
(\( channel, output ) ->
1063+
[ channel |> Element.text |> Element.el (headingAttributes 3)
1064+
, [ Html.text output
1065+
|> Element.html
1066+
|> Element.el [ Element.htmlAttribute (HA.style "white-space" "pre-wrap") ]
1067+
]
1068+
|> Element.paragraph
1069+
[ Element.htmlAttribute attributeMonospaceFont ]
1070+
|> indentOneLevel
1071+
]
1072+
|> Element.column
1073+
[ Element.spacing (defaultFontSize // 2)
1074+
, Element.width Element.fill
1075+
]
1076+
)
1077+
|> Element.column
1078+
[ Element.spacing defaultFontSize
1079+
, Element.width Element.fill
1080+
, Element.height Element.fill
1081+
, Element.scrollbarY
1082+
, Element.padding (defaultFontSize // 2)
1083+
]
1084+
1085+
Just compiledHtmlDocument ->
1086+
Html.iframe
1087+
[ HA.srcdoc compiledHtmlDocument
1088+
, HA.style "height" "98%"
1089+
]
1090+
[]
1091+
|> Element.html
1092+
|> Element.el
1093+
[ Element.width Element.fill
1094+
, Element.height Element.fill
1095+
]
1096+
in
1097+
[ warningFileContentChangedElement, compileResultElement ]
1098+
|> Element.column
1099+
[ Element.spacing (defaultFontSize // 2)
1100+
, Element.width Element.fill
1101+
, Element.height Element.fill
1102+
]
10481103

10491104
formatButton =
10501105
buttonElement { label = "📄 Format", onPress = Just UserInputFormat }

0 commit comments

Comments
 (0)