Skip to content

Commit

Permalink
feat: Modal for adding a pipeline to a collection (#1084)
Browse files Browse the repository at this point in the history
  • Loading branch information
minghay authored Jul 11, 2024
1 parent 4382d82 commit 8d04c6f
Show file tree
Hide file tree
Showing 8 changed files with 451 additions and 0 deletions.
128 changes: 128 additions & 0 deletions app/components/collection/modal/add-to-collection/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import Component from '@glimmer/component';
import { service } from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { createCollectionBody, getCollectionsWithoutPipeline } from './util';

export default class CollectionModalAddToCollectionModalComponent extends Component {
@service shuttle;

@tracked errorMessage;

@tracked newCollectionName = '';

@tracked newCollectionDescription = '';

@tracked selectedCollections = [];

@tracked wasActionSuccessful = false;

@tracked collectionsWithoutPipeline = [];

failedToAddToCollections = [];

constructor() {
super(...arguments);

const collections = this.args.collections || [];

this.collectionsWithoutPipeline = getCollectionsWithoutPipeline(
collections,
this.args.pipeline.id
);
this.errorMessage = this.args.errorMessage;
}

get isSubmitButtonDisabled() {
if (this.isAwaitingResponse) {
return true;
}

return !(
this.newCollectionName.length > 0 || this.selectedCollections.length > 0
);
}

get hasCollections() {
return this.collectionsWithoutPipeline.length > 0;
}

async createCollection() {
if (this.newCollectionName.length > 0) {
await this.shuttle
.fetchFromApi(
'post',
'/collections',
createCollectionBody(
this.newCollectionName,
this.newCollectionDescription,
this.args.pipeline.id
)
)
.then(() => {
this.newCollectionName = '';
this.newCollectionDescription = '';
})
.catch(() => {
this.errorMessage = `Failed to create new collection: ${this.newCollectionName}`;
});
}
}

async addToCollections() {
const promises = [];

if (this.selectedCollections.length > 0) {
this.failedToAddToCollections = [];

this.selectedCollections.forEach(collection => {
promises.push(
this.shuttle
.fetchFromApi('put', `/collections/${collection.id}`, {
pipelineIds: collection.pipelineIds.concat(this.args.pipeline.id)
})
.catch(() => {
this.failedToAddToCollections.push(collection.name);
})
);
});
}

return Promise.all(promises);
}

@action
async submitCollections() {
this.isAwaitingResponse = true;
this.errorMessage = null;

return new Promise(resolve => {
Promise.allSettled([
this.createCollection(),
this.addToCollections()
]).then(() => {
this.isAwaitingResponse = false;

if (this.failedToAddToCollections.length > 0) {
if (this.errorMessage) {
this.errorMessage += `. Also failed to add pipeline to collections: ${this.failedToAddToCollections.join(
', '
)}`;
} else {
this.errorMessage = `Failed to add pipeline to collections: ${this.failedToAddToCollections.join(
', '
)}`;
}
} else {
this.selectedCollections.forEach(collection => {
document.getElementById(
`collection-${collection.id}`
).disabled = true;
});
this.selectedCollections = [];
}
resolve();
});
});
}
}
59 changes: 59 additions & 0 deletions app/components/collection/modal/add-to-collection/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@use 'screwdriver-colors' as colors;
@use 'screwdriver-button' as button;

@mixin styles {
#add-to-collection-modal {
.modal-dialog {
max-width: 50%;

@include button.styles;

.modal-body {
.modal-title {
font-size: 1.75rem;
padding-bottom: 0.75rem;
}

.create-new-collection {
label {
display: flex;
justify-content: space-between;

> div {
margin: auto;
padding-right: 0.25rem;
}

input {
flex: 1;
border-radius: 4px;
border: 1px solid colors.$sd-text-med;
padding-left: 0.5rem;
margin-left: 0.25rem;
}
}
}

.select-collections {
max-height: 10rem;
overflow: scroll;

.btn-group {
display: flex;
flex-direction: column;

> .btn {
border-radius: 3px;
margin: 0.25rem;

&.active {
background-color: rgba(colors.$sd-running, 0.75);
color: colors.$sd-white;
}
}
}
}
}
}
}
}
72 changes: 72 additions & 0 deletions app/components/collection/modal/add-to-collection/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<BsModal
id="add-to-collection-modal"
@onHide={{fn @closeModal}}
as |modal|
>
<modal.body>
{{#if this.errorMessage}}
<InfoMessage
@message={{this.errorMessage}}
@type="warning"
@icon="exclamation-triangle"
/>
{{/if}}
<div class="modal-title">Add to collection(s)</div>
<div class="create-new-collection">
<label>
<div>Collection name:</div>
<Input
id="new-collection-name-input"
@type="text"
@value={{this.newCollectionName}}
placeholder="Please enter a name for your new collection"
/>
</label>
<label>
<div>Collection description:</div>
<Input
@type="text"
@value={{this.newCollectionDescription}}
placeholder="Optional: enter a name description for your new collection"
/>
</label>
</div>

{{#if this.hasCollections}}
<hr />

<div class="select-collections">
<BsButtonGroup
@value={{this.selectedCollections}}
@type="checkbox"
@onChange={{fn (mut this.selectedCollections)}}
as |bg|
>
{{#each this.collectionsWithoutPipeline as |collection|}}
<bg.button
id="collection-{{collection.id}}"
@type="primary"
@outline={{true}}
@value={{collection}}
>
{{collection.name}}
</bg.button>
{{/each}}
</BsButtonGroup>
</div>
{{/if}}

</modal.body>
<modal.footer>
<BsButton
id="submit-collections"
class="confirm"
disabled={{this.isSubmitButtonDisabled}}
@defaultText="Add to collection(s)"
@pendingText="Adding to collection(s)..."
@fulfilledText="Added to collection(s)"
@type="primary"
@onClick={{this.submitCollections}}
/>
</modal.footer>
</BsModal>
26 changes: 26 additions & 0 deletions app/components/collection/modal/add-to-collection/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const getCollectionsWithoutPipeline = (collections, pipelineId) => {
const collectionsWithoutPipeline = [];

collections.forEach(collection => {
if (!collection.pipelineIds.includes(pipelineId)) {
collectionsWithoutPipeline.push(collection);
}
});

collectionsWithoutPipeline.sort((a, b) => a.name.localeCompare(b.name));

return collectionsWithoutPipeline;
};

export const createCollectionBody = (
collectionName,
collectionDescription,
pipelineId
) => {
return {
name: collectionName,
description: collectionDescription,
pipelineIds: [pipelineId],
type: 'normal'
};
};
5 changes: 5 additions & 0 deletions app/components/collection/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@use 'modal/add-to-collection/styles' as modal;

@mixin styles {
@include modal.styles;
}
2 changes: 2 additions & 0 deletions app/components/styles.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
@use 'collection/styles' as collection;
@use 'pipeline/styles' as pipeline;

@mixin styles {
@include collection.styles;
@include pipeline.styles;
}
Loading

0 comments on commit 8d04c6f

Please sign in to comment.