From ea97eadfb792ef51473d65b84ef59c1462afab2e Mon Sep 17 00:00:00 2001 From: frikky Date: Sun, 4 Jun 2023 17:45:54 +0200 Subject: [PATCH] Added basic recommendation system to attach usecases and basic helpers to --- backend/go-app/main.go | 10 +-- backend/go-app/walkoff.go | 5 +- frontend/src/components/Priorities.jsx | 91 ++++++++++++++++++++++++++ frontend/src/components/Priority.jsx | 90 +++++++++++++++++++++++++ frontend/src/views/Admin.jsx | 26 ++++++-- 5 files changed, 212 insertions(+), 10 deletions(-) create mode 100644 frontend/src/components/Priorities.jsx create mode 100644 frontend/src/components/Priority.jsx diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 8f77bd19..71249839 100644 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -696,9 +696,9 @@ func createNewUser(username, password, role, apikey string, org shuffle.OrgMini) for tutorialIndex, tutorial := range neworg.Tutorials { if tutorial.Name == "Invite teammates" { neworg.Tutorials[tutorialIndex].Description = fmt.Sprintf("%d users are in your org. Org name and Image change next.", len(neworg.Users)) - if len(neworg.Users) > 0 { + if len(neworg.Users) > 1 { neworg.Tutorials[tutorialIndex].Done = true - neworg.Tutorials[tutorialIndex].Link = "/admin" + neworg.Tutorials[tutorialIndex].Link = "/admin?tab=users" } break @@ -1105,14 +1105,16 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) { userOrgs = shuffle.SortOrgList(userOrgs) orgPriorities := org.Priorities - if len(org.Priorities) < 5 { - log.Printf("[WARNING] Should find and add priorities as length is less than 5 for org %s", userInfo.ActiveOrg.Id) + if len(org.Priorities) < 10 { + log.Printf("[WARNING] Should find and add priorities as length is less than 10 for org %s", userInfo.ActiveOrg.Id) newPriorities, err := shuffle.GetPriorities(ctx, userInfo, org) if err != nil { log.Printf("[WARNING] Failed getting new priorities for org %s: %s", org.Id, err) //orgPriorities = []shuffle.Priority{} } else { orgPriorities = newPriorities + + // A way to manage them over time } } diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index d26cce0a..2a6f8057 100644 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -398,13 +398,14 @@ func handleGetWorkflowqueue(resp http.ResponseWriter, request *http.Request) { if !foundRecommendation { // Add to start of org.Priorities - org.Priorities = append(org.Priorities, shuffle.Priority{ + org, _ = shuffle.AddPriority(*org, shuffle.Priority{ Name: fmt.Sprintf("High CPU in environment %s", orgId), Description: fmt.Sprintf("The environment %s has been using more than %d percent CPU. This indicates you may need to look at scaling.", orgId, percentageCheck), Type: "scale", Active: true, URL: fmt.Sprintf("/admin?tab=environments"), - }) + Severity: 1, + }, false) //Make last item the first item org.Priorities = append([]shuffle.Priority{org.Priorities[len(org.Priorities)-1]}, org.Priorities[:len(org.Priorities)-1]...) diff --git a/frontend/src/components/Priorities.jsx b/frontend/src/components/Priorities.jsx new file mode 100644 index 00000000..4cc2358e --- /dev/null +++ b/frontend/src/components/Priorities.jsx @@ -0,0 +1,91 @@ +import React, { useState, useEffect } from "react"; + +import theme from "../theme.jsx"; +import { + Paper, + Typography, + Divider, + Button, + Grid, + Card, + Switch, +} from "@material-ui/core"; + +import Priority from "../components/Priority.jsx"; +import { useAlert } from "react-alert"; + +const Priorities = (props) => { + const { globalUrl, userdata, serverside, billingInfo, stripeKey, selectedOrganization, handleGetOrg, checkLogin, } = props; + const [showDismissed, setShowDismissed] = React.useState(false); + const [showRead, setShowRead] = React.useState(false); + + if (userdata === undefined || userdata === null) { + return + } + + return ( +
+

Priorities

+ + Priorities identified by Shuffle to help you discover ways to protect yourself.  + + Learn more + + +
+ { + setShowDismissed(!showDismissed); + }} + />  Show dismissed + {userdata.priorities === null || userdata.priorities === undefined || userdata.priorities.length === 0 ? + + No Priorities found + + : + userdata.priorities.map((priority, index) => { + if (showDismissed === false && priority.active === false) { + return null + } + + return ( + + ) + }) + } + +

Notifications

+ + Notifications help you find potential problems with your workflows and apps + + Learn more + + +
+ { + setShowRead(!showRead); + }} + />  Show read +
+ ) +} + +export default Priorities; diff --git a/frontend/src/components/Priority.jsx b/frontend/src/components/Priority.jsx new file mode 100644 index 00000000..d8538a9b --- /dev/null +++ b/frontend/src/components/Priority.jsx @@ -0,0 +1,90 @@ +import React, { useState, useEffect } from "react"; + +import theme from "../theme.jsx"; +import { useNavigate, Link } from "react-router-dom"; +import { + Paper, + Typography, + Divider, + Button, + Grid, + Card, +} from "@material-ui/core"; + +import { useAlert } from "react-alert"; + +const Priority = (props) => { + const { globalUrl, userdata, serverside, priority, checkLogin, } = props; + + + let navigate = useNavigate(); + const changeRecommendation = (recommendation, action) => { + const data = { + action: action, + name: recommendation.name, + }; + + fetch(`${globalUrl}/api/v1/recommendations/modify`, { + mode: "cors", + method: "POST", + body: JSON.stringify(data), + credentials: "include", + crossDomain: true, + withCredentials: true, + headers: { + "Content-Type": "application/json; charset=utf-8", + }, + }) + .then((response) => { + if (response.status === 200) { + } else { + } + + return response.json(); + }) + .then((responseJson) => { + if (responseJson.success === true) { + if (checkLogin !== undefined) { + checkLogin() + } + } else { + if (responseJson.success === false && responseJson.reason !== undefined) { + alert.error("Failed change recommendation: ", responseJson.reason) + } else { + alert.error("Failed change recommendation"); + } + } + }) + .catch((error) => { + alert.info("Failed dismissing alert. Please contact support@shuffler.io if this persists."); + }); + } + + return ( +
+
+ + {priority.name} + + + {priority.description} + +
+
+ + {priority.active === true ? + + : null } +
+
+ ) +} + +export default Priority; diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index fefe1adb..520103c2 100644 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -80,6 +80,7 @@ import HandlePaymentNew from "../views/HandlePaymentNew.jsx"; import OrgHeader from "../components/OrgHeader.jsx"; import OrgHeaderexpanded from "../components/OrgHeaderexpanded.jsx"; import Billing from "../components/Billing.jsx"; +import Priorities from "../components/Priorities.jsx"; import Branding from "../components/Branding.jsx"; import Files from "../components/Files.jsx"; import { display, style } from "@mui/system"; @@ -1359,9 +1360,9 @@ const Admin = (props) => { const admin_views = { 0: "organization", 1: "cloud_sync", - 2: "billing", - 3: "branding", - 4: "cache", + 2: "priorities", + 3: "billing", + 4: "branding", }; const setConfig = (event, inputValue) => { @@ -2309,6 +2310,11 @@ const Admin = (props) => { Cloud Synchronization /> + + Priorities + + /> @@ -2577,6 +2583,18 @@ const Admin = (props) => {
) : adminTab === 2 ? + + : adminTab === 3 ? { stripeKey={props.stripeKey} handleGetOrg={handleGetOrg} /> - : adminTab === 3 ? + : adminTab === 4 ?