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

Create grid action #801

Merged
merged 1 commit into from
Mar 31, 2020
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/801-bryanl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for Clarity's single action for data grid rows
1 change: 1 addition & 0 deletions pkg/view/component/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
typeExpressionSelector = "expressionSelector"
typeFlexLayout = "flexlayout"
typeGraphviz = "graphviz"
typeGridActions = "gridActions"
typeIFrame = "iframe"
typeLabels = "labels"
typeLabelSelector = "labelSelector"
Expand Down
71 changes: 71 additions & 0 deletions pkg/view/component/grid_actions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2020 the Octant contributors. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
*/

package component

import (
"encoding/json"

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

type GridAction struct {
// Name is the name of action. It will be shown to the user.
Name string `json:"name"`
// ActionPath is the path of the action.
ActionPath string `json:"actionPath"`
// Payload is the payload that will be submitted with the action is invoked.
Payload action.Payload `json:"payload"`
}

// GridActions add the ability to have specific actions for rows. This will allow for dynamic injection of actions
// that could be dependent on the content of a grid row.
type GridActions struct {
base

Config GridActionsConfig `json:"config"`
}

var _ Component = &GridActions{}

// NewGridActions creates an instance of GridActions.
func NewGridActions() *GridActions {
a := GridActions{
base: newBase(typeGridActions, nil),
}

return &a
}

// AddAction adds an action to GridAction.
func (a *GridActions) AddAction(name, actionPath string, payload action.Payload) {
ga := GridAction{
Name: name,
ActionPath: actionPath,
Payload: payload,
}

a.Config.Actions = append(a.Config.Actions, ga)
}

type gridActionsMarshal GridActions

// MarshalJSON converts the GridActions to a JSON.
func (a GridActions) MarshalJSON() ([]byte, error) {
m := gridActionsMarshal{
base: a.base,
Config: a.Config,
}

m.Metadata.Type = typeGridActions
return json.Marshal(&m)
}

// GridActionsConfig is configuration items for GridActions.
type GridActionsConfig struct {
// Actions is a slice that contains actions that can be performed by the user.
Actions []GridAction `json:"actions"`
}
31 changes: 31 additions & 0 deletions pkg/view/component/grid_actions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2020 the Octant contributors. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
*/

package component

import (
"testing"

"github.com/stretchr/testify/require"

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

func TestGridActions_AddAction(t *testing.T) {
ga := NewGridActions()

payload := action.Payload{"foo": "bar"}
ga.AddAction("name", "/path", payload)

expected := []GridAction{
{
Name: "name",
ActionPath: "/path",
Payload: payload,
},
}
require.Equal(t, expected, ga.Config.Actions)
}
11 changes: 11 additions & 0 deletions pkg/view/component/testdata/config_grid_actions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"actions": [
{
"name": "name",
"actionPath": "/path",
"payload": {
"foo": "bar"
}
}
]
}
5 changes: 5 additions & 0 deletions pkg/view/component/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ func unmarshal(to TypedObject) (Component, error) {
err = errors.Wrapf(json.Unmarshal(to.Config, &t.Config),
"unmarshal graphviz config")
o = t
case typeGridActions:
t := &GridActions{base: base{Metadata: to.Metadata}}
err = errors.Wrapf(json.Unmarshal(to.Config, &t.Config),
"unmarshal gridActions config")
o = t
case typeIFrame:
t := &IFrame{base: base{Metadata: to.Metadata}}
err = errors.Wrapf(json.Unmarshal(to.Config, &t.Config),
Expand Down
18 changes: 18 additions & 0 deletions pkg/view/component/unmarshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"testing"

"github.com/stretchr/testify/require"

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

func Test_unmarshal(t *testing.T) {
Expand Down Expand Up @@ -161,6 +163,22 @@ func Test_unmarshal(t *testing.T) {
base: newBase(typeFlexLayout, nil),
},
},
{
name: "grid actions",
configFile: "config_grid_actions.json",
objectType: typeGridActions,
expected: &GridActions{
Config: GridActionsConfig{
Actions: []GridAction{
{
Name: "name",
ActionPath: "/path",
Payload: action.Payload{"foo": "bar"},
},
},
},
},
},
{
name: "labels",
configFile: "config_labels.json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ <h4>{{ title }}</h4>
></app-content-filter>
</clr-dg-filter>
</clr-dg-column>
<clr-dg-row *clrDgItems="let row of rows; trackBy: identifyRow">
<clr-dg-row *clrDgItems="let row of rowsWithMetadata; trackBy: identifyRow">
<clr-dg-action-overflow *ngIf="row.actions.length > 0">
<button *ngFor="let action of row.actions" class="action-item" (click)="runAction(action.actionPath, action.payload)">
{{action.name}}
</button>
</clr-dg-action-overflow>
<clr-dg-cell *ngFor="let column of columns; trackBy: identifyColumn">
<app-content-switcher [view]="row[column]"></app-content-switcher>
<app-content-switcher [view]="row.data[column]"></app-content-switcher>
</clr-dg-cell>
</clr-dg-row>

<clr-dg-footer>
<clr-dg-pagination #pagination [clrDgPageSize]="10">
<clr-dg-page-size [clrPageSizeOptions]="[10,20,50,100]">Items per page</clr-dg-page-size>
<ng-container *ngIf="rows?.length > 0">
<ng-container *ngIf="rowsWithMetadata?.length > 0">
{{pagination.firstItem + 1}} - {{pagination.lastItem + 1}}
of {{pagination.totalItems}} items
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import {
GridAction,
GridActionsView,
TableFilters,
TableRow,
TableView,
Expand All @@ -12,6 +14,7 @@ import {
import trackByIndex from 'src/app/util/trackBy/trackByIndex';
import trackByIdentity from 'src/app/util/trackBy/trackByIdentity';
import { ViewService } from '../../../services/view/view.service';
import { ActionService } from '../../../services/action/action.service';

@Component({
selector: 'app-view-datagrid',
Expand All @@ -29,7 +32,7 @@ export class DatagridComponent implements OnChanges {
}

columns: string[];
rows: TableRow[];
rowsWithMetadata: TableRowWithMetadata[];
title: string;
placeholder: string;
lastUpdated: Date;
Expand All @@ -41,7 +44,10 @@ export class DatagridComponent implements OnChanges {
identifyColumn = trackByIdentity;
loading: boolean;

constructor(private viewService: ViewService) {}
constructor(
private viewService: ViewService,
private actionService: ActionService
) {}

ngOnChanges(changes: SimpleChanges): void {
if (changes.view) {
Expand All @@ -51,9 +57,10 @@ export class DatagridComponent implements OnChanges {
) {
this.title = this.viewService.viewTitleAsText(this.view);

const current = changes.view.currentValue;
const current = changes.view.currentValue as TableView;
this.columns = current.config.columns.map(column => column.name);
this.rows = current.config.rows;
this.rowsWithMetadata = this.getRowsWithMetadata(current.config.rows);

this.placeholder = current.config.emptyContent;
this.lastUpdated = new Date();
this.loading = current.config.loading;
Expand All @@ -63,4 +70,28 @@ export class DatagridComponent implements OnChanges {
}
}
}

private getRowsWithMetadata(rows: TableRow[]) {
return rows.map(row => {
let actions: GridAction[] = [];

if (row.hasOwnProperty('_action')) {
actions = (row._action as GridActionsView).config.actions;
}
return {
data: row,
actions,
};
});
}

runAction(actionPath: string, payload: {}) {
const update = { ...payload, action: actionPath };
this.actionService.perform(update);
}
}

interface TableRowWithMetadata {
data: TableRow;
actions?: GridAction[];
}
12 changes: 12 additions & 0 deletions web/src/app/modules/shared/models/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,18 @@ export interface FlexLayoutView extends View {
};
}

export interface GridAction {
name: string;
actionPath: string;
payload: {};
}

export interface GridActionsView extends View {
config: {
actions: GridAction[];
};
}

export interface LabelsView extends View {
config: {
labels: { [key: string]: string };
Expand Down