diff --git a/cypress/integration/pipeline.spec.js b/cypress/integration/pipeline.spec.js index 6307fe818..5da0d2265 100644 --- a/cypress/integration/pipeline.spec.js +++ b/cypress/integration/pipeline.spec.js @@ -4,7 +4,7 @@ context('Pipeline', () => { context( - 'logged in and server returning pipeline configuration and templates errors', + 'logged in and server returning pipeline configuration error and templates errors', () => { beforeEach(() => { cy.server(); @@ -126,60 +126,48 @@ context('Pipeline', () => { context('click line number', () => { beforeEach(() => { - cy.get('[data-test=config-line-num-0-2]').click({ force: true }); + cy.get('[data-test=config-line-num-2]').click({ force: true }); }); it('should update path with line num', () => { - cy.hash().should('eq', '#config:0:2'); + cy.hash().should('eq', '#2'); }); it('other lines should not have focus style', () => { - cy.get('[data-test=config-line-0-3]').should( + cy.get('[data-test=config-line-3]').should( 'not.have.class', '-focus', ); }); it('should set focus style on single line', () => { - cy.get('[data-test=config-line-0-2]').should( - 'have.class', - '-focus', - ); + cy.get('[data-test=config-line-2]').should('have.class', '-focus'); }); }); context('click line number, then shift click other line number', () => { beforeEach(() => { - cy.get('[data-test=config-line-num-0-2]') + cy.get('[data-test=config-line-num-2]') .type('{shift}', { release: false }) - .get('[data-test=config-line-num-0-5]') + .get('[data-test=config-line-num-5]') .click({ force: true }); }); it('should update path with range', () => { - cy.hash().should('eq', '#config:0:2:5'); + cy.hash().should('eq', '#2:5'); }); it('lines outside the range should not have focus style', () => { - cy.get('[data-test=config-line-0-6]').should( + cy.get('[data-test=config-line-6]').should( 'not.have.class', '-focus', ); }); it('lines within the range should have focus style', () => { - cy.get('[data-test=config-line-0-2]').should( - 'have.class', - '-focus', - ); - cy.get('[data-test=config-line-0-3]').should( - 'have.class', - '-focus', - ); - cy.get('[data-test=config-line-0-4]').should( - 'have.class', - '-focus', - ); + cy.get('[data-test=config-line-2]').should('have.class', '-focus'); + cy.get('[data-test=config-line-3]').should('have.class', '-focus'); + cy.get('[data-test=config-line-4]').should('have.class', '-focus'); }); }); }); @@ -193,54 +181,54 @@ context('Pipeline', () => { }); it('pipeline configuration data should respect yaml spacing', () => { - cy.get('[data-test=config-line-0-1]').should('contain', 'version:'); - cy.get('[data-test=config-line-0-2]').should('contain', 'steps:'); + cy.get('[data-test=config-line-1]').should('contain', 'version:'); + cy.get('[data-test=config-line-2]').should('contain', 'steps:'); }); context('click line number', () => { beforeEach(() => { - cy.get('[data-test=config-line-num-0-2]').click({ force: true }); + cy.get('[data-test=config-line-num-2]').click({ force: true }); }); it('should update path with line num', () => { - cy.hash().should('eq', '#config:0:2'); + cy.hash().should('eq', '#2'); }); it('other lines should not have focus style', () => { - cy.get('[data-test=config-line-0-3]').should( + cy.get('[data-test=config-line-3]').should( 'not.have.class', '-focus', ); }); it('should set focus style on single line', () => { - cy.get('[data-test=config-line-0-2]').should('have.class', '-focus'); + cy.get('[data-test=config-line-2]').should('have.class', '-focus'); }); }); context('click line number, then shift click other line number', () => { beforeEach(() => { - cy.get('[data-test=config-line-num-0-2]') + cy.get('[data-test=config-line-num-2]') .type('{shift}', { release: false }) - .get('[data-test=config-line-num-0-5]') + .get('[data-test=config-line-num-5]') .click({ force: true }); }); it('should update path with range', () => { - cy.hash().should('eq', '#config:0:2:5'); + cy.hash().should('eq', '#2:5'); }); it('lines outside the range should not have focus style', () => { - cy.get('[data-test=config-line-0-6]').should( + cy.get('[data-test=config-line-6]').should( 'not.have.class', '-focus', ); }); it('lines within the range should have focus style', () => { - cy.get('[data-test=config-line-0-2]').should('have.class', '-focus'); - cy.get('[data-test=config-line-0-3]').should('have.class', '-focus'); - cy.get('[data-test=config-line-0-4]').should('have.class', '-focus'); + cy.get('[data-test=config-line-2]').should('have.class', '-focus'); + cy.get('[data-test=config-line-3]').should('have.class', '-focus'); + cy.get('[data-test=config-line-4]').should('have.class', '-focus'); }); }); }, diff --git a/src/elm/Components/Secrets.elm b/src/elm/Components/Secrets.elm index 553404726..344a64ebe 100644 --- a/src/elm/Components/Secrets.elm +++ b/src/elm/Components/Secrets.elm @@ -160,7 +160,7 @@ viewSharedSecrets shared props = ) RemoteData.Failure error -> - ( span [ Util.testAttribute "repo-secrets-error" ] + ( span [ Util.testAttribute "shared-secrets-error" ] [ text <| case error of Http.BadStatus statusCode -> diff --git a/src/elm/Pages/Org_/Repo_/Build_/Pipeline.elm b/src/elm/Pages/Org_/Repo_/Build_/Pipeline.elm index 7bd047b46..a5a122828 100644 --- a/src/elm/Pages/Org_/Repo_/Build_/Pipeline.elm +++ b/src/elm/Pages/Org_/Repo_/Build_/Pipeline.elm @@ -403,96 +403,158 @@ subscriptions model = view : Shared.Model -> Route { org : String, repo : String, buildNumber : String } -> Model -> View Msg view shared route model = + let + viewExpandToggle = + case model.build of + RemoteData.Success build -> + div [ class "action", class "expand-pipeline", Util.testAttribute "pipeline-expand" ] + [ viewExpandToggleButton model + , if model.expanding then + Components.Loading.viewSmallLoader + + else if model.expand then + div [ class "icon" ] [ FeatherIcons.checkCircle |> FeatherIcons.withSize 20 |> FeatherIcons.toHtml [] ] + + else + div [ class "icon" ] [ FeatherIcons.circle |> FeatherIcons.withSize 20 |> FeatherIcons.toHtml [] ] + , small [ class "tip" ] [ text "note: yaml fields will be sorted alphabetically when the pipeline is expanded." ] + ] + + _ -> + text "" + + downloadButton = + case model.pipeline of + RemoteData.Success pipeline -> + div [ class "action" ] + [ button + [ class "button" + , class "-link" + , Util.testAttribute <| "download-yml" + , onClick <| + DownloadPipeline + { filename = "vela.yml" + , content = pipeline.decodedData + , map = identity + } + , attribute "aria-label" <| "download pipeline configuration file for " + ] + [ text <| + if model.expand then + "download (expanded) " ++ "vela.yml" + + else + "download " ++ "vela.yml" + ] + ] + + _ -> + text "" + in { title = "Pipeline" , body = [ div [ class "pipeline" ] [ case model.templates of RemoteData.Success templates -> if not <| Dict.isEmpty templates then - templates - |> Dict.toList - |> List.map viewTemplate - |> viewTemplatesDetails (class "-success") model.showTemplates ShowHideTemplates + viewTemplatesDetails model <| + div [ class "content", class "-success" ] <| + (templates + |> Dict.toList + |> List.map viewTemplate + ) else text "" - RemoteData.Failure _ -> - text "error" + RemoteData.Failure error -> + viewTemplatesDetails model <| + div [ class "content", class "-error" ] + [ span [ Util.testAttribute "pipeline-templates-error" ] + [ text <| + case error of + Http.BadStatus statusCode -> + case statusCode of + 401 -> + "No templates found for this pipeline, most likely due to not having access to the source control repo" + + _ -> + "No templates found for this pipeline, there was an error with the server (" ++ String.fromInt statusCode ++ ")" + + _ -> + "No templates found for this pipeline, there was an error with the server" + ] + ] _ -> - Components.Loading.viewSmallLoaderWithText "loading pipeline templates" - , case model.pipeline of - RemoteData.Success pipeline -> - if String.length pipeline.decodedData > 0 then - div [ class "logs-container", class "-pipeline" ] - [ table - [ class "logs-table" - ] - [ div [ class "header" ] - [ span [] - [ text "Pipeline Configuration" - ] - ] - , let - toggle = - case model.build of - RemoteData.Success build -> - div [ class "action", class "expand-pipeline", Util.testAttribute "pipeline-expand" ] - [ viewExpandToggleButton model - , if model.expanding then - Components.Loading.viewSmallLoader - - else if model.expand then - div [ class "icon" ] [ FeatherIcons.checkCircle |> FeatherIcons.withSize 20 |> FeatherIcons.toHtml [] ] - - else - div [ class "icon" ] [ FeatherIcons.circle |> FeatherIcons.withSize 20 |> FeatherIcons.toHtml [] ] - , small [ class "tip" ] [ text "note: yaml fields will be sorted alphabetically when the pipeline is expanded." ] - ] + viewTemplatesDetails model <| + div [ class "content", class "-success" ] [ Components.Loading.viewSmallLoaderWithText "loading pipeline templates" ] + , div [ class "logs-container", class "-pipeline" ] + [ table + [ class "logs-table" + , class "pipeline" + ] + [ div [ class "header" ] + [ span [] + [ text "Pipeline Configuration" + ] + ] + , div [ class "actions" ] + [ viewExpandToggle + , downloadButton + ] + , case model.pipeline of + RemoteData.Success pipeline -> + if String.length pipeline.decodedData > 0 then + div [ class "logs", Util.testAttribute "pipeline-configuration-data" ] <| + viewLines pipeline model.focus shared.shift + + else + div [ class "no-pipeline" ] [ small [] [ code [] [ text "The pipeline found for this build/ref contains no data." ] ] ] + + RemoteData.Failure error -> + div [ class "content", class "-error" ] + [ span [ Util.testAttribute "pipeline-configuration-error" ] + [ text <| + case error of + Http.BadStatus statusCode -> + case statusCode of + 401 -> + "No pipeline configuration (.vela.yml) found for this build/ref, most likely due to not being an admin of the source control repo" + + _ -> + "No pipeline configuration (.vela.yml) found for this build/ref, there was an error with the server (" ++ String.fromInt statusCode ++ ")" _ -> - text "" - in - div [ class "actions" ] - [ toggle - , div [ class "action" ] - [ button - [ class "button" - , class "-link" - , Util.testAttribute <| "download-yml" - , onClick <| - DownloadPipeline - { filename = "vela.yml" - , content = pipeline.decodedData - , map = identity - } - , attribute "aria-label" <| "download pipeline configuration file for " - ] - [ text <| - if model.expand then - "download (expanded) " ++ "vela.yml" - - else - "download " ++ "vela.yml" - ] - ] + "No pipeline configuration (.vela.yml) found for this build/ref, there was an error with the server" ] - , div [ class "logs", Util.testAttribute "pipeline-configuration-data" ] <| - viewLines pipeline model.focus shared.shift ] - ] - - else - div [ class "no-pipeline" ] [ small [] [ code [] [ text "No pipeline found for this build." ] ] ] - _ -> - Components.Loading.viewSmallLoader + _ -> + Components.Loading.viewSmallLoader + ] + ] ] ] } +viewTemplatesDetails : Model -> Html Msg -> Html Msg +viewTemplatesDetails model body = + details + (class "details" + :: class "templates" + :: Util.testAttribute "pipeline-templates" + :: Util.open model.showTemplates + ) + [ summary [ class "summary", Util.onClickPreventDefault ShowHideTemplates ] + [ div [] [ text "Templates" ] + , FeatherIcons.chevronDown |> FeatherIcons.withSize 20 |> FeatherIcons.withClass "details-icon-expand" |> FeatherIcons.toHtml [] + ] + , body + ] + + viewExpandToggleButton : Model -> Html Msg viewExpandToggleButton model = button @@ -525,22 +587,6 @@ viewTemplate ( _, t ) = ] -viewTemplatesDetails : Html.Attribute msg -> Bool -> msg -> List (Html msg) -> Html msg -viewTemplatesDetails cls open showHide content = - details - (class "details" - :: class "templates" - :: Util.testAttribute "pipeline-templates" - :: Util.open open - ) - [ summary [ class "summary", Util.onClickPreventDefault showHide ] - [ div [] [ text "Templates" ] - , FeatherIcons.chevronDown |> FeatherIcons.withSize 20 |> FeatherIcons.withClass "details-icon-expand" |> FeatherIcons.toHtml [] - ] - , div [ class "content", cls ] content - ] - - viewLines : Vela.PipelineConfig -> Focus.Focus -> Bool -> List (Html Msg) viewLines config focus shift = config.decodedData diff --git a/src/elm/Pages/Org_/Repo_/Deployments.elm b/src/elm/Pages/Org_/Repo_/Deployments.elm index 0f7c9d3b4..322a6d45a 100644 --- a/src/elm/Pages/Org_/Repo_/Deployments.elm +++ b/src/elm/Pages/Org_/Repo_/Deployments.elm @@ -261,6 +261,23 @@ viewDeployments shared model route = ] ( noRowsView, rows ) = + let + viewHttpError e = + span [ Util.testAttribute "repo-deployments-error" ] + [ text <| + case e of + Http.BadStatus statusCode -> + case statusCode of + 401 -> + "No deployments found for this repo, most likely due to not having access to the source control repo" + + _ -> + "No deployments found for this repo, there was an error with the server (" ++ String.fromInt statusCode ++ ")" + + _ -> + "No deployments found for this repo, there was an error with the server" + ] + in case ( model.repo, model.deployments ) of ( RemoteData.Success r, RemoteData.Success d ) -> ( text "No deployments found for this repo" @@ -268,10 +285,10 @@ viewDeployments shared model route = ) ( RemoteData.Failure error, _ ) -> - ( viewError error, [] ) + ( viewHttpError error, [] ) ( _, RemoteData.Failure error ) -> - ( viewError error, [] ) + ( viewHttpError error, [] ) _ -> ( Components.Loading.viewSmallLoader, [] ) @@ -460,21 +477,3 @@ viewDeploymentBuildsLinks deployment = ) |> List.intersperse (text ", ") |> div [] - - -viewError : Http.Error -> Html msg -viewError error = - span [ Util.testAttribute "repo-deployments-error" ] - [ text <| - case error of - Http.BadStatus statusCode -> - case statusCode of - 401 -> - "No deployments found for this repo, most likely due to not having access to the source control repo" - - _ -> - "No deployments found for this repo, there was an error with the server (" ++ String.fromInt statusCode ++ ")" - - _ -> - "No deployments found for this repo, there was an error with the server" - ] diff --git a/src/elm/Pages/Org_/Repo_/Hooks.elm b/src/elm/Pages/Org_/Repo_/Hooks.elm index 61bd2d8f9..a259ace1c 100644 --- a/src/elm/Pages/Org_/Repo_/Hooks.elm +++ b/src/elm/Pages/Org_/Repo_/Hooks.elm @@ -45,7 +45,7 @@ import Route.Path import Shared import Time import Utils.Ansi -import Utils.Errors as Errors +import Utils.Errors import Utils.Helpers as Util import Utils.Interval as Interval import Vela @@ -139,7 +139,7 @@ update shared route msg model = ) Err error -> - ( { model | hooks = Errors.toFailure error } + ( { model | hooks = Utils.Errors.toFailure error } , Effect.handleHttpError { httpError = error } ) diff --git a/src/scss/_pipelines.scss b/src/scss/_pipelines.scss index 8ad32698d..12c0a2fb7 100644 --- a/src/scss/_pipelines.scss +++ b/src/scss/_pipelines.scss @@ -154,7 +154,7 @@ .logs-table { padding-top: 0; - padding-bottom: 1rem; + padding-bottom: 0; } .logs-table.-error { @@ -175,4 +175,8 @@ .logs-table .line ~ .line { margin-top: 0; } + + .logs-table .logs { + padding-bottom: 1rem; + } }