From 2de1f1355a621a282dccd16a13f6e891f9a5280d Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 16:34:25 +0530 Subject: [PATCH 01/33] feat[health-page]: adding health page to onprem --- frontend/src/App.jsx | 34 +++ frontend/src/components/HealthBarChart.jsx | 22 ++ frontend/src/components/HealthPage.jsx | 317 +++++++++++++++++++++ 3 files changed, 373 insertions(+) create mode 100644 frontend/src/components/HealthBarChart.jsx create mode 100644 frontend/src/components/HealthPage.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index dba2d5db..639b80bd 100755 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -9,6 +9,8 @@ import GettingStarted from "./views/GettingStarted"; import AngularWorkflow from "./views/AngularWorkflow.jsx"; import Header from "./components/NewHeader.jsx"; +import HealthPage from "./components/HealthPage.jsx"; + //import Header from "./components/Header.jsx"; import theme from "./theme"; import Apps from "./views/Apps"; @@ -272,6 +274,38 @@ const App = (message, props) => { /> } /> + + } + /> + + } + /> {userdata.id !== undefined ? ( { + const { globalUrl, filteredData, options, onBarClick } = props; + + return ( + { + if (elements && elements.length > 0) { + onBarClick(elements); + } + }} + /> + ); +}; + +export default HealthBarChart; diff --git a/frontend/src/components/HealthPage.jsx b/frontend/src/components/HealthPage.jsx new file mode 100644 index 00000000..3ad6ad8b --- /dev/null +++ b/frontend/src/components/HealthPage.jsx @@ -0,0 +1,317 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { Bar } from 'react-chartjs-2'; +//import healthData1 from '../healthstats1.json'; +import { toast } from "react-toastify" +import CheckOutlinedIcon from '@mui/icons-material/CheckOutlined'; +import { + Button, + ButtonGroup, + Typography, +} from "@mui/material"; +import HealthBarChart from '../components/HealthBarChart.jsx'; + +const HealthPage = (props) => { + const { userdata } = props; + const [healthData, setHealthData] = useState(null); + const [selectedRange, setSelectedRange] = useState('30d'); + const [filteredData, setFilteredData] = useState([]); + const [averageUptime, setAverageUptime] = useState(0); + + const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io"; + const globalUrl = `https://shuffler.io` + + console.log("HEALTHPAGE 1") + + const fetchHealthStats = useCallback(async () => { + //const after = new Date().getTime() - 90 * 24 * 60 * 60 + try { + //const response = await fetch(`${globalUrl}/api/v1/health/stats?after=${after}`, { + const response = await fetch(`${globalUrl}/api/v1/health/stats`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }); + if (!response.ok) { + throw new Error("Failed to fetch health stats"); + } + const data = await response.json(); + setHealthData(data); + } catch (error) { + console.error("Error fetching health stats:", error); + toast.error("Failed loading health stats"); + } + }, [globalUrl]); + + useEffect(() => { + fetchHealthStats(); + }, [fetchHealthStats]); + + const extractRunFinished = (data, range) => { + if (!data || !Array.isArray(data)) return []; + + const currentDate = new Date().getTime(); + const rangeInMillis = { + '24hr': 24 * 60 * 60 * 1000, + '7day': 7 * 24 * 60 * 60 * 1000, + '30d': 30 * 24 * 60 * 60 * 1000, + '90d': 90 * 24 * 60 * 60 * 1000 + } + const filteredData = data.filter(item => currentDate - item.updated * 1000 <= rangeInMillis[range]) + + const aggregatedData = new Map() + + filteredData.forEach(item => { + const timestamp = item.updated * 1000; // Convert Unix timestamp to milliseconds + let key; + + switch (range) { + case '24hr': + const date = new Date(timestamp); + const hour = date.getHours(); + const formattedDate = `${date.toLocaleDateString()} ${hour}:00`; + key = formattedDate; + break; + case '7day': + const date1 = new Date(timestamp); + const hour1 = date1.getHours(); + const formattedDate1 = `${date1.toLocaleDateString()} ${hour1}:00`; + key = formattedDate1; + break; + default: + key = new Date(timestamp).toLocaleDateString(); + } + + // Check if date already exists in the map + if (aggregatedData.has(key)) { + // Update aggregated values + const existingData = aggregatedData.get(key); + existingData.totalEntries++; + existingData.totalRunFinished += item.workflows.run_finished ? 1 : 0; + existingData.executionIds.push(item.workflows.execution_id); + } else { + // Add new entry to the map + aggregatedData.set(key, { + totalEntries: 1, + totalRunFinished: item.workflows.run_finished ? 1 : 0, + executionIds: [item.workflows.execution_id] + }); + } + }); + + // Calculate averages and assign colors + const result = Array.from(aggregatedData.entries()).map(([key, { totalEntries, totalRunFinished, executionIds }]) => { + const avg = totalEntries > 0 ? totalRunFinished / totalEntries : 0; + const FinalAvg = avg * 100; + let color; + + if (FinalAvg >= 100) { + color = '#00F670'; + } else if (FinalAvg >= 98.50 && FinalAvg <= 99.99) { + color = '#FFD700'; + } else if (FinalAvg <= 98.49) { + color = '#FF354C'; + } + + return { + date: range === '24hr' ? `${key}:00` : key, + avgRunFinished: FinalAvg, + color, + executionIds + }; + }); + + return result; + }; + + + useEffect(() => { + if (healthData) { + const newData = extractRunFinished(healthData, selectedRange); + setFilteredData(newData); + + const totalUptime = newData.reduce((acc, curr) => acc + curr.avgRunFinished, 0); + const avgUptime = totalUptime / newData.length; + setAverageUptime(avgUptime); + } + }, [selectedRange, healthData]); + + const filterDataByRange = (range) => { + setSelectedRange(range); + }; + + const updateChartData = () => { + if (!filteredData) { + return { + labels: [], + datasets: [{ + label: "", + data: [], + backgroundColor: [], + borderWidth: 1, + barThickness: 7, // Default bar thickness + }], + }; + } + let barThickness = 7; + + const labels = filteredData.map((value, i) => { + if (selectedRange === '24hr') { + const [datePart, hourPart] = value.date.split(' '); + const [day, month, year] = datePart.split('/'); + const monthIndex = parseInt(month, 10) - 1; + const date = new Date(year, monthIndex, day); + let formattedDate = `${date.toLocaleString('en-US', { month: 'short', day: '2-digit' })}`; + + // Add hour part if available + if (hourPart) { + formattedDate += `, ${hourPart.split(':').slice(0, 2).join(':')}`; + } + return `${formattedDate} \nUptime: ${value.avgRunFinished.toFixed(2)}%`; + } else if (selectedRange === '7day') { + const [datePart, hourPart] = value.date.split(' '); + const [day, month, year] = datePart.split('/'); + const monthIndex = parseInt(month, 10) - 1; + const date = new Date(year, monthIndex, day); + let formattedDate = `${date.toLocaleString('en-US', { month: 'short', day: '2-digit' })}`; + + // Add hour part if available + if (hourPart) { + formattedDate += `, ${hourPart.split(':').slice(0, 2).join(':')}`; + } + return `${formattedDate} \nUptime: ${value.avgRunFinished.toFixed(2)}%`; + } + else { + const dateParts = value.date.split('/'); // Assuming the date format is "DD/MM/YYYY" + const date = new Date(`${dateParts[2]}-${dateParts[1]}-${dateParts[0]}`); // Reformat the date string to "YYYY-MM-DD" + return `${date.toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' })} \nUptime: ${value.avgRunFinished.toFixed(2)}%`; + } + }); + + + if (selectedRange === '24hr') { + barThickness = 35; + } + else if (selectedRange === '7day') { + barThickness = 5; + } + else if (selectedRange === '30d') { + barThickness = 25; + } + // let width = 800; // Default chart width + // if (selectedRange === '7day') { + // width = 400; // Adjust chart width for 7 days + // } else if (selectedRange === '30d') { + // width = 600; // Adjust chart width for 30 days + // } + + const datasets = [{ + label: "", + data: filteredData.map(item => 1), + backgroundColor: filteredData.map(item => item.color), + borderWidth: 1, + barThickness: barThickness, + // barPercentage: barPercentage, + }]; + + return { labels, datasets }; + }; + + console.log("HEALTHPAGE 2") + + const options = { + legend: { + display: false + }, + layout: { + padding: { + top: 0, // Adjust the top padding as needed + bottom: 20, // Adjust the bottom padding as needed + left: 20, // Adjust the left padding as needed + right: 20 // Adjust the right padding as needed + } + }, + scales: { + yAxes: [{ + ticks: { + display: false + } + }], + xAxes: [{ + ticks: { + display: false + } + }] + }, + tooltips: { + callbacks: { + label: function (tooltipItem, data) { + const label = data.labels[tooltipItem.index]; + return label.split('\n')[0]; // Return only the date part + }, + afterLabel: function (tooltipItem, data) { + const label = data.labels[tooltipItem.index]; + // console.log(label) + const uptime = label.match(/Uptime:\s*(\d+(?:\.\d+)?)/)[1]; // Extract uptime value using regex + return `Success Rate: ${uptime}%`; // Customize the uptime display + }, + title: function () { + return 'Fully Oprational'; // Hide the tooltip title + } + } + } + }; + + const handleBarClick = (event, elements) => { + if (event && event.length > 0) { + const clickedIndex = event[0]._index + const clickedData = filteredData[clickedIndex] + const executionIds = clickedData.executionIds + .filter(executionId => { + const item = healthData.find(dataItem => dataItem.workflows.execution_id === executionId); + return item && item.workflows.run_finished === false; + }); + + // console.log("Filtered Execution IDs:", executionIds); + if (executionIds.length > 0) { + const url = `${globalUrl}/api/v1/health/stats?execution_id=${executionIds.join(',')}`; + window.open(url, '_blank'); + } else { + toast.success("All executions in selected period succeeded"); + } + } + }; + + + return ( +
+ + + + + + + + + +
+
+ +
+ Workflow Health + Operational +
+
+ {averageUptime.toFixed(2)}% + Success Rate +
+
+ +
+
+ ); +}; + +export default HealthPage; From 00ac276603b880c319df1652d873bc794033f4e2 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 17:51:11 +0530 Subject: [PATCH 02/33] fix[auth-overrides]: frontend loading fixes --- frontend/src/views/AngularWorkflow.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index 2b1a97a2..5bb4adb7 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -3915,8 +3915,7 @@ const AngularWorkflow = (defaultprops) => { if (data.app_name === "Shuffle Workflow") { console.log("Shuffle Workflow selected") - if (data.parameters[0].value !== undefined && data.parameters[0].value !== null && data.parameters[0].value.length > 0) { - console.log("Get workflow apps calling") + if ((data.parameters !== undefined) && (data.parameters.length > 0)) { getWorkflowApps(data.parameters[0].value) } } From 52bdc86551964e5ff8aa2565b70f01cc68c6c2f0 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 18:24:03 +0530 Subject: [PATCH 03/33] fix[user-account-deletion]: enabled it for onprem --- backend/go-app/go.mod | 2 +- backend/go-app/main.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index 6e4b2ef2..3adc7095 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -20,7 +20,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/h2non/filetype v1.1.3 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.6.27 + github.com/shuffle/shuffle-shared v0.6.28 golang.org/x/crypto v0.22.0 google.golang.org/api v0.176.1 google.golang.org/grpc v1.63.2 diff --git a/backend/go-app/main.go b/backend/go-app/main.go index 62870a45..020d0258 100755 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -4926,6 +4926,7 @@ func initHandlers() { r.HandleFunc("/api/v1/users/getsettings", shuffle.HandleSettings).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/users/getusers", shuffle.HandleGetUsers).Methods("GET", "OPTIONS") r.HandleFunc("/api/v1/users/updateuser", shuffle.HandleUpdateUser).Methods("PUT", "OPTIONS") + r.HandleFunc("/api/v1/users/{userID}/remove", shuffle.HandleDeleteUsersAccount).Methods("DELETE", "OPTIONS") r.HandleFunc("/api/v1/users/{user}", shuffle.DeleteUser).Methods("DELETE", "OPTIONS") r.HandleFunc("/api/v1/users/passwordchange", shuffle.HandlePasswordChange).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/users/{key}/get2fa", shuffle.HandleGet2fa).Methods("GET", "OPTIONS") From 1f410674b98744f4dbde58df264070513d461f4a Mon Sep 17 00:00:00 2001 From: yashsinghcodes Date: Wed, 22 May 2024 13:08:11 +0000 Subject: [PATCH 04/33] discord img fix --- frontend/src/components/NewHeader.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/NewHeader.jsx b/frontend/src/components/NewHeader.jsx index 0757f6fc..19c26fb5 100644 --- a/frontend/src/components/NewHeader.jsx +++ b/frontend/src/components/NewHeader.jsx @@ -541,7 +541,7 @@ const Header = (props) => { > Discord Community Join From 166b251ffac81e56229705ef0c2cc2ce386f3934 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 19:35:09 +0530 Subject: [PATCH 05/33] fix[docker-compose]: making all images as latest --- docker-compose.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2c50d5a1..2f096df2 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: frontend: - image: ghcr.io/shuffle/shuffle-frontend:nightly + image: ghcr.io/shuffle/shuffle-frontend:latest container_name: shuffle-frontend hostname: shuffle-frontend ports: @@ -15,7 +15,7 @@ services: depends_on: - backend backend: - image: ghcr.io/shuffle/shuffle-backend:nightly + image: ghcr.io/shuffle/shuffle-backend:latest container_name: shuffle-backend hostname: ${BACKEND_HOSTNAME} # Here for debugging: @@ -34,7 +34,7 @@ services: - SHUFFLE_FILE_LOCATION=/shuffle-files restart: unless-stopped orborus: - image: ghcr.io/shuffle/shuffle-orborus:nightly + image: ghcr.io/shuffle/shuffle-orborus:latest container_name: shuffle-orborus hostname: shuffle-orborus networks: From 6b18e90e3bc2c52b28c377b8f07019454fcf86d2 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 20:23:38 +0530 Subject: [PATCH 06/33] init: quick testing --- .github/workflows/quick-testing.yml | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/quick-testing.yml diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml new file mode 100644 index 00000000..f36c6241 --- /dev/null +++ b/.github/workflows/quick-testing.yml @@ -0,0 +1,31 @@ +name: Docker Compose Up and Ping + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Docker + run: | + curl -fsSL https://get.docker.com | sh + sudo systemctl start docker + + - name: Set up Docker Compose + run: | + curl -L "https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose + docker-compose version + + - name: Start Docker Compose + run: docker-compose up -d + + - name: Wait for services to start + run: sleep 20 + + - name: Ping localhost + run: curl --fail http://localhost:3001 || exit 1 From 6119655d318111b2272012df313c4131544fbd4f Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 20:29:57 +0530 Subject: [PATCH 07/33] fix: trying out docker-compose in actions --- .github/workflows/quick-testing.yml | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index f36c6241..f09cf801 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -10,22 +10,8 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - - name: Set up Docker - run: | - curl -fsSL https://get.docker.com | sh - sudo systemctl start docker - - - name: Set up Docker Compose - run: | - curl -L "https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose - chmod +x /usr/local/bin/docker-compose - docker-compose version - - - name: Start Docker Compose + - name: Build the stack run: docker-compose up -d - - name: Wait for services to start - run: sleep 20 - - - name: Ping localhost - run: curl --fail http://localhost:3001 || exit 1 + - name: In 30 seconds, check docker ps + run: sleep 30 && docker ps \ No newline at end of file From 8f3e663f20a20a3ee162da5eb874d7024ce25f04 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 20:54:18 +0530 Subject: [PATCH 08/33] fix: making testing end-to-end --- .github/workflows/quick-testing.yml | 83 ++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index f09cf801..b183b50d 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -13,5 +13,84 @@ jobs: - name: Build the stack run: docker-compose up -d - - name: In 30 seconds, check docker ps - run: sleep 30 && docker ps \ No newline at end of file + - name: Wait for 30 seconds + run: sleep 30 + + - name: Check for restarting containers in a loop + run: | + ATTEMPTS=30 # Total time = ATTEMPTS * 5 seconds = 30 seconds + for i in $(seq 1 $ATTEMPTS); do + RESTARTING_CONTAINERS=$(docker ps --filter "status=restarting" --format "{{.Names}}") + if [ -n "$RESTARTING_CONTAINERS" ]; then + echo "The following containers are restarting:" + echo "$RESTARTING_CONTAINERS" + exit 1 + fi + echo "No containers are restarting. Attempt $i/$ATTEMPTS." + sleep 1 + done + echo "No containers were found in a restarting state after $ATTEMPTS checks." + + - name: Check if the response from the web service includes "Shuffle" + run: | + RESPONSE=$(curl -s http://localhost:3001) + if echo "$RESPONSE" | grep -q "Shuffle"; then + echo "The word 'Shuffle' was found in the response." + else + echo "The word 'Shuffle' was not found in the response." + exit 1 + fi + + - name: Register a user and check the status code + run: | + STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" 'http://localhost:3001/api/v1/register' \ + -H 'Accept: */*' \ + -H 'Accept-Language: en-US,en;q=0.9' \ + -H 'Connection: keep-alive' \ + -H 'Content-Type: application/json' \ + --data-raw '{"username":"demo@demo.io","password":"supercoolpassword"}') + if [ "$STATUS_CODE" -eq 200 ]; then + echo "User registration was successful with status code 200." + else + echo "User registration failed with status code $STATUS_CODE." + exit 1 + fi + + - name: Get the API key and run a health check + run: | + RESPONSE=$(curl -s -k -u admin:StrongShufflePassword321! 'https://localhost:9200/users/_search') + API_KEY=$(echo "$RESPONSE" | jq -r '.hits.hits[0]._source.apikey') + if [ -n "$API_KEY" ]; then + echo "Admin API key: $API_KEY" + else + echo "Failed to retrieve the API key for the admin user." + exit 1 + fi + + HEALTH_RESPONSE=$(curl -s 'http://localhost:3001/api/v1/health?force=true' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \ + -H 'Accept-Language: en-US,en;q=0.9' \ + -H 'Connection: keep-alive' \ + -H 'Sec-Fetch-Dest: document' \ + -H 'Sec-Fetch-Mode: navigate' \ + -H 'Sec-Fetch-Site: none' \ + -H "Authorization: Bearer $API_KEY" \ + -H 'Sec-Fetch-User: ?1' \ + -H 'Upgrade-Insecure-Requests: 1' \ + -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36' \ + -H 'sec-ch-ua: "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"' \ + -H 'sec-ch-ua-mobile: ?0' \ + -H 'sec-ch-ua-platform: "macOS"') + + WORKFLOWS_CREATE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.create') + WORKFLOWS_RUN=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run') + WORKFLOWS_RUN_FINISHED=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run_finished') + WORKFLOWS_RUN_STATUS=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run_status') + WORKFLOWS_DELETE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.delete') + + if [ "$WORKFLOWS_CREATE" = "true" ] && [ "$WORKFLOWS_RUN" = "true" ] && [ "$WORKFLOWS_RUN_FINISHED" = "true" ] && [ "$WORKFLOWS_RUN_STATUS" = "FINISHED" ] && [ "$WORKFLOWS_DELETE" = "true" ]; then + echo "Health endpoint check was successful." + else + echo "Health endpoint check failed. Response did not meet expected criteria." + exit 1 + fi From b2cc556b6f0e6e78382b8958447036f012055f33 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 20:58:59 +0530 Subject: [PATCH 09/33] fix: tackling 502s --- .github/workflows/quick-testing.yml | 38 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index b183b50d..b8e73daa 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -43,18 +43,32 @@ jobs: - name: Register a user and check the status code run: | - STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" 'http://localhost:3001/api/v1/register' \ - -H 'Accept: */*' \ - -H 'Accept-Language: en-US,en;q=0.9' \ - -H 'Connection: keep-alive' \ - -H 'Content-Type: application/json' \ - --data-raw '{"username":"demo@demo.io","password":"supercoolpassword"}') - if [ "$STATUS_CODE" -eq 200 ]; then - echo "User registration was successful with status code 200." - else - echo "User registration failed with status code $STATUS_CODE." - exit 1 - fi + MAX_RETRIES=30 + RETRY_INTERVAL=2 + + for (( i=1; i<=$MAX_RETRIES; i++ )) + do + STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" 'http://localhost:3001/api/v1/register' \ + -H 'Accept: */*' \ + -H 'Accept-Language: en-US,en;q=0.9' \ + -H 'Connection: keep-alive' \ + -H 'Content-Type: application/json' \ + --data-raw '{"username":"demo@demo.io","password":"supercoolpassword"}') + + if [ "$STATUS_CODE" -eq 200 ]; then + echo "User registration was successful with status code 200." + exit 0 + elif [ "$STATUS_CODE" -ne 502 ]; then + echo "User registration failed with status code $STATUS_CODE." + exit 1 + fi + + echo "Received status code 502. Retrying in $RETRY_INTERVAL seconds... ($i/$MAX_RETRIES)" + sleep $RETRY_INTERVAL + done + + echo "User registration failed after $MAX_RETRIES attempts." + exit 1 - name: Get the API key and run a health check run: | From c57117e298728b16e549eb073bb09bbbaf7dd59d Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:04:07 +0530 Subject: [PATCH 10/33] fix: debugging 502s in pinging --- .github/workflows/quick-testing.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index b8e73daa..881f2474 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -44,7 +44,8 @@ jobs: - name: Register a user and check the status code run: | MAX_RETRIES=30 - RETRY_INTERVAL=2 + RETRY_INTERVAL=5 + CONTAINER_NAME="shuffle-backend" for (( i=1; i<=$MAX_RETRIES; i++ )) do @@ -60,6 +61,8 @@ jobs: exit 0 elif [ "$STATUS_CODE" -ne 502 ]; then echo "User registration failed with status code $STATUS_CODE." + echo "Fetching last 30 lines of logs from container $CONTAINER_NAME..." + docker logs --tail 30 "$CONTAINER_NAME" exit 1 fi From 728f5d1d16dc49232471bedafe3998fde545077d Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:10:08 +0530 Subject: [PATCH 11/33] fix: debugging 502s in pinging (1) --- .github/workflows/quick-testing.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index 881f2474..2160022c 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -44,7 +44,7 @@ jobs: - name: Register a user and check the status code run: | MAX_RETRIES=30 - RETRY_INTERVAL=5 + RETRY_INTERVAL=10 CONTAINER_NAME="shuffle-backend" for (( i=1; i<=$MAX_RETRIES; i++ )) @@ -62,7 +62,8 @@ jobs: elif [ "$STATUS_CODE" -ne 502 ]; then echo "User registration failed with status code $STATUS_CODE." echo "Fetching last 30 lines of logs from container $CONTAINER_NAME..." - docker logs --tail 30 "$CONTAINER_NAME" + logs_output=$(docker logs --tail 30 "$CONTAINER_NAME") + echo "$logs_output" exit 1 fi From 00438d7b9ced29068783e891e524208f2bdc1372 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:12:37 +0530 Subject: [PATCH 12/33] fix: debugging 502s in pinging (2) --- .github/workflows/quick-testing.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index 2160022c..ae194436 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -61,13 +61,13 @@ jobs: exit 0 elif [ "$STATUS_CODE" -ne 502 ]; then echo "User registration failed with status code $STATUS_CODE." - echo "Fetching last 30 lines of logs from container $CONTAINER_NAME..." - logs_output=$(docker logs --tail 30 "$CONTAINER_NAME") - echo "$logs_output" exit 1 fi - echo "Received status code 502. Retrying in $RETRY_INTERVAL seconds... ($i/$MAX_RETRIES)" + echo "Received status code $STATUS_CODE. Retrying in $RETRY_INTERVAL seconds... ($i/$MAX_RETRIES)" + echo "Fetching last 30 lines of logs from container $CONTAINER_NAME..." + logs_output=$(docker logs --tail 30 "$CONTAINER_NAME") + echo "$logs_output" sleep $RETRY_INTERVAL done From 800b108c325a6b786e7de8d9183872e00ac746d7 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:15:35 +0530 Subject: [PATCH 13/33] fix: debugging 502s in pinging (3) --- .github/workflows/quick-testing.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index ae194436..e86d3fce 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -65,9 +65,17 @@ jobs: fi echo "Received status code $STATUS_CODE. Retrying in $RETRY_INTERVAL seconds... ($i/$MAX_RETRIES)" + echo "Fetching last 30 lines of logs from container $CONTAINER_NAME..." + logs_output=$(docker logs --tail 30 "$CONTAINER_NAME") echo "$logs_output" + + echo "Fetching last 30 lines of logs from container shuffle-opensearch..." + + opensearch_logs=$(docker logs --tail 30 shuffle-opensearch) + echo "$opensearch_logs" + sleep $RETRY_INTERVAL done From 10b05a883e6ae7ca62402b1d7f02d4380d8d8352 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:19:33 +0530 Subject: [PATCH 14/33] fix: debugging 502s in pinging (4) --- .github/workflows/quick-testing.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index e86d3fce..9dbf950e 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -9,6 +9,9 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v2 + + - name: Set up opensearch directory + run: mkdir shuffle-database && chmod -R 755 shuffle-database - name: Build the stack run: docker-compose up -d @@ -31,7 +34,7 @@ jobs: done echo "No containers were found in a restarting state after $ATTEMPTS checks." - - name: Check if the response from the web service includes "Shuffle" + - name: Check if the response from the frontend contains the word "Shuffle" run: | RESPONSE=$(curl -s http://localhost:3001) if echo "$RESPONSE" | grep -q "Shuffle"; then @@ -65,7 +68,6 @@ jobs: fi echo "Received status code $STATUS_CODE. Retrying in $RETRY_INTERVAL seconds... ($i/$MAX_RETRIES)" - echo "Fetching last 30 lines of logs from container $CONTAINER_NAME..." logs_output=$(docker logs --tail 30 "$CONTAINER_NAME") From 279950883b43188ccbfd7a3cde83b68d4ca85351 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:22:17 +0530 Subject: [PATCH 15/33] fix: debugging 502s in pinging (5) --- .github/workflows/quick-testing.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index 9dbf950e..cbdfd1dd 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 - name: Set up opensearch directory - run: mkdir shuffle-database && chmod -R 755 shuffle-database + run: mkdir shuffle-database && chmod -R 1000:1000 shuffle-database - name: Build the stack run: docker-compose up -d @@ -19,8 +19,9 @@ jobs: - name: Wait for 30 seconds run: sleep 30 - - name: Check for restarting containers in a loop + - name: Check for restarting containers in a loop and fixing perms again once run: | + chmod -R 1000:1000 shuffle-database ATTEMPTS=30 # Total time = ATTEMPTS * 5 seconds = 30 seconds for i in $(seq 1 $ATTEMPTS); do RESTARTING_CONTAINERS=$(docker ps --filter "status=restarting" --format "{{.Names}}") From d3c344e39b7897b707acf781ab635ed77fa02801 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:24:53 +0530 Subject: [PATCH 16/33] fix: debugging 502s in pinging (6) --- .github/workflows/quick-testing.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index cbdfd1dd..6c53238d 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 - name: Set up opensearch directory - run: mkdir shuffle-database && chmod -R 1000:1000 shuffle-database + run: mkdir shuffle-database && chown -R 1000:1000 shuffle-database - name: Build the stack run: docker-compose up -d @@ -21,7 +21,7 @@ jobs: - name: Check for restarting containers in a loop and fixing perms again once run: | - chmod -R 1000:1000 shuffle-database + chown -R 1000:1000 shuffle-database ATTEMPTS=30 # Total time = ATTEMPTS * 5 seconds = 30 seconds for i in $(seq 1 $ATTEMPTS); do RESTARTING_CONTAINERS=$(docker ps --filter "status=restarting" --format "{{.Names}}") From a0c1db71a35919479716c5a9047c8283332ead5d Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Wed, 22 May 2024 21:31:14 +0530 Subject: [PATCH 17/33] fix: debugging 502s in pinging (7) --- .github/workflows/quick-testing.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index 6c53238d..af8924d3 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 - name: Set up opensearch directory - run: mkdir shuffle-database && chown -R 1000:1000 shuffle-database + run: mkdir shuffle-database && chmod -R 755 shuffle-database - name: Build the stack run: docker-compose up -d @@ -19,9 +19,11 @@ jobs: - name: Wait for 30 seconds run: sleep 30 - - name: Check for restarting containers in a loop and fixing perms again once + - name: Check for restarting containers in a loop and fixing perms again run: | - chown -R 1000:1000 shuffle-database + echo "Changing permissions on shuffle-database directory again" + chmod -R 755 shuffle-database + ATTEMPTS=30 # Total time = ATTEMPTS * 5 seconds = 30 seconds for i in $(seq 1 $ATTEMPTS); do RESTARTING_CONTAINERS=$(docker ps --filter "status=restarting" --format "{{.Names}}") From a61984a70c44526bbf46bed1775e47e9e3ac7add Mon Sep 17 00:00:00 2001 From: satti-hari-krishna-reddy Date: Wed, 22 May 2024 20:51:51 +0530 Subject: [PATCH 18/33] making pipelines to show up in the ui --- frontend/src/views/Admin.jsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/views/Admin.jsx b/frontend/src/views/Admin.jsx index aab163de..b074e404 100755 --- a/frontend/src/views/Admin.jsx +++ b/frontend/src/views/Admin.jsx @@ -805,7 +805,7 @@ If you're interested, please let me know a time that works for you, or set up a .then((responseJson) => { setWebHooks(responseJson.webhooks || []); // Handling the case where the result is null or undefined setAllSchedules(responseJson.schedules || []); - // setPipelines(responseJson.pipelines || []); + setPipelines(responseJson.pipelines || []); }) .catch((error) => { // toast(error.toString()); @@ -990,11 +990,13 @@ If you're interested, please let me know a time that works for you, or set up a } const data = { + command: pipeline.command, name: pipeline.name, type: state, environment: pipeline.environment, workflow_id: pipeline.workflow_id, trigger_id: pipeline.trigger_id, + start_node: pipeline.start_node, }; if (state === "start") toast("starting the pipeline"); @@ -1025,6 +1027,7 @@ If you're interested, please let me know a time that works for you, or set up a if (state === "start") toast("Successfully created pipeline"); else toast("Sucessfully stopped the pipeline"); } + setTimeout(handleGetAllTriggers, 1000); }) .catch((error) => { //toast(error.toString()); @@ -4938,7 +4941,7 @@ If you're interested, please let me know a time that works for you, or set up a - - - ); - - const toggleBetweenRequiredOrOptional = (event) => { - setSSORequired(event.target.checked); - }; - - return ( -
- - - - Notification Workflow - - {/* - - */} - - -
- {workflows !== undefined && workflows !== null && workflows.length > 0 ? - { - if ( - option === undefined || - option === null || - option.name === undefined || - option.name === null - ) { - return "No Workflow Selected"; - } - - const newname = ( - option.name.charAt(0).toUpperCase() + option.name.substring(1) - ).replaceAll("_", " "); - return newname; - }} - options={workflows} - fullWidth - style={{ - backgroundColor: theme.palette.inputColor, - height: 50, - borderRadius: theme.palette.borderRadius, - }} - onChange={(event, newValue) => { - console.log("Found value: ", newValue) - - var parsedinput = { target: { value: newValue } } - - // For variables - if (typeof newValue === 'string' && newValue.startsWith("$")) { - parsedinput = { - target: { - value: { - "name": newValue, - "id": newValue, - "actions": [], - "triggers": [], - } - } - } - } - - handleWorkflowSelectionUpdate(parsedinput) - }} - renderOption={(props, data, state) => { - if (data.id === workflow.id) { - data = workflow; - } - - return ( - - {data.image !== undefined && data.image !== null && data.image.length > 0 ? - {data.name} - : null} - - Choose {data.name} - - - } placement="bottom"> - { - var parsedinput = { target: { value: data } } - handleWorkflowSelectionUpdate(parsedinput) - }} - > - {data.name} - - - ) - }} - renderInput={(params) => { - return ( - - ); - }} - /> - : - { - setNotificationWorkflow(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - } -
- {orgSaveButton} -
-
-
-
- - - Org Documentation reference - { - setDocumentationReference(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - {/* {isCloud ? null : */} -
-
- - {SSORequired ? 'Required' : 'Optional'} -
- Make SAML SSO or OpenID Authentication Required or Optional for Your Organization. -
-
-
- - OpenID connect - - - - Client ID - 0 - } - id="outlined-with-placeholder" - margin="normal" - variant="outlined" - placeholder="The OpenID client ID from the identity provider" - value={openidClientId} - onChange={(e) => { - setOpenidClientId(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - - - Client Secret (optional) - 0 - } - id="outlined-with-placeholder" - margin="normal" - variant="outlined" - placeholder="The OpenID client secret - DONT use this if dealing with implicit auth / PKCE" - value={openidClientSecret} - onChange={(e) => { - setOpenidClientSecret(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - - - - - Authorization URL - { - setOpenidAuthorization(e.target.value) - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - - - Token URL - { - setOpenidToken(e.target.value) - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - - - {/* } */} - {/*isCloud ? null : */} - - SAML SSO (v1.1) - - - - SSO Entrypoint (IdP) - 0 - } - id="outlined-with-placeholder" - margin="normal" - variant="outlined" - placeholder="The entrypoint URL from your provider" - value={ssoEntrypoint} - onChange={(e) => { - setSsoEntrypoint(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - - - SSO Certificate (X509) - { - setSsoCertificate(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - - {isCloud ? - - IdP URL for Shuffle: https://shuffler.io/api/v1/login_sso - - : null} - - {isCloud ? null : ( - - - App Download URL - { - setAppDownloadUrl(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - )} - {isCloud ? null : ( - - - App Download Branch - { - setAppDownloadBranch(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - )} - {isCloud ? null : ( - - - Workflow Download URL - { - setWorkflowDownloadUrl(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - )} - {isCloud ? null : ( - - - Workflow Download Branch - { - setWorkflowDownloadBranch(e.target.value); - }} - InputProps={{ - classes: { - notchedOutline: classes.notchedOutline, - }, - style: { - color: "white", - }, - }} - /> - - - )} - -
- {orgSaveButton} -
- {/* - - {expanded ? - - : - - } - - */} -
-
- ) -} - +import React, { useEffect } from "react"; + +import { makeStyles } from "@mui/styles"; +import theme from '../theme.jsx'; +import { toast } from "react-toastify" +import Chip from '@mui/material/Chip'; +import Stack from '@mui/material/Stack'; +import SubflowSuggestions from "../components/SubflowSuggestions.jsx"; + +import { + FormControl, + InputLabel, + Paper, + OutlinedInput, + Checkbox, + Card, + Tooltip, + FormControlLabel, + Typography, + Switch, + Select, + MenuItem, + Divider, + TextField, + Button, + Tabs, + Tab, + Grid, + IconButton, + Autocomplete, + Dialog, + DialogTitle, + DialogActions, + DialogContent, + Box +} from "@mui/material"; + +import { + ExpandLess as ExpandLessIcon, + ExpandMore as ExpandMoreIcon, + Save as SaveIcon, +} from "@mui/icons-material"; + +const useStyles = makeStyles({ + notchedOutline: { + borderColor: "#f85a3e !important", + }, +}) + +const OrgHeaderexpanded = (props) => { + const { + userdata, + selectedOrganization, + setSelectedOrganization, + globalUrl, + isCloud, + adminTab, + } = props; + + const classes = useStyles(); + const defaultBranch = "master"; + + const [orgName, setOrgName] = React.useState(selectedOrganization.name); + const [orgDescription, setOrgDescription] = React.useState( + selectedOrganization.description + ); + + const [appDownloadUrl, setAppDownloadUrl] = React.useState( + selectedOrganization.defaults === undefined + ? "https://github.com/frikky/shuffle-apps" + : selectedOrganization.defaults.app_download_repo === undefined || + selectedOrganization.defaults.app_download_repo.length === 0 + ? "https://github.com/frikky/shuffle-apps" + : selectedOrganization.defaults.app_download_repo + ); + const [appDownloadBranch, setAppDownloadBranch] = React.useState( + selectedOrganization.defaults === undefined + ? defaultBranch + : selectedOrganization.defaults.app_download_branch === undefined || + selectedOrganization.defaults.app_download_branch.length === 0 + ? defaultBranch + : selectedOrganization.defaults.app_download_branch + ); + const [workflowDownloadUrl, setWorkflowDownloadUrl] = React.useState( + selectedOrganization.defaults === undefined + ? "https://github.com/frikky/shuffle-apps" + : selectedOrganization.defaults.workflow_download_repo === undefined || + selectedOrganization.defaults.workflow_download_repo.length === 0 + ? "https://github.com/frikky/shuffle-workflows" + : selectedOrganization.defaults.workflow_download_repo + ); + const [workflowDownloadBranch, setWorkflowDownloadBranch] = React.useState( + selectedOrganization.defaults === undefined + ? defaultBranch + : selectedOrganization.defaults.workflow_download_branch === undefined || + selectedOrganization.defaults.workflow_download_branch.length === 0 + ? defaultBranch + : selectedOrganization.defaults.workflow_download_branch + ); + const [ssoEntrypoint, setSsoEntrypoint] = React.useState( + selectedOrganization.sso_config === undefined + ? "" + : selectedOrganization.sso_config.sso_entrypoint === undefined || + selectedOrganization.sso_config.sso_entrypoint.length === 0 + ? "" + : selectedOrganization.sso_config.sso_entrypoint + ); + const [ssoCertificate, setSsoCertificate] = React.useState( + selectedOrganization.sso_config === undefined + ? "" + : selectedOrganization.sso_config.sso_certificate === undefined || + selectedOrganization.sso_config.sso_certificate.length === 0 + ? "" + : selectedOrganization.sso_config.sso_certificate + ); + const [SSORequired, setSSORequired] = React.useState(selectedOrganization.sso_config === undefined + ? false + : selectedOrganization.sso_config.SSORequired === undefined + ? false + : selectedOrganization.sso_config.SSORequired); + + const [notificationWorkflow, setNotificationWorkflow] = React.useState( + selectedOrganization.defaults === undefined + ? "" + : selectedOrganization.defaults.notification_workflow === undefined || + selectedOrganization.defaults.notification_workflow.length === 0 + ? "" + : selectedOrganization.defaults.notification_workflow + ); + + const [documentationReference, setDocumentationReference] = React.useState( + selectedOrganization.defaults === undefined + ? "" + : selectedOrganization.defaults.documentation_reference === undefined || + selectedOrganization.defaults.documentation_reference.length === 0 + ? "" + : selectedOrganization.defaults.documentation_reference + ); + const [openidClientId, setOpenidClientId] = React.useState( + selectedOrganization.sso_config === undefined + ? "" + : selectedOrganization.sso_config.client_id === undefined || + selectedOrganization.sso_config.client_id.length === 0 + ? "" + : selectedOrganization.sso_config.client_id + ); + const [openidClientSecret, setOpenidClientSecret] = React.useState( + selectedOrganization.sso_config === undefined + ? "" + : selectedOrganization.sso_config.client_secret === undefined || + selectedOrganization.sso_config.client_secret.length === 0 + ? "" + : selectedOrganization.sso_config.client_secret + ); + const [openidAuthorization, setOpenidAuthorization] = React.useState( + selectedOrganization.sso_config === undefined + ? "" + : selectedOrganization.sso_config.openid_authorization === undefined || + selectedOrganization.sso_config.openid_authorization.length === 0 + ? "" + : selectedOrganization.sso_config.openid_authorization + ); + const [openidToken, setOpenidToken] = React.useState( + selectedOrganization.sso_config === undefined + ? "" + : selectedOrganization.sso_config.openid_token === undefined || + selectedOrganization.sso_config.openid_token.length === 0 + ? "" + : selectedOrganization.sso_config.openid_token + ) + + const [workflows, setWorkflows] = React.useState([]) + const [workflow, setWorkflow] = React.useState({}) + + const getAvailableWorkflows = (trigger_index) => { + fetch(globalUrl + "/api/v1/workflows", { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + credentials: "include", + }) + .then((response) => { + if (response.status !== 200) { + console.log("Status not 200 for workflows :O!"); + return; + } + return response.json(); + }) + .then((responseJson) => { + if (responseJson !== undefined) { + setWorkflows(responseJson) + + if (selectedOrganization.defaults !== undefined && selectedOrganization.defaults.notification_workflow !== undefined) { + + const workflow = responseJson.find((workflow) => workflow.id === selectedOrganization.defaults.notification_workflow) + if (workflow !== undefined && workflow !== null) { + setWorkflow(workflow) + } + } + } + }) + .catch((error) => { + console.log("Error getting workflows: " + error); + }) + } + + useEffect(() => { + getAvailableWorkflows() + }, []) + + const handleEditOrg = ( + name, + description, + orgId, + image, + defaults, + sso_config + ) => { + + const data = { + name: name, + description: description, + org_id: orgId, + image: image, + defaults: defaults, + sso_config: sso_config, + }; + + const url = globalUrl + `/api/v1/orgs/${selectedOrganization.id}`; + fetch(url, { + mode: "cors", + method: "POST", + body: JSON.stringify(data), + credentials: "include", + crossDomain: true, + withCredentials: true, + headers: { + "Content-Type": "application/json; charset=utf-8", + }, + }) + .then((response) => + response.json().then((responseJson) => { + if (responseJson["success"] === false) { + toast("Failed updating org: ", responseJson.reason); + } else { + toast("Successfully edited org!"); + } + }) + ) + .catch((error) => { + toast("Err: " + error.toString()); + }); + }; + + + const handleWorkflowSelectionUpdate = (e, isUserinput) => { + if (e.target.value === undefined || e.target.value === null || e.target.value.id === undefined) { + console.log("Returning as there's no id") + return null + } + + setWorkflow(e.target.value) + setNotificationWorkflow(e.target.value.id) + toast("Updated notification workflow. Don't forget to save!") + } + + const orgSaveButton = ( + +
+ +
+
+ ); + + const toggleBetweenRequiredOrOptional = (event) => { + if (ssoEntrypoint === "" && openidAuthorization === "" && openidToken === "") { + if (!SSORequired) { + toast.error("Please fill in fields for either OpenID connect or SSO before continuing. ") + return + } + } else { + toast.info("Toggled SSO. Remember to save.") + } + + setSSORequired(event.target.checked) + }; + + return ( +
+ + + + Notification Workflow + + {/* + + */} + + +
+ {workflows !== undefined && workflows !== null && workflows.length > 0 ? + { + if ( + option === undefined || + option === null || + option.name === undefined || + option.name === null + ) { + return "No Workflow Selected"; + } + + const newname = ( + option.name.charAt(0).toUpperCase() + option.name.substring(1) + ).replaceAll("_", " "); + return newname; + }} + options={workflows} + fullWidth + style={{ + backgroundColor: theme.palette.inputColor, + height: 50, + borderRadius: theme.palette.borderRadius, + }} + onChange={(event, newValue) => { + console.log("Found value: ", newValue) + + var parsedinput = { target: { value: newValue } } + + // For variables + if (typeof newValue === 'string' && newValue.startsWith("$")) { + parsedinput = { + target: { + value: { + "name": newValue, + "id": newValue, + "actions": [], + "triggers": [], + } + } + } + } + + handleWorkflowSelectionUpdate(parsedinput) + }} + renderOption={(props, data, state) => { + if (data.id === workflow.id) { + data = workflow; + } + + return ( + + {data.image !== undefined && data.image !== null && data.image.length > 0 ? + {data.name} + : null} + + Choose {data.name} + + + } placement="bottom"> + { + var parsedinput = { target: { value: data } } + handleWorkflowSelectionUpdate(parsedinput) + }} + > + {data.name} + + + ) + }} + renderInput={(params) => { + return ( + + ); + }} + /> + : + { + setNotificationWorkflow(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + } +
+ {orgSaveButton} +
+
+
+
+ + + Org Documentation reference + { + setDocumentationReference(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + {/* {isCloud ? null : */} + Single Signon - SAML/OpenID +
+ Make SAML SSO or OpenID Authentication required/optional for your organization. Tip: Do not make it required until you have tested the URL directly. +
+ { + toggleBetweenRequiredOrOptional(e) + }} + name="onOffSwitch" + color="primary" + title="Make SAML SSO or OpenID Authentication Required or Optional for Your Organization" + /> + {SSORequired ? 'Required' : 'Optional'} +
+
+
+
+ + OpenID connect + + + + Client ID + { + setOpenidClientId(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + + + Client Secret (optional) + { + setOpenidClientSecret(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + + + + + Authorization URL + { + setOpenidAuthorization(e.target.value) + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + + + Token URL + { + setOpenidToken(e.target.value) + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + + + {/* } */} + {/*isCloud ? null : */} + + SAML SSO (v1.1) + + + + SSO Entrypoint (IdP) + { + setSsoEntrypoint(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + + + SSO Certificate (X509) + { + setSsoCertificate(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + + {isCloud ? + + IdP URL for Shuffle: https://shuffler.io/api/v1/login_sso + + : null} + + {isCloud ? null : ( + + + App Download URL + { + setAppDownloadUrl(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + )} + {isCloud ? null : ( + + + App Download Branch + { + setAppDownloadBranch(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + )} + {isCloud ? null : ( + + + Workflow Download URL + { + setWorkflowDownloadUrl(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + )} + {isCloud ? null : ( + + + Workflow Download Branch + { + setWorkflowDownloadBranch(e.target.value); + }} + InputProps={{ + classes: { + notchedOutline: classes.notchedOutline, + }, + style: { + color: "white", + }, + }} + /> + + + )} + +
+ {orgSaveButton} +
+ {/* + + {expanded ? + + : + + } + + */} +
+
+ ) +} + export default OrgHeaderexpanded; From 031703ceb2450419005d0e2618572b734f8d701b Mon Sep 17 00:00:00 2001 From: Frikky Date: Mon, 27 May 2024 01:23:02 +0200 Subject: [PATCH 30/33] Update README.md --- shuffle-apps/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shuffle-apps/README.md b/shuffle-apps/README.md index f30690cd..59ad076a 100755 --- a/shuffle-apps/README.md +++ b/shuffle-apps/README.md @@ -1,5 +1,5 @@ # Shuffle Apps * This folder is by default meant to be empty * This folder is meant for quick development of apps (single button hot-loading) -* Some shuffle apps can be found at https://github.com/frikky/shuffle-apps +* Some shuffle apps can be found at https://github.com/shuffle/python-apps From 1c5eddac7f51396f666d3b723b8f129e22883ce9 Mon Sep 17 00:00:00 2001 From: yashsinghcodes Date: Mon, 27 May 2024 07:04:23 +0000 Subject: [PATCH 31/33] parse video link from markdown --- frontend/src/views/Docs.jsx | 38 +++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx index 339bd608..6c412080 100755 --- a/frontend/src/views/Docs.jsx +++ b/frontend/src/views/Docs.jsx @@ -102,6 +102,35 @@ export const CopyToClipboard = (props) => { ) } +export const Paragrah = (props) => { + const element = React.createElement( + `p`, + {}, + props.children, + ) + + if (props.children[0] != undefined) { + if(typeof props.children[0] === "string") { + if (props.children[0].includes('.mp4')) { + return ( +
+ +
+ ) + } + } + } + + + return ( +
+ {element} +
+ ) +} + export const OuterLink = (props) => { if (props.href.includes("http") || props.href.includes("mailto")) { return ( @@ -581,8 +610,8 @@ const Docs = (defaultprops) => { position: "sticky", top: 50, paddingTop: "0.25em", - minHeight: "93vh", - maxHeight: "93vh", + minHeight: "95vh", + maxHeight: "95vh", overflowX: "hidden", overflowY: "auto", zIndex: 1000, @@ -940,7 +969,8 @@ const Docs = (defaultprops) => { h4: Heading, h5: Heading, h6: Heading, - a: OuterLink, + a: OuterLink, + p: Paragrah, } @@ -1188,7 +1218,7 @@ const Docs = (defaultprops) => { // Padding and zIndex etc set because of footer in cloud. const loadedCheck = ( -
+
{postDataBrowser} {postDataMobile}
From 27fe834075b68f43d7cd32ebcfdfa32a0d2ad5b0 Mon Sep 17 00:00:00 2001 From: yashsinghcodes Date: Thu, 30 May 2024 11:51:30 +0000 Subject: [PATCH 32/33] now able to click back in activeworkflow page --- frontend/src/views/AngularWorkflow.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index fece7151..a27d1876 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -14697,7 +14697,6 @@ const AngularWorkflow = (defaultprops) => { right: 0, left: isMobile ? 20 : leftBarSize + 20, top: isMobile ? 30 : appBarSize + 20, - pointerEvents: "none", } @@ -14718,7 +14717,6 @@ const AngularWorkflow = (defaultprops) => {
{

{workflow.name}

From 72b062def163f67d595df6f482ada91554f1137a Mon Sep 17 00:00:00 2001 From: Frikky Date: Thu, 30 May 2024 14:25:21 +0200 Subject: [PATCH 33/33] Revert "parse video link from markdown and fix for the wokflow page" --- frontend/src/views/AngularWorkflow.jsx | 3 ++ frontend/src/views/Docs.jsx | 38 +++----------------------- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/frontend/src/views/AngularWorkflow.jsx b/frontend/src/views/AngularWorkflow.jsx index a27d1876..fece7151 100755 --- a/frontend/src/views/AngularWorkflow.jsx +++ b/frontend/src/views/AngularWorkflow.jsx @@ -14697,6 +14697,7 @@ const AngularWorkflow = (defaultprops) => { right: 0, left: isMobile ? 20 : leftBarSize + 20, top: isMobile ? 30 : appBarSize + 20, + pointerEvents: "none", } @@ -14717,6 +14718,7 @@ const AngularWorkflow = (defaultprops) => {
{

{workflow.name}

diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx index 6c412080..339bd608 100755 --- a/frontend/src/views/Docs.jsx +++ b/frontend/src/views/Docs.jsx @@ -102,35 +102,6 @@ export const CopyToClipboard = (props) => { ) } -export const Paragrah = (props) => { - const element = React.createElement( - `p`, - {}, - props.children, - ) - - if (props.children[0] != undefined) { - if(typeof props.children[0] === "string") { - if (props.children[0].includes('.mp4')) { - return ( -
- -
- ) - } - } - } - - - return ( -
- {element} -
- ) -} - export const OuterLink = (props) => { if (props.href.includes("http") || props.href.includes("mailto")) { return ( @@ -610,8 +581,8 @@ const Docs = (defaultprops) => { position: "sticky", top: 50, paddingTop: "0.25em", - minHeight: "95vh", - maxHeight: "95vh", + minHeight: "93vh", + maxHeight: "93vh", overflowX: "hidden", overflowY: "auto", zIndex: 1000, @@ -969,8 +940,7 @@ const Docs = (defaultprops) => { h4: Heading, h5: Heading, h6: Heading, - a: OuterLink, - p: Paragrah, + a: OuterLink, } @@ -1218,7 +1188,7 @@ const Docs = (defaultprops) => { // Padding and zIndex etc set because of footer in cloud. const loadedCheck = ( -
+
{postDataBrowser} {postDataMobile}