Compare commits
35 Commits
master
...
first-clas
Author | SHA1 | Date |
---|---|---|
kzantow | 7f9cf649ef | |
kzantow | 4264c72112 | |
kzantow | 183c83a4fa | |
kzantow | 772540946f | |
kzantow | 4083806d30 | |
kzantow | 944ad55dfc | |
kzantow | e7ba99feb7 | |
kzantow | 15d0254bce | |
kzantow | a2fadf15c5 | |
kzantow | 13c91c75a1 | |
kzantow | afd9abd767 | |
Cliff Meyers | 37d4ba3b24 | |
Cliff Meyers | 250da96ca5 | |
Cliff Meyers | cc5a1a09f4 | |
Cliff Meyers | 7459fc3975 | |
kzantow | dc9139ae39 | |
kzantow | a856e6b422 | |
kzantow | 20e5fd31d2 | |
kzantow | 56d0816844 | |
kzantow | d90eb68572 | |
kzantow | e063944582 | |
kzantow | b566f3d82c | |
kzantow | 2a808b2295 | |
kzantow | 479bc8e994 | |
kzantow | fdbe5a664f | |
kzantow | 3397771a85 | |
kzantow | a91b41e01d | |
kzantow | 898323353f | |
kzantow | d09af3e650 | |
kzantow | 7e21edafef | |
kzantow | c24dfaf8c6 | |
kzantow | 4ebf1cfebb | |
kzantow | f41a636492 | |
kzantow | 8d3c0e0893 | |
kzantow | 7a4cc9c2bc |
|
@ -36,7 +36,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@jenkins-cd/design-language": "0.0.64",
|
||||
"@jenkins-cd/js-extensions": "0.0.19",
|
||||
"@jenkins-cd/js-extensions": "0.0.20-beta-1",
|
||||
"@jenkins-cd/js-modules": "0.0.5",
|
||||
"@jenkins-cd/sse-gateway": "0.0.6",
|
||||
"immutable": "3.8.1",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Route, Redirect, IndexRoute, IndexRedirect } from 'react-router';
|
||||
|
||||
import React from 'react';
|
||||
import Dashboard from './Dashboard';
|
||||
import OrganizationPipelines from './OrganizationPipelines';
|
||||
|
@ -14,34 +14,60 @@ import {
|
|||
RunDetailsArtifacts,
|
||||
RunDetailsTests,
|
||||
} from './components';
|
||||
import Extensions from '@jenkins-cd/js-extensions';
|
||||
|
||||
const DynamicRoutes = {
|
||||
path: ':pipeline/(.*)',
|
||||
|
||||
getChildRoutes(partialNextState, callback) {
|
||||
Extensions.store.getExtensions('pipeline.routes', routes => {
|
||||
callback(null, routes); // routes is array
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default (
|
||||
<Route path="/" component={Dashboard}>
|
||||
<Route path="organizations/:organization" component={OrganizationPipelines}>
|
||||
<IndexRedirect to="pipelines" />
|
||||
<Route path="pipelines" component={Pipelines} />
|
||||
{ path: '', component: Dashboard, indexRoute: {
|
||||
onEnter: ({ params }, replace) => replace('pipelines'),
|
||||
},
|
||||
childRoutes: [
|
||||
{ path: 'organizations/:organization', component: OrganizationPipelines,
|
||||
indexRoute: { onEnter: ({ params }, replace) => replace(`/organizations/${params.organization}/pipelines`) },
|
||||
childRoutes: [
|
||||
{ path: 'pipelines', component: Pipelines },
|
||||
|
||||
<Route component={PipelinePage}>
|
||||
<Route path=":pipeline/branches" component={MultiBranch} />
|
||||
<Route path=":pipeline/activity" component={Activity} />
|
||||
<Route path=":pipeline/pr" component={PullRequests} />
|
||||
{ component: PipelinePage, childRoutes: [
|
||||
{ path: ':pipeline/branches', component: MultiBranch },
|
||||
{ path: ':pipeline/activity', component: Activity },
|
||||
{ path: ':pipeline/pr', component: PullRequests },
|
||||
|
||||
<Route path=":pipeline/detail/:branch/:runId" component={RunDetails}>
|
||||
<IndexRedirect to="pipeline" />
|
||||
<Route path="pipeline" component={RunDetailsPipeline} >
|
||||
<Route path=":node" component={RunDetailsPipeline} />
|
||||
</Route>
|
||||
<Route path="changes" component={RunDetailsChanges} />
|
||||
<Route path="tests" component={RunDetailsTests} />
|
||||
<Route path="artifacts" component={RunDetailsArtifacts} />
|
||||
</Route>
|
||||
{ path: ':pipeline/detail/:branch/:runId', component: RunDetails,
|
||||
indexRoute: {
|
||||
onEnter: ({ params }, replace) => replace(
|
||||
`/organizations/${params.organization}/${encodeURIComponent(params.pipeline)}/` +
|
||||
`detail/${params.branch}/${params.runId}/pipeline`
|
||||
),
|
||||
},
|
||||
childRoutes: [
|
||||
{ path: 'pipeline', component: RunDetailsPipeline, childRoutes: [
|
||||
{ path: ':node', component: RunDetailsPipeline },
|
||||
] },
|
||||
{ path: 'changes', component: RunDetailsChanges },
|
||||
{ path: 'tests', component: RunDetailsTests },
|
||||
{ path: 'artifacts', component: RunDetailsArtifacts },
|
||||
],
|
||||
},
|
||||
|
||||
<Redirect from=":pipeline(/*)" to=":pipeline/activity" />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/pipelines" component={OrganizationPipelines}>
|
||||
<IndexRoute component={Pipelines} />
|
||||
</Route>
|
||||
<IndexRedirect to="pipelines" />
|
||||
</Route>
|
||||
DynamicRoutes,
|
||||
// TODO: need to convert this to onEnter - somehow?
|
||||
//<Redirect from=":pipeline(/*)" to=":pipeline/activity" />
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ path: '/pipelines', component: OrganizationPipelines, indexRoute: {
|
||||
component: Pipelines,
|
||||
} },
|
||||
],
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component, PropTypes } from 'react';
|
||||
import Extensions, { dataType } from '@jenkins-cd/js-extensions';
|
||||
import { Link } from 'react-router';
|
||||
import { isFailure, isPending } from '../util/FetchStatus';
|
||||
import NotFound from './NotFound';
|
||||
|
@ -7,7 +8,6 @@ import {
|
|||
PageHeader,
|
||||
Title,
|
||||
PageTabs,
|
||||
TabLink,
|
||||
WeatherIcon,
|
||||
Favorite,
|
||||
} from '@jenkins-cd/design-language';
|
||||
|
@ -47,9 +47,7 @@ export default class PipelinePage extends Component {
|
|||
<Favorite className="dark-yellow" />
|
||||
</Title>
|
||||
<PageTabs base={baseUrl}>
|
||||
<TabLink to="/activity">Activity</TabLink>
|
||||
<TabLink to="/branches">Branches</TabLink>
|
||||
<TabLink to="/pr">Pull Requests</TabLink>
|
||||
<Extensions.Renderer extensionPoint="pipeline.main.navigation" filter={dataType(pipeline._jobClass)} pipeline={pipeline} baseLink={baseUrl} />
|
||||
</PageTabs>
|
||||
</PageHeader>
|
||||
{React.cloneElement(this.props.children, { pipeline })}
|
||||
|
|
|
@ -5,8 +5,8 @@ import {
|
|||
ModalHeader,
|
||||
PipelineResult,
|
||||
PageTabs,
|
||||
TabLink,
|
||||
} from '@jenkins-cd/design-language';
|
||||
import Extensions, { dataType } from '@jenkins-cd/js-extensions';
|
||||
|
||||
import {
|
||||
actions,
|
||||
|
@ -119,10 +119,7 @@ class RunDetails extends Component {
|
|||
onAuthorsClick={() => this.navigateToChanges()}
|
||||
/>
|
||||
<PageTabs base={baseUrl}>
|
||||
<TabLink to="/pipeline">Pipeline</TabLink>
|
||||
<TabLink to="/changes">Changes</TabLink>
|
||||
<TabLink to="/tests">Tests</TabLink>
|
||||
<TabLink to="/artifacts">Artifacts</TabLink>
|
||||
<Extensions.Renderer extensionPoint="rundetails.main.navigation" filter={dataType(currentRun)} currentRun={currentRun} baseLink={baseUrl} />
|
||||
</PageTabs>
|
||||
</div>
|
||||
</ModalHeader>
|
||||
|
|
|
@ -268,6 +268,11 @@ export class RunDetailsPipeline extends Component {
|
|||
const noSteps = !log && currentSteps && currentSteps.model && currentSteps.model.length === 0;
|
||||
const shouldShowLogHeader = log !== null || !noSteps;
|
||||
return (
|
||||
<div>
|
||||
<Extensions.Renderer
|
||||
extensionPoint="jenkins.pipeline.run.details"
|
||||
currentRun={this.props.result}
|
||||
/>
|
||||
<div ref="scrollArea">
|
||||
{ nodes && nodes[nodeKey] && <Extensions.Renderer
|
||||
extensionPoint="jenkins.pipeline.run.result"
|
||||
|
@ -300,6 +305,7 @@ export class RunDetailsPipeline extends Component {
|
|||
|
||||
{ log && <LogConsole key={logGeneral.url} logArray={log.logArray} scrollToBottom={scrollToBottom} /> }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { Component, PropTypes } from 'react';
|
|||
import { EmptyStateView } from '@jenkins-cd/design-language';
|
||||
import { actions as selectorActions, testResults as testResultsSelector,
|
||||
connect, createSelector } from '../redux';
|
||||
import Extensions, { dataType } from '@jenkins-cd/js-extensions';
|
||||
import Extensions, { mostSpecificDataType } from '@jenkins-cd/js-extensions';
|
||||
|
||||
const EmptyState = () => (
|
||||
<EmptyStateView tightSpacing>
|
||||
|
@ -58,7 +58,7 @@ export class RunDetailsTests extends Component {
|
|||
<div className="test-result-duration">Duration {testResults.duration}</div>
|
||||
</div>
|
||||
|
||||
<Extensions.Renderer extensionPoint="jenkins.test.result" filter={dataType(testResults)} testResults={testResults} />
|
||||
<Extensions.Renderer extensionPoint="jenkins.test.result" filter={mostSpecificDataType(testResults)} testResults={testResults} />
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
import { TabLink } from '@jenkins-cd/design-language';
|
||||
|
||||
export default class RunDetailsArtifactsTab extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<TabLink to={`${this.props.baseLink}/artifacts`}>Artifacts</TabLink>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RunDetailsArtifactsTab.propTypes = {
|
||||
pipeline: React.PropTypes.any,
|
||||
baseLink: React.PropTypes.string,
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
import React from 'react';
|
||||
import { TabLink } from '@jenkins-cd/design-language';
|
||||
|
||||
export default class RunDetailsTabs extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<span>
|
||||
<TabLink to={`${this.props.baseLink}/pipeline`}>Pipeline</TabLink>
|
||||
<TabLink to={`${this.props.baseLink}/changes`}>Changes</TabLink>
|
||||
<TabLink to={`${this.props.baseLink}/tests`}>Tests</TabLink>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RunDetailsTabs.propTypes = {
|
||||
pipeline: React.PropTypes.any,
|
||||
baseLink: React.PropTypes.string,
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { TabLink } from '@jenkins-cd/design-language';
|
||||
|
||||
export default class PipelineActivityTab extends React.Component {
|
||||
render() {
|
||||
return <TabLink to={`${this.props.baseLink}/activity`}>Activity</TabLink>;
|
||||
}
|
||||
}
|
||||
|
||||
PipelineActivityTab.propTypes = {
|
||||
pipeline: React.PropTypes.any,
|
||||
baseLink: React.PropTypes.string,
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { TabLink } from '@jenkins-cd/design-language';
|
||||
|
||||
export default class PipelineBranchesTab extends React.Component {
|
||||
render() {
|
||||
return <TabLink to={`${this.props.baseLink}/branches`}>Branches</TabLink>;
|
||||
}
|
||||
}
|
||||
|
||||
PipelineBranchesTab.propTypes = {
|
||||
pipeline: React.PropTypes.any,
|
||||
baseLink: React.PropTypes.string,
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
import React from 'react';
|
||||
import { TabLink } from '@jenkins-cd/design-language';
|
||||
|
||||
export default class PipelinePullRequestsTab extends React.Component {
|
||||
render() {
|
||||
return <TabLink to={`${this.props.baseLink}/pr`}>Pull Requests</TabLink>;
|
||||
}
|
||||
}
|
||||
|
||||
PipelinePullRequestsTab.propTypes = {
|
||||
pipeline: React.PropTypes.any,
|
||||
baseLink: React.PropTypes.string,
|
||||
};
|
|
@ -10,6 +10,24 @@ extensions:
|
|||
extensionPoint: jenkins.main.stores
|
||||
- component: components/PipelineRunGraph
|
||||
extensionPoint: jenkins.pipeline.run.result
|
||||
- component: components/tabs/PipelineActivityTab
|
||||
extensionPoint: pipeline.main.navigation
|
||||
dataType: hudson.model.Job
|
||||
- component: components/tabs/PipelineBranchesTab
|
||||
extensionPoint: pipeline.main.navigation
|
||||
dataType: org.jenkinsci.plugins.workflow.job.WorkflowJob
|
||||
- component: components/tabs/PipelinePullRequestsTab
|
||||
extensionPoint: pipeline.main.navigation
|
||||
dataType: org.jenkinsci.plugins.workflow.job.WorkflowJob
|
||||
- component: components/tabs/PipelineActivityTab
|
||||
extensionPoint: pipeline.main.navigation
|
||||
dataType: jenkins.branch.MultiBranchProject
|
||||
- component: components/tabs/PipelineBranchesTab
|
||||
extensionPoint: pipeline.main.navigation
|
||||
dataType: jenkins.branch.MultiBranchProject
|
||||
- component: components/tabs/PipelinePullRequestsTab
|
||||
extensionPoint: pipeline.main.navigation
|
||||
dataType: jenkins.branch.MultiBranchProject
|
||||
- component: components/testing/TestResults
|
||||
extensionPoint: jenkins.test.result
|
||||
dataType: hudson.tasks.test.TestResult
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
@import "variables";
|
||||
|
||||
@import "core";
|
||||
@import "page-tabs";
|
||||
@import "testing";
|
||||
@import "run-pipeline";
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
.page-tabs {
|
||||
> div, > div > div {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"presets": ["es2015", "stage-0", "react"]
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 160
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "@jenkins-cd/jenkins/react",
|
||||
"rules": {
|
||||
"react/jsx-no-bind": 0,
|
||||
"no-unused-vars": [2, {"varsIgnorePattern": "^React$"}],
|
||||
"max-len": [1, 160, 4]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import { configure } from '@kadira/storybook';
|
||||
|
||||
function loadStories() {
|
||||
require('../src/main/js/stories/index');
|
||||
}
|
||||
|
||||
configure(loadStories, module);
|
|
@ -0,0 +1,16 @@
|
|||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Reset -->
|
||||
<link href="/css/normalize.css" rel="stylesheet">
|
||||
|
||||
<!-- Icons -->
|
||||
<link href="/css/latofonts.css" rel="stylesheet">
|
||||
<link href="/octicons/octicons.css" rel="stylesheet">
|
||||
|
||||
<!-- Jenkins theme -->
|
||||
<link href="/css/jenkins-design-language.css" rel="stylesheet">
|
||||
|
||||
<!-- styles -->
|
||||
<link href="/extensions.css" rel="stylesheet">
|
|
@ -0,0 +1,11 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
module: {},
|
||||
resolve: {
|
||||
extensions: [
|
||||
'.js', // required by storybook
|
||||
'', '.jsx' // for blueocean files
|
||||
],
|
||||
}
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License
|
||||
|
||||
Copyright (c) 2016 CloudBees Inc and a number of other of contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// See https://github.com/jenkinsci/js-builder
|
||||
//
|
||||
var builder = require('@jenkins-cd/js-builder')
|
||||
.withExternalModuleMapping('react-router', 'react:react-router');
|
||||
|
||||
//
|
||||
// Redefine the "test" task to use mocha and support es6.
|
||||
// We might build this into js-builder, but is ok here
|
||||
// for now.
|
||||
//
|
||||
builder.defineTask('test', function() {
|
||||
var mocha = require('gulp-mocha');
|
||||
var babel = require('babel-core/register');
|
||||
|
||||
builder.gulp.src('src/test/js/**/*-spec.jsx')
|
||||
.pipe(mocha({
|
||||
compilers: { js: babel },
|
||||
})).on('error', function(e) {
|
||||
if (builder.isRetest()) {
|
||||
// ignore test failures if we are running retest.
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
builder.gulp.task('lint:watch', function () {
|
||||
builder.gulp.watch(['src/main/js/**/*.js', 'src/main/js/**/*.jsx'], ['lint']);
|
||||
});
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"name": "blueocean-freestyle",
|
||||
"version": "0.0.1-beta-1",
|
||||
"scripts": {
|
||||
"storybook": "start-storybook -p 9001 -s node_modules/@jenkins-cd/design-language/dist/assets/,target/classes/org/jenkins/ui/jsmodules/blueocean_freestyle/",
|
||||
"lint": "gulp lint",
|
||||
"lint:fix": "gulp lint --fixLint",
|
||||
"lint:watch": "gulp lint:watch --continueOnLint",
|
||||
"test": "gulp test",
|
||||
"test:watch": "gulp test:watch",
|
||||
"bundle": "gulp bundle",
|
||||
"bundle:watch": "gulp bundle:watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jenkins-cd/eslint-config-jenkins": "0.0.2",
|
||||
"@jenkins-cd/js-builder": "0.0.34",
|
||||
"@jenkins-cd/js-test": "1.1.1",
|
||||
"@kadira/storybook": "1.34.0",
|
||||
"babel": "^6.5.2",
|
||||
"babel-core": "^6.7.6",
|
||||
"babel-eslint": "^6.0.2",
|
||||
"babel-preset-es2015": "^6.6.0",
|
||||
"babel-preset-react": "^6.5.0",
|
||||
"babel-preset-stage-0": "^6.5.0",
|
||||
"chai": "^3.5.0",
|
||||
"enzyme": "2.3.0",
|
||||
"eslint": "2.8.0",
|
||||
"eslint-plugin-react": "^5.0.1",
|
||||
"eslint-to-editorconfig": "1.2.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-mocha": "^2.2.0",
|
||||
"mocha": "^2.4.5",
|
||||
"nock": "^8.0.0",
|
||||
"react-addons-test-utils": "15.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jenkins-cd/design-language": "0.0.63",
|
||||
"@jenkins-cd/js-extensions": "0.0.19-beta-3",
|
||||
"@jenkins-cd/js-modules": "0.0.5",
|
||||
"@jenkins-cd/sse-gateway": "0.0.5",
|
||||
"immutable": "3.8.1",
|
||||
"isomorphic-fetch": "2.2.1",
|
||||
"keymirror": "0.1.1",
|
||||
"moment": "2.13.0",
|
||||
"moment-duration-format": "1.3.0",
|
||||
"react": "15.1.0",
|
||||
"react-dom": "15.1.0",
|
||||
"react-material-icons-blue": "1.0.4",
|
||||
"react-redux": "4.4.5",
|
||||
"react-router": "2.3.0",
|
||||
"redux": "3.5.2",
|
||||
"redux-thunk": "2.0.1",
|
||||
"reselect": "2.5.1",
|
||||
"window-handle": "1.0.0"
|
||||
},
|
||||
"jenkinscd": {
|
||||
"extDependencies": [
|
||||
"@jenkins-cd/sse-gateway",
|
||||
"immutable",
|
||||
"isomorphic-fetch",
|
||||
"react-router",
|
||||
"keymirror",
|
||||
"react-redux",
|
||||
"react-router",
|
||||
"redux",
|
||||
"redux-thunk",
|
||||
"reselect"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>blueocean-parent</artifactId>
|
||||
<groupId>io.jenkins.blueocean</groupId>
|
||||
<version>1.0-alpha-5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<name>BlueOcean :: Freestyle</name>
|
||||
<artifactId>blueocean-freestyle</artifactId>
|
||||
<packaging>hpi</packaging>
|
||||
|
||||
<url>https://wiki.jenkins-ci.org/display/JENKINS/Blue+Ocean+Plugin</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>blueocean-rest</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>blueocean-rest-impl</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,102 @@
|
|||
package io.jenkins.blueocean.freestyle;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.jenkins.blueocean.rest.annotation.Capability;
|
||||
import io.jenkins.blueocean.rest.hal.Link;
|
||||
import io.jenkins.blueocean.rest.model.BlueActionProxy;
|
||||
import io.jenkins.blueocean.rest.model.BlueFavorite;
|
||||
import io.jenkins.blueocean.rest.model.BlueFavoriteAction;
|
||||
import io.jenkins.blueocean.rest.model.BluePipeline;
|
||||
import io.jenkins.blueocean.rest.model.BlueQueueContainer;
|
||||
import io.jenkins.blueocean.rest.model.BlueRun;
|
||||
import io.jenkins.blueocean.rest.model.BlueRunContainer;
|
||||
|
||||
@Capability("freestyle.project")
|
||||
public class BlueFreestylePipeline extends BluePipeline {
|
||||
|
||||
@Override
|
||||
public Link getLink() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueFavorite favorite(BlueFavoriteAction arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BlueActionProxy> getActions() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getEstimatedDurationInMillis() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullName() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJobClass() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLastSuccessfulRun() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueRun getLatestRun() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrganization() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueQueueContainer getQueue() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueRunContainer getRuns() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getWeatherScore() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package io.jenkins.blueocean.freestyle;
|
||||
|
||||
import hudson.model.Item;
|
||||
import io.jenkins.blueocean.rest.Reachable;
|
||||
import io.jenkins.blueocean.rest.model.BluePipeline;
|
||||
import io.jenkins.blueocean.rest.model.Resource;
|
||||
import io.jenkins.blueocean.service.embedded.rest.BluePipelineFactory;
|
||||
|
||||
public class BlueFreestyleProjectFactory extends BluePipelineFactory {
|
||||
|
||||
@Override
|
||||
public BluePipeline getPipeline(Item arg0, Reachable arg1) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource resolve(Item arg0, Reachable arg1, Item arg2) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package io.jenkins.blueocean.freestyle;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import io.jenkins.blueocean.rest.hal.Link;
|
||||
import io.jenkins.blueocean.rest.model.BlueActionProxy;
|
||||
import io.jenkins.blueocean.rest.model.BlueChangeSetEntry;
|
||||
import io.jenkins.blueocean.rest.model.BluePipelineNodeContainer;
|
||||
import io.jenkins.blueocean.rest.model.BluePipelineStepContainer;
|
||||
import io.jenkins.blueocean.rest.model.BlueQueueItem;
|
||||
import io.jenkins.blueocean.rest.model.BlueRun;
|
||||
import io.jenkins.blueocean.rest.model.Container;
|
||||
|
||||
public class BlueFreestyleRun extends BlueRun {
|
||||
|
||||
@Override
|
||||
public Link getLink() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BlueActionProxy> getActions() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Container<BlueArtifact> getArtifacts() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Container<BlueChangeSetEntry> getChangeSet() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getDurationInMillis() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getEnQueueTime() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getEndTime() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getEstimatedDurtionInMillis() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getLog() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluePipelineNodeContainer getNodes() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOrganization() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPipeline() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueRunResult getResult() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRunSummary() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getStartTime() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueRunState getStateObj() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluePipelineStepContainer getSteps() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueQueueItem replay() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueRun stop() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package io.jenkins.blueocean.freestyle;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import io.jenkins.blueocean.rest.hal.Link;
|
||||
import io.jenkins.blueocean.rest.model.BluePipeline;
|
||||
import io.jenkins.blueocean.rest.model.BlueQueueItem;
|
||||
import io.jenkins.blueocean.rest.model.BlueRun;
|
||||
import io.jenkins.blueocean.rest.model.BlueRunContainer;
|
||||
|
||||
public class BlueFreestyleRunContainer extends BlueRunContainer {
|
||||
|
||||
@Override
|
||||
public Iterator<BlueRun> iterator() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Link getLink() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueQueueItem create() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluePipeline getPipeline(String arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueRun get(String arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import FreestyleDeployments from './components/FreestyleDeployments';
|
||||
|
||||
export default { path: 'deployments', component: FreestyleDeployments };
|
|
@ -0,0 +1,3 @@
|
|||
import FreestyleDeployments from './components/FreestyleDeployments';
|
||||
|
||||
export default { path: '/deployments', component: FreestyleDeployments };
|
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
|
||||
export default class FreestyleDeployments extends React.Component {
|
||||
render() {
|
||||
return <div>Some deployments</div>;
|
||||
}
|
||||
}
|
||||
|
||||
FreestyleDeployments.contextTypes = {
|
||||
pipeline: React.PropTypes.any,
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
import { TabLink } from '@jenkins-cd/design-language';
|
||||
|
||||
export default class FreestyleArtifactsTab extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<TabLink to={`${this.props.baseLink}/freestyle-artifacts`}>Freestyle Artifacts</TabLink>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FreestyleArtifactsTab.propTypes = {
|
||||
baseLink: React.PropTypes.string,
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
import React from 'react';
|
||||
import { TabLink } from '@jenkins-cd/design-language';
|
||||
|
||||
export default class FreestyleDeploymentsTab extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<TabLink to={`${this.props.baseLink}/deployments`}>Deployments</TabLink>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FreestyleDeploymentsTab.propTypes = {
|
||||
baseLink: React.PropTypes.string,
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
# Extensions in this plugin
|
||||
extensions:
|
||||
- component: PipelineRoutes
|
||||
extensionPoint: pipeline.routes
|
||||
|
||||
- component: Routes
|
||||
extensionPoint: jenkins.main.routes
|
||||
|
||||
- component: components/tabs/FreestyleDeploymentsTab
|
||||
extensionPoint: pipeline.main.navigation
|
||||
dataType: hudson.model.FreeStyleProject
|
||||
|
||||
- component: components/tabs/FreestyleArtifactsTab
|
||||
extensionPoint: rundetails.main.navigation
|
||||
dataType: io.jenkins.blueocean.service.embedded.rest.FreeStyleRunImpl
|
|
@ -0,0 +1 @@
|
|||
// nothing to see here
|
|
@ -0,0 +1,4 @@
|
|||
<?jelly escape-by-default='true'?>
|
||||
<div>
|
||||
Blue Ocean Freestyle
|
||||
</div>
|
|
@ -56,6 +56,10 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline {
|
|||
return OrganizationImpl.INSTANCE.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJobClass() {
|
||||
return mbp.getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlueFavorite favorite(@JsonBody BlueFavoriteAction favoriteAction) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import hudson.scm.ChangeLogSet;
|
|||
import hudson.scm.ChangeLogSet.Entry;
|
||||
import io.jenkins.blueocean.commons.ServiceException;
|
||||
import io.jenkins.blueocean.rest.Reachable;
|
||||
import io.jenkins.blueocean.rest.annotation.Capability;
|
||||
import io.jenkins.blueocean.rest.hal.Link;
|
||||
import io.jenkins.blueocean.rest.model.BlueChangeSetEntry;
|
||||
import io.jenkins.blueocean.rest.model.BluePipelineNodeContainer;
|
||||
|
@ -32,6 +33,7 @@ import java.util.Map;
|
|||
*
|
||||
* @author Vivek Pandey
|
||||
*/
|
||||
@Capability("io.jenkins.blueocean.rest.model.BlueArtifactProvider")
|
||||
public class PipelineRunImpl extends AbstractRunImpl<WorkflowRun> {
|
||||
public PipelineRunImpl(WorkflowRun run, Link parent) {
|
||||
super(run, parent);
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>blueocean-personalization</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>blueocean-freestyle</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>blueocean-rest</artifactId>
|
||||
|
@ -106,6 +110,7 @@
|
|||
linkHPI('blueocean-rest');
|
||||
linkHPI('blueocean-commons');
|
||||
linkHPI('blueocean-rest-impl');
|
||||
linkHPI('blueocean-freestyle');
|
||||
linkHPI('blueocean-pipeline-api-impl')
|
||||
</source>
|
||||
</configuration>
|
||||
|
|
|
@ -42,6 +42,11 @@ public class PipelineFolderImpl extends BluePipelineFolder {
|
|||
return folder.getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJobClass() {
|
||||
return folder.getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return folder.getDisplayName();
|
||||
|
|
|
@ -19,6 +19,7 @@ import io.jenkins.blueocean.rest.model.BlueRunContainer;
|
|||
import io.jenkins.blueocean.rest.model.Resource;
|
||||
import org.kohsuke.stapler.Stapler;
|
||||
import org.kohsuke.stapler.WebMethod;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
import org.kohsuke.stapler.json.JsonBody;
|
||||
import org.kohsuke.stapler.verb.DELETE;
|
||||
|
||||
|
@ -47,6 +48,11 @@ public class PipelineImpl extends BluePipeline {
|
|||
return job.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJobClass() {
|
||||
return job.getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return job.getDisplayName();
|
||||
|
|
|
@ -39,6 +39,12 @@ public abstract class BluePipeline extends Resource {
|
|||
@Exported(name = NAME)
|
||||
public abstract String getName();
|
||||
|
||||
/**
|
||||
* Return the underlying job class
|
||||
*/
|
||||
@Exported(name="_jobClass")
|
||||
public abstract String getJobClass();
|
||||
|
||||
/**
|
||||
* @return human readable name of this pipeline
|
||||
*/
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@jenkins-cd/design-language": "0.0.64",
|
||||
"@jenkins-cd/js-extensions": "0.0.19",
|
||||
"@jenkins-cd/js-extensions": "0.0.20-beta-1",
|
||||
"@jenkins-cd/js-modules": "0.0.5",
|
||||
"history": "2.0.2",
|
||||
"immutable": "3.8.1",
|
||||
|
|
|
@ -62,8 +62,8 @@ function makeRoutes(routes) {
|
|||
const appRoutes = [
|
||||
...routes,
|
||||
// FIXME: Not sure best how to set this up without the hardcoded IndexRedirect :-/
|
||||
<IndexRedirect to="/pipelines" />,
|
||||
<Route path="*" component={NotFound}/>
|
||||
//<IndexRedirect to="/pipelines" />,
|
||||
//<Route path="*" component={NotFound}/>
|
||||
];
|
||||
|
||||
const routeProps = {
|
||||
|
@ -71,7 +71,13 @@ function makeRoutes(routes) {
|
|||
component: App
|
||||
};
|
||||
|
||||
return React.createElement(Route, routeProps, ...appRoutes);
|
||||
//return React.createElement(Route, routeProps, ...appRoutes);
|
||||
|
||||
return {
|
||||
path: "/",
|
||||
component: App,
|
||||
childRoutes: routes
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,7 +144,7 @@ function startApp(routes, stores) {
|
|||
// Start React
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<Router history={history}>{ makeRoutes(routes) }</Router>
|
||||
<Router history={history} routes={ makeRoutes(routes) }/>
|
||||
</Provider>
|
||||
, rootElement);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@jenkins-cd/js-extensions",
|
||||
"version": "0.0.19",
|
||||
"version": "0.0.20-beta-1",
|
||||
"description": "Jenkins Extension Store",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
|
|
|
@ -34,7 +34,36 @@ export class ClassMetadataStore {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches all extensions that handle this data type or a supertype
|
||||
*/
|
||||
dataType(dataType) {
|
||||
return (extensions, onload) => {
|
||||
if (dataType && typeof(dataType) === 'object'
|
||||
&& '_class' in dataType) { // handle the common API incoming data
|
||||
dataType = dataType._class;
|
||||
}
|
||||
|
||||
this.getClassMetadata(dataType, (currentTypeInfo) => {
|
||||
// add all types that handle this data type
|
||||
var matchingExtensions = [];
|
||||
for (var i = 0; i < extensions.length; i++) {
|
||||
var extension = extensions[i];
|
||||
if (currentTypeInfo.classes.indexOf(extension.dataType) >= 0) {
|
||||
matchingExtensions.push(extension);
|
||||
}
|
||||
}
|
||||
onload(matchingExtensions);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the extensions based on the data type, stopping at the most specific
|
||||
* type of data: this can be used for getting the most specific
|
||||
* view for a particular class name, for example.
|
||||
*/
|
||||
mostSpecificDataType(dataType) {
|
||||
return (extensions, onload) => {
|
||||
if (dataType && typeof(dataType) === 'object'
|
||||
&& '_class' in dataType) { // handle the common API incoming data
|
||||
|
|
|
@ -118,6 +118,10 @@ export class ExtensionRenderer extends React.Component {
|
|||
|
||||
/** Actually render an individual extension */
|
||||
_renderExtension(element, extension) {
|
||||
if (extension.type && React.Component.isPrototypeOf(extension.type)) { // already instantiated, just use it
|
||||
ReactDOM.render(extension, element); // should probably bridge this
|
||||
return;
|
||||
}
|
||||
var component = React.createElement(extension, this.props);
|
||||
try {
|
||||
var contextValuesAsProps = {
|
||||
|
@ -169,6 +173,7 @@ ExtensionRenderer.propTypes = {
|
|||
};
|
||||
|
||||
ExtensionRenderer.contextTypes = {
|
||||
pipeline: React.PropTypes.any,
|
||||
router: React.PropTypes.object,
|
||||
config: React.PropTypes.object
|
||||
};
|
||||
|
|
|
@ -48,9 +48,11 @@ export class ExtensionStore {
|
|||
this._loadBundles(extensionPointId, () => this._registerComponentInstance(extensionPointId, pluginId, component, instance));
|
||||
return;
|
||||
}
|
||||
var extension = this._findPlugin(extensionPointId, pluginId, component);
|
||||
if (extension) {
|
||||
extension.instance = instance;
|
||||
extensions = this._findPlugins(extensionPointId, pluginId, component);
|
||||
if (extensions) {
|
||||
for (var extension of extensions) {
|
||||
extension.instance = instance;
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw new Error(`Unable to locate plugin for ${extensionPointId} / ${pluginId} / ${component}`);
|
||||
|
@ -59,15 +61,10 @@ export class ExtensionStore {
|
|||
/**
|
||||
* Finds a plugin by extension point id, plugin id, component name
|
||||
*/
|
||||
_findPlugin(extensionPointId, pluginId, component) {
|
||||
_findPlugins(extensionPointId, pluginId, component) {
|
||||
var extensions = this.extensionPoints[extensionPointId];
|
||||
if (extensions) {
|
||||
for (var i = 0; i < extensions.length; i++) {
|
||||
var extension = extensions[i];
|
||||
if (extension.pluginId == pluginId && extension.component == component) {
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
return extensions.filter(extension => extension.pluginId == pluginId && extension.component == component);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
7
pom.xml
7
pom.xml
|
@ -104,6 +104,7 @@
|
|||
<module>blueocean-events</module>
|
||||
<module>blueocean-dashboard</module>
|
||||
<module>blueocean-personalization</module>
|
||||
<module>blueocean-freestyle</module>
|
||||
<module>blueocean-plugin</module>
|
||||
</modules>
|
||||
|
||||
|
@ -154,6 +155,12 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>blueocean-freestyle</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>blueocean-events</artifactId>
|
||||
|
|
Loading…
Reference in New Issue