Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: New pipeline parameters component #1068

Merged
merged 4 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions app/components/pipeline/parameters/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import {
extractJobParameters,
extractEventParameters,
getNormalizedParameterGroups
} from 'screwdriver-ui/utils/pipeline/parameters';

export default class PipelineParametersComponent extends Component {
@tracked parameters;

@tracked selectedParameters;

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

const { pipelineParameters, jobParameters } = extractEventParameters(
this.args.event
);

this.parameters = getNormalizedParameterGroups(
pipelineParameters,
this.args.pipeline.parameters,
jobParameters,
extractJobParameters(this.args.jobs),
this.args.job ? this.args.job.name : null
);

this.selectedParameters = {
pipeline: { ...pipelineParameters },
job: { ...jobParameters }
};
}

get title() {
return `${this.args.action} pipeline with parameters`.toUpperCase();
}

@action
toggleParameterGroup(groupName) {
const updatedParameters = [];

this.parameters.forEach(group => {
if (group.paramGroupTitle === groupName) {
updatedParameters.push({ ...group, isOpen: !group.isOpen });
} else {
updatedParameters.push(group);
}
});

this.parameters = updatedParameters;
}

@action
openSelect(powerSelectObject) {
setTimeout(() => {
const container = document.getElementsByClassName('parameters-container');
const scrollFrame = container[0];
const optionsBox = document.getElementById(
`ember-power-select-options-${powerSelectObject.uniqueId}`
);

if (optionsBox === null) {
return;
}

const optionsBoxRect = optionsBox.getBoundingClientRect();
const scrollFrameRect = scrollFrame.getBoundingClientRect();
const hiddenAreaHeight = optionsBoxRect.bottom - scrollFrameRect.bottom;

if (hiddenAreaHeight > 0) {
scrollFrame.scrollBy({ top: hiddenAreaHeight + 10 });
}
}, 100);
}

@action
onInput(parameterGroup, parameter, event) {
this.updateParameter(parameterGroup, parameter, event.target.value);
}

@action
updateParameter(parameterGroup, parameter, value) {
if (parameterGroup) {
const jobParameters = { ...this.selectedParameters.job[parameterGroup] };

jobParameters[parameter.name] = { value };
this.selectedParameters.job[parameterGroup] = jobParameters;
} else {
this.selectedParameters.pipeline[parameter.name] = { value };
}

const { pipeline, job } = this.selectedParameters;

this.args.onUpdateParameters({ ...pipeline, ...job });
}
}
64 changes: 64 additions & 0 deletions app/components/pipeline/parameters/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
@use 'screwdriver-colors' as colors;
@use 'variables';

@mixin styles {
.pipeline-parameters {
.parameter-title {
font-size: 1.2rem;
font-weight: variables.$weight-bold;
color: colors.$sd-light-gray;
}

.parameters-container {
max-height: 50vh;
overflow-y: scroll;

.parameter-group {
border-radius: 8px;
border: 1px solid colors.$sd-separator;
margin-top: 1rem;
padding: 0.5rem;

.group-title {
font-size: 1.5rem;
}

.parameter-list {
&.collapsed {
display: none;
}

.parameter {
display: flex;
padding: 0.2rem;

label {
display: flex;
margin-top: auto;
margin-bottom: auto;
padding-right: 0.5rem;
flex-basis: 25%;

svg {
margin-top: auto;
margin-bottom: auto;
padding-left: 0.25rem;
}
}

.dropdown-selection-container {
flex: 1;
}

> input {
flex: 1;
border-radius: 4px;
border: 1px solid colors.$sd-text-med;
padding-left: 8px;
}
}
}
}
}
}
}
42 changes: 42 additions & 0 deletions app/components/pipeline/parameters/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<div class="pipeline-parameters">
<div class="parameter-title">
{{this.title}}
</div>
<div class="parameters-container">
{{#each this.parameters as |parameterGroup|}}
<div class="parameter-group">
<div class="group-title">
<FaIcon @icon={{if parameterGroup.isOpen "minus-square" "plus-square"}} {{on "click" (fn this.toggleParameterGroup parameterGroup.paramGroupTitle)}}></FaIcon>
{{parameterGroup.paramGroupTitle}}
</div>
<div class="parameter-list {{if parameterGroup.isOpen "expanded" "collapsed"}}">
{{#each parameterGroup.parameters as |parameter|}}
<div class="parameter">
<label>
{{parameter.name}}
{{#if parameter.description}}
<FaIcon @icon="question-circle" @title={{parameter.description}}></FaIcon>
{{/if}}
</label>
{{#if (is-array parameter.defaultValues)}}
<div class="dropdown-selection-container">
<Pipeline::Parameters::Selectable
@parameter={{parameter}}
@onOpen={{this.openSelect}}
@onSelectValue={{(fn this.updateParameter parameterGroup.jobName)}}
/>
</div>
{{else}}
<Input
@value={{parameter.value}}
defaultValue={{parameter.value}}
{{on "input" (fn this.onInput parameterGroup.jobName parameter)}}
/>
{{/if}}
</div>
{{/each}}
</div>
</div>
{{/each}}
</div>
</div>
42 changes: 42 additions & 0 deletions app/utils/pipeline/parameters.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
/**
* Extracts parameters from the API response object of an event
* @param event
* @returns {{pipelineParameters: {}, jobParameters: {}}}
*/
export function extractEventParameters(event) {
const eventParameters = event.meta.parameters || {};
const pipelineParameters = {};
const jobParameters = {};

// Extract pipeline level and job level parameters
Object.entries(eventParameters).forEach(([propertyName, propertyVal]) => {
const keys = Object.keys(propertyVal);

if (keys.length === 1 && keys[0] === 'value') {
pipelineParameters[propertyName] = propertyVal;
} else {
jobParameters[propertyName] = propertyVal;
}
});

return {
pipelineParameters,
jobParameters
};
}

/**
* Extracts job parameters from the API response object of a job
*/
export function extractJobParameters(jobs) {
if (jobs.length === 0) {
return {};
}

return jobs.reduce((jobParameters, job) => {
jobParameters[job.name] = job.permutations[0].parameters;

return jobParameters;
}, {});
}

/**
* normalizeParameters transform given parameters from object into array of objects
* this method also backfills with default properties
Expand Down
Loading