diff --git a/client/src/app/ctl/phase/phase.component.css b/client/src/app/ctl/phase/phase.component.css
index 65361f8..4b82b27 100644
--- a/client/src/app/ctl/phase/phase.component.css
+++ b/client/src/app/ctl/phase/phase.component.css
@@ -39,6 +39,11 @@
flex-direction: row;
}
+.unloaded-phase {
+ display: flex;
+ flex-direction: row;
+}
+
.docless-phase-btn {
padding-left: 20px;
padding-right: 0px;
diff --git a/client/src/app/ctl/phase/phase.component.html b/client/src/app/ctl/phase/phase.component.html
index a1e2823..9f17552 100755
--- a/client/src/app/ctl/phase/phase.component.html
+++ b/client/src/app/ctl/phase/phase.component.html
@@ -20,9 +20,31 @@
-
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/client/src/app/ctl/phase/phase.component.ts b/client/src/app/ctl/phase/phase.component.ts
index 1538722..c1520b5 100755
--- a/client/src/app/ctl/phase/phase.component.ts
+++ b/client/src/app/ctl/phase/phase.component.ts
@@ -44,6 +44,7 @@ export class PhaseComponent implements WsReceiver {
activeLink = 'overview';
phaseTree: KustomNode[] = [];
+ clickedNode: KustomNode;
treeControl = new NestedTreeControl(node => node.children);
dataSource = new MatTreeNestedDataSource();
@@ -84,6 +85,9 @@ export class PhaseComponent implements WsReceiver {
case WsConstants.GET_PHASE:
this.handleGetPhase(message);
break;
+ case WsConstants.GET_PHASE_SOURCE_FILES:
+ this.handleGetPhaseSourceFiles(message);
+ break;
case WsConstants.GET_YAML:
this.handleGetYaml(message);
break;
@@ -109,6 +113,13 @@ export class PhaseComponent implements WsReceiver {
}
}
+ handleGetPhaseSourceFiles(message: WsMessage): void {
+ this.clickedNode.running = false;
+ const data: KustomNode[] = [];
+ Object.assign(data, message.data);
+ this.updateTree(data);
+ }
+
handleValidatePhase(message: WsMessage): void {
this.websocketService.printIfToast(message);
}
@@ -288,4 +299,30 @@ export class PhaseComponent implements WsReceiver {
}
}
}
+
+ getPhaseSourceFiles(node: KustomNode): void {
+ const msg = new WsMessage(this.type, this.component, WsConstants.GET_PHASE_SOURCE_FILES);
+ msg.id = JSON.stringify(node.phaseId);
+ this.websocketService.sendMessage(msg);
+ }
+
+ refreshTreeData(): void {
+ const tmpdata = this.dataSource.data;
+ this.dataSource.data = null;
+ this.dataSource.data = tmpdata;
+ }
+
+ loadPhase(node: KustomNode): void {
+ this.clickedNode = node;
+ this.clickedNode.running = true;
+ this.getPhaseSourceFiles(this.clickedNode);
+ }
+
+ updateTree(data: KustomNode[]): void {
+ if (this.clickedNode !== undefined) {
+ this.clickedNode.children = data;
+ this.clickedNode.hasDocuments = false;
+ this.refreshTreeData();
+ }
+ }
}
diff --git a/client/src/app/ctl/phase/phase.models.ts b/client/src/app/ctl/phase/phase.models.ts
index 39365bd..2ebe666 100644
--- a/client/src/app/ctl/phase/phase.models.ts
+++ b/client/src/app/ctl/phase/phase.models.ts
@@ -16,7 +16,7 @@ export class KustomNode {
id: string;
phaseId: { Name: string, Namespace: string};
name: string;
- canLoadChildren: boolean;
+ hasDocuments: boolean;
children: KustomNode[];
isPhaseNode: boolean;
running: boolean;
diff --git a/client/src/services/ws/ws.models.ts b/client/src/services/ws/ws.models.ts
index 2631809..52b5d4f 100755
--- a/client/src/services/ws/ws.models.ts
+++ b/client/src/services/ws/ws.models.ts
@@ -81,6 +81,7 @@ export class WsConstants {
public static readonly GET_DOCUMENT_BY_SELECTOR = 'getDocumentsBySelector';
public static readonly GET_EXECUTOR_DOC = 'getExecutorDoc';
public static readonly GET_PHASE = 'getPhase';
+ public static readonly GET_PHASE_SOURCE_FILES = 'getPhaseSourceFiles';
public static readonly GET_PHASE_TREE = 'getPhaseTree';
public static readonly GET_TARGET = 'getTarget';
public static readonly GET_YAML = 'getYaml';
diff --git a/pkg/configs/configs.go b/pkg/configs/configs.go
index 7998391..2f2966b 100644
--- a/pkg/configs/configs.go
+++ b/pkg/configs/configs.go
@@ -178,7 +178,7 @@ const (
GetYaml WsSubComponentType = "getYaml"
GetRendered WsSubComponentType = "getRendered"
GetPhaseTree WsSubComponentType = "getPhaseTree"
- GetPhaseSourceFiles WsSubComponentType = "getPhaseSource"
+ GetPhaseSourceFiles WsSubComponentType = "getPhaseSourceFiles"
GetDocumentsBySelector WsSubComponentType = "getDocumentsBySelector"
GetPhase WsSubComponentType = "getPhase"
GetExecutorDoc WsSubComponentType = "getExecutorDoc"
diff --git a/pkg/ctl/phase.go b/pkg/ctl/phase.go
index 1b7ae07..3184e2e 100644
--- a/pkg/ctl/phase.go
+++ b/pkg/ctl/phase.go
@@ -89,6 +89,8 @@ func HandlePhaseRequest(user *string, request configs.WsMessage) configs.WsMessa
s := "rendered"
message = &s
response.Name, response.YAML, err = client.GetExecutorDoc(id)
+ case configs.GetPhaseSourceFiles:
+ response.Data, err = client.getPhaseSource(id)
default:
err = fmt.Errorf("Subcomponent %s not found", request.SubComponent)
}
@@ -103,6 +105,17 @@ func HandlePhaseRequest(user *string, request configs.WsMessage) configs.WsMessa
return response
}
+func (c *Client) getPhaseSource(id string) ([]KustomNode, error) {
+ phaseID := ifc.ID{}
+
+ err := json.Unmarshal([]byte(id), &phaseID)
+ if err != nil {
+ return nil, err
+ }
+
+ return c.GetPhaseSourceFiles(phaseID)
+}
+
// this helper function will likely disappear once a clear workflow for
// phase validation takes shape in UI. For now, it simply returns a
// string message to be displayed as a toast in frontend client
diff --git a/pkg/ctl/tree.go b/pkg/ctl/tree.go
index dafbbde..7acb541 100644
--- a/pkg/ctl/tree.go
+++ b/pkg/ctl/tree.go
@@ -70,26 +70,14 @@ func (client *Client) GetPhaseTree() ([]KustomNode, error) {
for _, p := range phases {
pNode := KustomNode{
- ID: uuid.New().String(),
- PhaseID: ifc.ID{Name: p.Name, Namespace: p.Namespace},
- Name: fmt.Sprintf("Phase: %s", p.Name),
- IsPhaseNode: true,
- Children: []KustomNode{},
+ ID: uuid.New().String(),
+ PhaseID: ifc.ID{Name: p.Name, Namespace: p.Namespace},
+ Name: fmt.Sprintf("Phase: %s", p.Name),
+ IsPhaseNode: true,
+ HasDocuments: p.Config.DocumentEntryPoint != "",
+ Children: []KustomNode{},
}
- // some phases don't have any associated documents, so don't look
- // for children unless a DocumentEntryPoint has been specified
- if p.Config.DocumentEntryPoint != "" {
- children, err := client.GetPhaseSourceFiles(pNode.PhaseID)
- if err != nil {
- // TODO(mfuller): push an error to UI so it can be handled by
- // toastr service, pending refactor of webservice and configs pkgs
- log.Errorf("Error building tree for phase '%s': %s", p.Name, err)
- pNode.HasError = true
- } else {
- pNode.Children = children
- }
- }
nodes = append(nodes, pNode)
}
@@ -181,12 +169,13 @@ func (client *Client) GetPhaseSourceFiles(id ifc.ID) ([]KustomNode, error) {
// KustomNode structure to represent the kustomization tree for a given phase
// bundle to be consumed by the UI frontend
type KustomNode struct {
- ID string `json:"id"` // UUID for backend node index
- PhaseID ifc.ID `json:"phaseId"`
- Name string `json:"name"` // name used for display purposes (cli, ui)
- IsPhaseNode bool `json:"isPhaseNode"`
- HasError bool `json:"hasError"`
- Children []KustomNode `json:"children"`
+ ID string `json:"id"`
+ PhaseID ifc.ID `json:"phaseId"`
+ Name string `json:"name"`
+ IsPhaseNode bool `json:"isPhaseNode"`
+ HasError bool `json:"hasError"`
+ HasDocuments bool `json:"hasDocuments"`
+ Children []KustomNode `json:"children"`
}
func contains(dirs []string, val string) bool {