Skip to content
This repository has been archived by the owner on Jan 19, 2023. It is now read-only.

Commit

Permalink
Allow ContentResponse to receive multiple components next to a title
Browse files Browse the repository at this point in the history
Signed-off-by: ftovaro <f.tovar12@gmail.com>
  • Loading branch information
ftovaro committed May 4, 2021
1 parent d91a8d3 commit 878473a
Show file tree
Hide file tree
Showing 12 changed files with 112 additions and 31 deletions.
1 change: 1 addition & 0 deletions changelogs/unreleased/2302-ftovaro
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allowed to pass multiple components next to a title in a ContentResponse
20 changes: 10 additions & 10 deletions internal/describer/object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,22 +99,22 @@ func TestObjectDescriber(t *testing.T) {

summary := component.NewText("summary")

buttonGroup := component.NewButtonGroup()

buttonGroup.AddButton(
component.NewButton("Delete",
action.CreatePayload(octant.ActionDeleteObject, key.ToActionPayload()),
component.WithButtonConfirmation(
"Delete Pod",
"Are you sure you want to delete *Pod* **pod**? This action is permanent and cannot be recovered.",
)))
button := component.NewButton("Delete",
action.CreatePayload(octant.ActionDeleteObject, key.ToActionPayload()),
component.WithButtonConfirmation(
"Delete Pod",
"Are you sure you want to delete *Pod* **pod**? This action is permanent and cannot be recovered.",
),
)

expected := component.ContentResponse{
Title: component.Title(component.NewText("pod")),
Components: []component.Component{
summary,
},
ButtonGroup: buttonGroup,
TitleComponents: []component.Component{
button,
},
}

testutil.AssertJSONEqual(t, &expected, &cResponse)
Expand Down
2 changes: 0 additions & 2 deletions pkg/plugin/grpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ func Test_GRPCClient_Content(t *testing.T) {
contentResponseBytes, err := json.Marshal(&contentResponse)
require.NoError(t, err)

contentResponse.ButtonGroup = nil

resp := &dashboard.ContentResponse{
ContentResponse: contentResponseBytes,
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/plugin/javascript.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func (t *jsPlugin) Content(ctx context.Context, contentPath string) (component.C
return
}

cr.ButtonGroup = buttonGroup
cr.AddTitleComponents(buttonGroup)
}
errCh <- nil
})
Expand Down
30 changes: 24 additions & 6 deletions pkg/view/component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,22 @@ type ContentResponse struct {
Title []TitleComponent `json:"title,omitempty"`
Components []Component `json:"viewComponents"`
ExtensionComponent Component `json:"extensionComponent,omitempty"`
ButtonGroup *ButtonGroup `json:"buttonGroup,omitempty"`
TitleComponents []Component `json:"titleComponents,omitempty"`
}

// NewContentResponse creates an instance of ContentResponse.
func NewContentResponse(title []TitleComponent) *ContentResponse {
return &ContentResponse{
Title: title,
ButtonGroup: NewButtonGroup(),
Title: title,
}
}

// AddTitleComponents Adds any number of components to accompany the title
func (c *ContentResponse) AddTitleComponents(components ...Component) {
for i := range components {
if components[i] != nil {
c.TitleComponents = append(c.TitleComponents, components[i])
}
}
}

Expand All @@ -52,14 +60,15 @@ func (c *ContentResponse) SetExtension(component *Extension) {
// AddButton adds one or more actions to a content response.
func (c *ContentResponse) AddButton(name string, payload action.Payload, buttonOptions ...ButtonOption) {
button := NewButton(name, payload, buttonOptions...)
c.ButtonGroup.AddButton(button)
c.TitleComponents = append(c.TitleComponents, button)
}

// UnmarshalJSON unmarshals a content response from JSON.
func (c *ContentResponse) UnmarshalJSON(data []byte) error {
stage := struct {
Title []TypedObject `json:"title,omitempty"`
Components []TypedObject `json:"viewComponents,omitempty"`
Title []TypedObject `json:"title,omitempty"`
Components []TypedObject `json:"viewComponents,omitempty"`
TitleComponents []TypedObject `json:"titleComponents,omitempty"`
}{}

if err := json.Unmarshal(data, &stage); err != nil {
Expand Down Expand Up @@ -89,6 +98,15 @@ func (c *ContentResponse) UnmarshalJSON(data []byte) error {
c.Components = append(c.Components, vc)
}

for _, to := range stage.TitleComponents {
vc, err := to.ToComponent()
if err != nil {
return err
}

c.TitleComponents = append(c.TitleComponents, vc)
}

return nil
}

Expand Down
52 changes: 52 additions & 0 deletions pkg/view/component/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"path/filepath"
"testing"

"github.com/vmware-tanzu/octant/pkg/action"

"github.com/stretchr/testify/require"

"github.com/vmware-tanzu/octant/internal/testutil"
Expand Down Expand Up @@ -57,3 +59,53 @@ func TestContentResponse_Add(t *testing.T) {
})
}
}

