Files
UnrealEngine/Engine/Extras/RoboMerge/v3/public/js/createshelf.js
2025-05-18 13:04:45 +08:00

346 lines
15 KiB
JavaScript

// Copyright Epic Games, Inc. All Rights Reserved.
function goHome() {
location.href = '/' + location.hash
}
function shelfVerify() {
let queryParams = processQueryParameters(['bot', 'branch', 'cl', 'target'], ['targetStream'])
if (!queryParams) return;
let requestedBotName = queryParams["bot"]
let requestedBranchName = queryParams["branch"]
let targetBranchName = queryParams["target"]
let optTargetStreamName = queryParams["targetStream"]
let requestedBranchCl = parseInt(queryParams["cl"], 10)
if (isNaN(requestedBranchCl)) {
shelfFailure(`CL ${queryParams["cl"]} not a number.`)
return
}
// Retrieve branch information to verify requested information
getBranch(requestedBotName, requestedBranchName, function(data) {
if (!data) {
shelfFailure(`Couldn't find branch for ${requestedBranchName}`)
return
}
let requestedBranch = verifyShelfRequest(requestedBotName, requestedBranchName, requestedBranchCl, targetBranchName, data.branch)
// If the branch failed verification, please quit immediately
if (!requestedBranch) {
return
}
let requestedEdgeData = requestedBranch.edges[targetBranchName.toUpperCase()]
// Print preview
$('#preview').append(renderSingleBranchTable(requestedBranch, requestedEdgeData))
let formDiv = $('#workspaceFormDiv')
let workspaceForm = $('<form id="workspaceForm" style="display: inline-block; text-align: left">').prependTo(formDiv)
// Check if conflict is already acknowledged or not
const conflictAcknowledged = requestedEdgeData.blockage.acknowledger !== undefined
// Determine if we have any relevant workspaces
let foundWorkspaces = false
getUserWorkspaces(requestedEdgeData.serverID, function(wsdata) {
// Ensure we have data
if (!wsdata || !wsdata.data) {
shelfFailure('Workspaces could not be found for user.')
return
}
// Ensure we have a proper return code, or display the error message
if (wsdata.statusCode !== 200) {
shelfFailure("Could not retrieve workspaces: " + wsdata.message)
return
}
let userWorkspaces = wsdata.data
if (!userWorkspaces || userWorkspaces.length == 0) {
shelfFailure("Found no user workspaces.")
return
}
// Collect and sort the user workspaces
userWorkspaces.sort(function(a,b) {
return a.client.localeCompare(b.client);
});
// Create form for relevant workspaces
const addClientToForm = function(client, exactMatch) {
const clientOptionLabel = $('<label>').text(client)
// Add CSS class to differentiate
if (exactMatch) {
clientOptionLabel.addClass('workspaceExactMatch')
} else {
clientOptionLabel.addClass('workspaceInexactMatch')
}
workspaceForm.append(
clientOptionLabel.prepend(
$(`<input type="radio" class="workspaceRadio" name="workspace" value="${client}">`)
)
).append($('<br>'))
}
// If the target branch is a stream, filter the available workspaces
if (optTargetStreamName) {
// We have some elements in the HTML that hold the streamname as text
$('.streamName').each(function() {
$(this).text(optTargetStreamName)
})
// Look through user's list of workspaces for any that are mapped to the target stream (or start with the same depot path)
const depotPathMatches = optTargetStreamName.match(/(\/\/[\w-_]+\/)/)
var depotPath
if (depotPathMatches) {
depotPath = depotPathMatches[0]
}
console.log(`Selecting user workspaces for stream ${optTargetStreamName} (or in depot "${depotPath}")`)
var exactMatches = []
var inexactMatches = []
$.each(userWorkspaces, function(_, workspace) {
if (!workspace.Stream) {
return
}
// Check for exact matches
if (workspace.Stream === optTargetStreamName) {
// Mark our tracker that we've encountered relevant workspaces
foundWorkspaces = true
exactMatches.push(workspace.client)
}
// Check for workspaces with similar depots
else if (workspace.Stream.startsWith(depotPath)) {
// Mark our tracker that we've encountered relevant workspaces
foundWorkspaces = true
inexactMatches.push(workspace.client)
}
})
// Append workspace options to our form
for (var i in exactMatches) {
addClientToForm(exactMatches[i], true)
}
for (var i in inexactMatches) {
addClientToForm(inexactMatches[i], false)
}
// If we found no workspaces, display the tutorial on how to create a stream workspace
if (!foundWorkspaces) {
$('#createStreamWorkspaceTutorial').removeClass('initiallyHidden')
}
}
// On non-stream requests, display all non-stream workspaces
else {
// This must be a non-Stream integration
foundWorkspaces = true
console.log(`Selecting non-stream user workspaces`)
$.each(userWorkspaces, function(_, workspace) {
if (!workspace.Stream || workspace.Stream === "") {
// Append workspace option to our form
addClientToForm(workspace.client)
}
})
}
// Check if we found any relevant data
if (foundWorkspaces) {
$('#preview').append(
$('<h3 class="centered-text">').text(`Creating shelf in ${targetBranchName}. Please choose one of your workspaces to create the shelf in:`)
)
if (optTargetStreamName && inexactMatches.length > 0) {
$('#preview').append(
$('<p class="centered-text">').html(`Workspaces that are mapped to ${optTargetStreamName} are in <strong>bold</strong>.<br />Alternative workspaces under the same depot (${depotPath}) are at the bottom of the list.`)
)
}
// Show form and submit/cancel buttons
$('#preview').append(formDiv)
formDiv.removeClass('initiallyHidden')
let buttonDiv = $('#submitDiv')
// Return to Robomerge homepage
let cancelButton = $('<button type="button" class="btn btn-lg btn-info">').text(`Cancel`).appendTo(buttonDiv)
cancelButton.click(function() {
goHome()
})
// Show the acknowledge checkbox option
let acknowledgeCheckbox = $($("input[name='acknowledgeCheckbox']")[0])
acknowledgeCheckbox.removeClass('initiallyHidden')
// If the conflict is not acknowledged, default to checking this box to acknowledge with creating the shelf
acknowledgeCheckbox.prop('checked', !conflictAcknowledged)
let createShelfButton = $('<button type="button" id="createShelfButton" class="btn btn-lg btn-primary" disabled>').text('Create Shelf').appendTo(buttonDiv)
workspaceForm.change(function() {
// On form change, enable the create shelf button
createShelfButton.attr('disabled', false);
// Display warning message if the user selects an inexact match for their workspace
const selectedWorkspace = $("input[name='workspace']:checked")[0].value
const selectWorkspaceLabel = $($(`label:contains('${selectedWorkspace}')`)[0])
if (selectWorkspaceLabel.hasClass('workspaceInexactMatch')) {
$('#inexactWorkspaceWarning').removeClass('initiallyHidden')
} else {
// Exact match
$('#inexactWorkspaceWarning').addClass('initiallyHidden')
}
})
createShelfButton.click(function() {
// Grab values BEFORE locking form
// This should only return one value
const selectedWorkspace = $("input[name='workspace']:checked")[0].value
const acknowledgeWithShelf = acknowledgeCheckbox.prop('checked')
// Disable the form elements to lock in the choice
createShelfButton.attr('disabled', true)
cancelButton.attr('disabled', true)
acknowledgeCheckbox.attr('disabled', true)
$.each($('.workspaceRadio'), function(index, radioButton) {
$(radioButton).attr('disabled', true)
})
createShelfButton.text(`Creating shelf in ${selectedWorkspace}...`)
// Ensure we still have data since we last verified and displayed the data
// (The issue might have been resolved during that time.)
getBranch(requestedBotName, requestedBranchName, function(data) {
let requestedBranch = verifyShelfRequest(requestedBotName, requestedBranchName, requestedBranchCl, targetBranchName, data.branch)
// If the branch failed verification, please quit immediately
if (!requestedBranch) {
// No longer valid.
shelfFailure(`Shelving conflict for ${requestedBranchCl} is no longer valid.`)
return
}
doShelf(data, requestedBranchCl, targetBranchName, selectedWorkspace, acknowledgeWithShelf)
})
})
} else {
$('#returnbutton').removeClass('initiallyHidden')
}
})
})
}
// This function takes in requested bot/branch/cl combo (usually from query parameters processed earlier) and
// ensures this is a valid request
function verifyShelfRequest(requestedBotName, requestedBranchName, requestedBranchCl, targetBranchName, branchData) {
// Verify we got a branch
if (!branchData.def) {
let errText = `Could not find matching branch for ${requestedBotName}:${requestedBranchName}.`
if (branchData.message) {
errText += `\n${branchData.message}`
}
shelfFailure(errText)
return
}
// Verify we can get the edge for the requested branch
if (!branchData.edges || !branchData.edges[targetBranchName.toUpperCase()]) {
shelfFailure(`Could not find a edge in ${requestedBotName}:${requestedBranchName} for requested edge "${targetBranchName}"`)
return
}
let requestedBranch = branchData
let requestedEdgeData = branchData.edges[targetBranchName.toUpperCase()]
// Find conflict in question matching the requested CL
// First, verify the request branch is paused
if (!requestedEdgeData.blockage) {
shelfFailure(`${requestedEdgeData.display_name} not currently blocked, no need to create a shelf.`)
$('#result').append(renderSingleBranchTable(requestedBranch, requestedEdgeData))
return
}
// Ensure the current pause is applicable to the CL
if (requestedEdgeData.blockage.change != requestedBranchCl) {
displayWarningMessage(`${requestedEdgeData.display_name} currently blocked, but not at requested CL ${requestedBranchCl}. Performing no action.`, false)
$('#result').append(renderSingleBranchTable(requestedBranch, requestedEdgeData))
$('#returnbutton').removeClass("initiallyHidden")
return
}
return requestedBranch
}
function doShelf(fullData, branchCl, target, workspace, acknowledgeWithShelf) {
// Data all verified, time to perform the shelf operation.
let queryData = {
cl: branchCl,
target,
workspace
}
let branchData = fullData.branch
let botname = branchData.bot
let branchname = branchData.def.name
// Perform create shelf operation
let createShelf = nodeAPIOp(botname, branchname, '/create_shelf?' + toQuery(queryData))
createShelf.done(function(_success) {
$('#preview').hide()
let successMsg = `${fullData.user.displayName} successfully queued CL ${branchCl} for reconsideration. The shelf will appear in workspace "${workspace}"`
// If we're set to acknowledge after the shelf is created, do so now
if (acknowledgeWithShelf) {
performAcknowledge(botname, branchname, target, branchCl).done(function(_success) {
shelfSuccess(`${successMsg}. Additionally, acknowledged blockage in ${botname}:${branchname}.`)
}).fail(function(_jqXHR, _textStatus, _errMsg) {
shelfWarning(`${successMsg}, but could not acknowledge blockage in ${botname}:${branchname}. Please contact Robomerge help if you need assistance`)
})
}
// Otherwise display a success and be done with it
else {
shelfSuccess(`${successMsg}.`)
}
}).fail(function(jqXHR, _textStatus, errMsg) {
$('#preview').hide()
const errText = `${jqXHR && jqXHR.status ? jqXHR.status + ": " : ""}${jqXHR && jqXHR.responseText ? jqXHR.responseText : errMsg}`
let shelfFailureAlert = `An error was encountered reconsidering CL ${branchCl}. No shelf was created. Error message: "${errText}"`
if (acknowledgeWithShelf) {
shelfFailureAlert += " Acknowledge operation skipped due to error."
}
shelfFailure(shelfFailureAlert)
})
}
function performAcknowledge(requestedBotName, nodeBranch, targetBranch, requestedBranchCl) {
const ackQueryData = {
cl: requestedBranchCl
}
// This page is only relevant to edge acknowledgements
return edgeAPIOp(requestedBotName, nodeBranch, targetBranch, '/acknowledge?' + toQuery(ackQueryData))
}
function shelfFailure(message) {
$(`<div class="alert alert-danger show" role="alert">`).html(`<strong>ERROR:</strong> ${message}`).appendTo($('#result'))
$('#returnbutton').removeClass("initiallyHidden")
}
function shelfWarning(message) {
$(`<div class="alert alert-warning show" role="alert">`).html(`<strong>WARNING:</strong> ${message}`).appendTo($('#result'))
$('#returnbutton').removeClass("initiallyHidden")
}
function shelfSuccess(message) {
$(`<div class="alert alert-success show" role="alert">`).html(message).appendTo($('#result'))
$('#nextSteps').removeClass("initiallyHidden")
$('#returnbutton').removeClass("initiallyHidden")
}