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

Commit

Permalink
Create grid action
Browse files Browse the repository at this point in the history
Create grid action that allows users of the table component add grid actions. It allows Octant to take advantage of https://clarity.design/documentation/datagrid/single-action

Signed-off-by: bryanl <bryanliles@gmail.com>
  • Loading branch information
bryanl committed Mar 29, 2020
1 parent a9f41ce commit 6364f21
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 7 deletions.
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

0 comments on commit 6364f21

Please sign in to comment.