func TestContentResponse_AddTitleComponents(t *testing.T) {
tests := []struct {
name string
components []Component
wanted []Component
}{
{
name: "with no components",
components: []Component{},
wanted: nil,
},
{
name: "with nil components",
components: []Component{nil, NewButton("btn", nil), nil},
wanted: []Component{NewButton("btn", nil)},
},
{
name: "in general",
components: []Component{NewIcon("car")},
wanted: []Component{NewIcon("car")},
},
{
name: "with many components",
components: []Component{
NewIcon("car"),
NewButton("btn", action.Payload{}),
NewButton("btn", action.Payload{}),
NewButton("btn", action.Payload{}),
NewButton("btn", action.Payload{}),
NewLink("link", "", ""),
},
wanted: []Component{
NewIcon("car"),
NewButton("btn", action.Payload{}),
NewButton("btn", action.Payload{}),
NewButton("btn", action.Payload{}),
NewButton("btn", action.Payload{}),
NewLink("link", "", ""),
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
cr := NewContentResponse(TitleFromString("cr"))
cr.AddTitleComponents(test.components...)
testutil.AssertJSONEqual(t, test.wanted, cr.TitleComponents)
})
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<div class="clr-row clr-align-items-center clr-justify-content-between">
<div class="clr-col-10">
<div class="clr-col-6">
<app-breadcrumb [path]="title"> </app-breadcrumb>
</div>
<div class="clr-col-2">
<div *ngIf="buttonGroup" class="action-buttons">
<app-button-group [view]="buttonGroup"></app-button-group>
<div class="clr-col-6">
<div *ngIf="titleComponents?.length > 0" class="title-container">
<div *ngFor="let component of titleComponents; let i = index; trackBy: identifyPath" class="item">
<app-view-container [view]="component"></app-view-container>
</div>
</div>
</div>
</div>
Expand All @@ -29,4 +31,4 @@
</clr-tabs>
<ng-template #noTabs>
<app-view-container [view]="view"></app-view-container>
</ng-template>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@
.action-buttons {
float: right;
}

.title-container {
float: right;
display: flex;
justify-content: space-between;

.item {
margin: 0 5px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
SimpleChanges,
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ButtonGroupView, View } from 'src/app/modules/shared/models/content';
import { View } from 'src/app/modules/shared/models/content';
import { SliderService } from 'src/app/modules/shared/slider/slider.service';
import { ViewService } from '../../../services/view/view.service';
import { ActionService } from '../../../services/action/action.service';
Expand All @@ -29,11 +29,11 @@ interface Tab {
export class TabsComponent implements OnChanges, OnInit {
@Input() title: View[];
@Input() views: View[];
@Input() titleComponents: View[];
@Input() payloads: [{ [key: string]: string }];
@Input() iconName: string;
@Input() closable: boolean;
@Input() extView: boolean;
@Input() buttonGroup: ButtonGroupView;

tabs: Tab[] = [];
activeTab: string;
Expand Down
2 changes: 1 addition & 1 deletion web/src/app/modules/shared/models/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface Content {
extensionComponent: ExtensionView;
viewComponents: View[];
title: View[];
buttonGroup?: ButtonGroupView;
titleComponents?: View[];
}

export interface Metadata {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
[buttonGroup]="buttonGroup"
[title]="title"
[views]="views"
[titleComponents]="titleComponents"
></app-object-tabs>
</ng-container>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
} from '@angular/core';
import { Params, Router, UrlSegment } from '@angular/router';
import {
ButtonGroupView,
ContentResponse,
ExtensionView,
View,
Expand All @@ -39,9 +38,9 @@ export class ContentComponent implements OnInit, OnDestroy {
hasReceivedContent = false;
title: View[] = null;
views: View[] = null;
titleComponents: View[] = null;
extView: ExtensionView = null;
singleView: View = null;
buttonGroup: ButtonGroupView = null;
private contentSubscription: Subscription;
private previousUrl = '';
private defaultPath: string;
Expand Down Expand Up @@ -131,6 +130,7 @@ export class ContentComponent implements OnInit, OnDestroy {
private resetView() {
this.title = null;
this.views = null;
this.titleComponents = null;
}

private setContent = (contentResponse: ContentResponse) => {
Expand All @@ -147,11 +147,10 @@ export class ContentComponent implements OnInit, OnDestroy {
return;
}

this.buttonGroup = contentResponse.content.buttonGroup;

this.extView = contentResponse.content.extensionComponent;
this.views = views;
this.title = contentResponse.content.title;
this.titleComponents = contentResponse.content.titleComponents;

this.hasReceivedContent = true;
};
Expand Down

0 comments on commit 878473a

Please sign in to comment.