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

Allow ContentResponse to receive multiple components next to a title #2407

Merged
merged 1 commit into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
ftovaro marked this conversation as resolved.
Show resolved Hide resolved
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; trackBy: trackByIndex" 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 @@ -6,6 +6,12 @@
outline: none;
}

.action-buttons {
.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,10 +9,11 @@ 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';
import trackByIndex from 'src/app/util/trackBy/trackByIndex';

interface Tab {
name: string;
Expand All @@ -29,17 +30,18 @@ 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;
activeTabIndex: number;
closingTab: boolean;
view: View;
trackByIndex = trackByIndex;

constructor(
private router: Router,
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 @@ -6,9 +6,9 @@
>
<ng-container *ngIf="hasReceivedContent && !showSpinner; else loading">
<app-object-tabs
[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