Skip to content

Commit

Permalink
feat: Support deleting all pacts for a specific tag in the UI (#480)
Browse files Browse the repository at this point in the history
  • Loading branch information
bangn authored Sep 5, 2021
1 parent 9692b46 commit 10dda8a
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 43 deletions.
12 changes: 6 additions & 6 deletions lib/pact_broker/domain/index_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ module PactBroker
module Domain
class IndexItem
attr_reader :consumer,
:provider,
:latest_pact,
:latest_verification,
:webhooks,
:triggered_webhooks,
:latest_verification_latest_tags
:provider,
:latest_pact,
:latest_verification,
:webhooks,
:triggered_webhooks,
:latest_verification_latest_tags,

# rubocop:disable Metrics/ParameterLists
def self.create(consumer, provider, latest_pact, latest, latest_verification, webhooks = [], triggered_webhooks = [], tags = [], latest_verification_latest_tags = [], latest_for_branch = nil)
Expand Down
9 changes: 9 additions & 0 deletions lib/pact_broker/ui/view_models/index_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ def base_url
@options[:base_url]
end

def tagged_pacts
@relationship.tag_names.map do |tag|
{
tag: tag,
deletionUrl: PactBroker::Api::PactBrokerUrls.tagged_pact_versions_url(consumer_name, provider_name, tag, base_url)
}.to_json
end
end

private

attr_reader :relationship
Expand Down
9 changes: 6 additions & 3 deletions lib/pact_broker/ui/views/index/show-with-tags.haml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@
%tbody

- index_items.each do | index_item |
%tr{'data-pact-versions-url': index_item.pact_versions_url, 'data-consumer-name': index_item.consumer_name, 'data-provider-name': index_item.provider_name, 'data-integration-url': index_item.integration_url}
%tr{'data-pact-versions-url': index_item.pact_versions_url,
'data-consumer-name': index_item.consumer_name,
'data-provider-name': index_item.provider_name,
'data-integration-url': index_item.integration_url,
'data-tagged-pacts': index_item.tagged_pacts}
%td.consumer
%a{:href => index_item.consumer_group_url }
= index_item.consumer_name
Expand Down Expand Up @@ -108,8 +112,7 @@
- if index_item.warning?
%span.warning-icon{ 'aria-hidden': true }
%td
- if index_item.show_settings?
%span.integration-settings.kebab-horizontal{ 'aria-hidden': true }
%span.integration-settings.kebab-horizontal{ 'aria-hidden': true }

%div.pagination.text-center

Expand Down
163 changes: 129 additions & 34 deletions public/javascripts/index.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
$(document).ready(function() {
$(".integration-settings")
.materialMenu("init", {
$(".integration-settings").click(function() {
const clickedElementData = $(this).closest("tr").data();
$(this).materialMenu("init", {
position: "overlay",
animationSpeed: 1,
items: [
{
type: "normal",
text: "Delete pacts ...",
click: handleDeletePactsSelected
},
{
type: "normal",
text: "Delete integration...",
click: handleDeleteIntegrationsSelected
}
]
})
.click(function() {
$(this).materialMenu("open");
items: buildMaterialMenuItems(clickedElementData)
});
$(this).materialMenu("open");
});
});

function createPactDeletionConfirmationText(rowData) {
Expand All @@ -35,6 +24,16 @@ function createIntegrationDeletionConfirmationText(rowData) {
}, and all associated data (pacts, verifications, application versions, tags and webhooks) that are not associated with other integrations. Do you wish to continue?`;
}

function createPactTagDeletionConfirmationText({
providerName,
consumerName,
pactTagName
}) {
return `This will delete the pacts for provider ${providerName} and all versions of ${
consumerName
} with tag ${pactTagName}. Do you wish to continue?`;
}

function handleDeletePactsSelected(clickedElement) {
const tr = $(clickedElement).closest("tr");
const confirmationText = createPactDeletionConfirmationText(tr.data());
Expand All @@ -51,12 +50,47 @@ function handleDeleteIntegrationsSelected(clickedElement) {
handleDeleteResourcesSelected(tr, tr.data().integrationUrl, confirmationText);
}

function findRowsToBeDeleted(table, consumerName, providerName) {
return table
.children("tbody")
.find(
`[data-consumer-name="${consumerName}"][data-provider-name="${providerName}"]`
function handleDeleteTagSelected({
providerName,
consumerName,
pactTagName,
deletionUrl
}) {
return function(clickedElement) {
const tr = $(clickedElement).closest("tr");
const confirmationText = createPactTagDeletionConfirmationText({
providerName,
consumerName,
pactTagName
});
handleDeleteResourcesSelected(
tr,
deletionUrl,
confirmationText,
pactTagName
);
};
}

function findRowsToBeDeleted(table, consumerName, providerName, tagName) {
if (!tagName) {
return table
.children("tbody")
.find(
`[data-consumer-name="${consumerName}"][data-provider-name="${providerName}"]`
);
}

return table
.children("tbody")
.find("tr")
.find("td")
.filter(function() {
return $(this)
.text()
.includes(`tag: ${tagName}`);
})
.closest("tr");
}

function highlightRowsToBeDeleted(rows) {
Expand Down Expand Up @@ -87,28 +121,38 @@ function confirmDeleteResources(
});
}

function handleDeleteResourcesSelected(row, deletionUrl, confirmationText) {
function handleDeleteResourcesSelected(
row,
deletionUrl,
confirmationText,
tagName
) {
const rowData = row.data();
const rows = findRowsToBeDeleted(
row.closest("table"),
rowData.consumerName,
rowData.providerName
rowData.providerName,
tagName
);
const isRefreshingThePage = !!tagName;
const cancelled = function() {
unHighlightRows(rows);
};
const confirmed = function() {
deleteResources(
deletionUrl,
function() {
handleDeletionSuccess(rows);
handleDeletionSuccess(rows, isRefreshingThePage);
},
function(response) {
handleDeletionFailure(rows, response);
}
);
};
highlightRowsToBeDeleted(rows);

if (!isRefreshingThePage) {
highlightRowsToBeDeleted(rows);
}
confirmDeleteResources(confirmationText, confirmed, cancelled);
}

Expand All @@ -125,19 +169,34 @@ function hideDeletedRows(rows) {
});
}

function handleDeletionSuccess(rows) {
function refreshPage() {
const url = new URL(window.location);
url.searchParams.delete("search");
window.location = url.toString();
}

function handleDeletionSuccess(rows, isRefreshingThePage) {
if (isRefreshingThePage) {
return refreshPage();
}

hideDeletedRows(rows);
}

function createErrorMessage(responseBody) {
if (responseBody && responseBody.error && responseBody.error.message && responseBody.error.reference) {
return `<p>Could not delete resources due to error: ${
responseBody.error.message
}</p><p>Error reference:
if (
responseBody &&
responseBody.error &&
responseBody.error.message &&
responseBody.error.reference
) {
return `<p>Could not delete resources due to error: ${responseBody.error.message}</p><p>Error reference:
${responseBody.error.reference}
</p>`;
} else if (responseBody) {
return `Could not delete resources due to error: ${JSON.stringify(responseBody)}`;
return `Could not delete resources due to error: ${JSON.stringify(
responseBody
)}`;
}

return "Could not delete resources.";
Expand All @@ -159,11 +218,47 @@ function deleteResources(url, successCallback, errorCallback) {
accepts: {
text: "application/hal+json"
},
success: function(data, textStatus, jQxhr) {
success: function() {
successCallback();
},
error: function(jqXhr, textStatus, errorThrown) {
error: function(jqXhr) {
errorCallback(jqXhr.responseJSON);
}
});
}

function buildMaterialMenuItems(clickedElementData) {
const baseOptions = [
{
type: "normal",
text: "Delete pacts ...",
click: handleDeletePactsSelected
},
{
type: "normal",
text: "Delete integration...",
click: handleDeleteIntegrationsSelected
}
];

const taggedPacts = clickedElementData.taggedPacts || [];
const providerName = clickedElementData.providerName;
const consumerName = clickedElementData.consumerName;
const taggedPactsOptions = taggedPacts.map(taggedPact => {
const taggedPactObject = JSON.parse(taggedPact);
const pactTagName = taggedPactObject.tag;
const taggedPactUrl = taggedPactObject.deletionUrl;
return {
type: "normal",
text: `Delete pacts for ${pactTagName}...`,
click: handleDeleteTagSelected({
providerName,
consumerName,
pactTagName,
deletionUrl: taggedPactUrl
})
};
});

return [...baseOptions, ...taggedPactsOptions];
}
10 changes: 10 additions & 0 deletions spec/lib/pact_broker/ui/view_models/index_item_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ module ViewDomain
its(:provider_version_latest_tag_names) { is_expected.to eq ["dev", "prod"] }
end

describe "tagged_pacts" do
let(:tags) { ["master", "prod"] }
its(:tagged_pacts) do
is_expected.to eq([
{ tag: "master", deletionUrl: "/pacts/provider/Provider%20Name/consumer/Consumer%20Name/tag/master" }.to_json,
{ tag: "prod", deletionUrl: "/pacts/provider/Provider%20Name/consumer/Consumer%20Name/tag/prod" }.to_json
])
end
end

describe "<=>" do

let(:relationship_model_4) { double("PactBroker::Domain::IndexItem", consumer_name: "A", provider_name: "X") }
Expand Down

0 comments on commit 10dda8a

Please sign in to comment.