mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-15 09:46:16 +01:00
Merge pull request #1196 from scm-manager/feature/annotate
Annotate View
This commit is contained in:
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Added links in diff views to expand the gaps between "hunks" ([#1178](https://github.com/scm-manager/scm-manager/pull/1178))
|
- Added links in diff views to expand the gaps between "hunks" ([#1178](https://github.com/scm-manager/scm-manager/pull/1178))
|
||||||
- Show commit contributors in table on changeset details view ([#1169](https://github.com/scm-manager/scm-manager/pull/1169))
|
- Show commit contributors in table on changeset details view ([#1169](https://github.com/scm-manager/scm-manager/pull/1169))
|
||||||
- Show changeset parents on changeset details view ([#1189](https://github.com/scm-manager/scm-manager/pull/1189))
|
- Show changeset parents on changeset details view ([#1189](https://github.com/scm-manager/scm-manager/pull/1189))
|
||||||
|
- Annotate view to display commit metadata for each line of a file ([#1196](https://github.com/scm-manager/scm-manager/pull/1196))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Avoid caching of detected browser language ([#1176](https://github.com/scm-manager/scm-manager/pull/1176))
|
- Avoid caching of detected browser language ([#1176](https://github.com/scm-manager/scm-manager/pull/1176))
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.web;
|
package sonia.scm.web;
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
@@ -71,13 +71,12 @@ public class VndMediaType {
|
|||||||
@SuppressWarnings("squid:S2068")
|
@SuppressWarnings("squid:S2068")
|
||||||
public static final String PASSWORD_OVERWRITE = PREFIX + "passwordOverwrite" + SUFFIX;
|
public static final String PASSWORD_OVERWRITE = PREFIX + "passwordOverwrite" + SUFFIX;
|
||||||
public static final String PERMISSION_COLLECTION = PREFIX + "permissionCollection" + SUFFIX;
|
public static final String PERMISSION_COLLECTION = PREFIX + "permissionCollection" + SUFFIX;
|
||||||
public static final String MERGE_RESULT = PREFIX + "mergeResult" + SUFFIX;
|
|
||||||
public static final String MERGE_COMMAND = PREFIX + "mergeCommand" + SUFFIX;
|
|
||||||
|
|
||||||
public static final String NAMESPACE_STRATEGIES = PREFIX + "namespaceStrategies" + SUFFIX;
|
public static final String NAMESPACE_STRATEGIES = PREFIX + "namespaceStrategies" + SUFFIX;
|
||||||
|
|
||||||
public static final String ME = PREFIX + "me" + SUFFIX;
|
public static final String ME = PREFIX + "me" + SUFFIX;
|
||||||
public static final String SOURCE = PREFIX + "source" + SUFFIX;
|
public static final String SOURCE = PREFIX + "source" + SUFFIX;
|
||||||
|
public static final String ANNOTATE = PREFIX + "annotate" + SUFFIX;
|
||||||
public static final String ERROR_TYPE = PREFIX + "error" + SUFFIX;
|
public static final String ERROR_TYPE = PREFIX + "error" + SUFFIX;
|
||||||
|
|
||||||
public static final String REPOSITORY_ROLE = PREFIX + "repositoryRole" + SUFFIX;
|
public static final String REPOSITORY_ROLE = PREFIX + "repositoryRole" + SUFFIX;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"@types/react-select": "^2.0.19",
|
"@types/react-select": "^2.0.19",
|
||||||
"@types/react-syntax-highlighter": "^11.0.1",
|
"@types/react-syntax-highlighter": "^11.0.1",
|
||||||
"@types/storybook__addon-storyshots": "^5.1.1",
|
"@types/storybook__addon-storyshots": "^5.1.1",
|
||||||
"@types/styled-components": "^4.1.19",
|
"@types/styled-components": "^5.1.0",
|
||||||
"enzyme-context": "^1.1.2",
|
"enzyme-context": "^1.1.2",
|
||||||
"enzyme-context-react-router-4": "^2.0.0",
|
"enzyme-context-react-router-4": "^2.0.0",
|
||||||
"fetch-mock": "^7.5.1",
|
"fetch-mock": "^7.5.1",
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
"react-markdown": "^4.0.6",
|
"react-markdown": "^4.0.6",
|
||||||
"react-router-dom": "^5.1.2",
|
"react-router-dom": "^5.1.2",
|
||||||
"react-select": "^2.1.2",
|
"react-select": "^2.1.2",
|
||||||
"react-syntax-highlighter": "^11.0.2"
|
"react-syntax-highlighter": "https://github.com/conorhastings/react-syntax-highlighter#08bcf49b1aa7877ce94f7208e73dfa6bef8b26e7"
|
||||||
},
|
},
|
||||||
"babel": {
|
"babel": {
|
||||||
"presets": [
|
"presets": [
|
||||||
|
|||||||
@@ -24,25 +24,41 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import DateFromNow from "./DateFromNow";
|
import DateFromNow from "./DateFromNow";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
|
import DateShort from "./DateShort";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
timeZone: "Europe/Berlin",
|
timeZone: "Europe/Berlin",
|
||||||
baseDate: "2019-10-12T13:56:42+02:00"
|
baseDate: "2019-10-12T13:56:42+02:00"
|
||||||
};
|
};
|
||||||
|
|
||||||
storiesOf("DateFromNow", module).add("Default", () => (
|
const dates = [
|
||||||
<div>
|
"2009-06-30T18:30:00+02:00",
|
||||||
<p>
|
"2019-06-30T18:30:00+02:00",
|
||||||
<DateFromNow date="2009-06-30T18:30:00+02:00" {...baseProps} />
|
"2019-10-12T13:56:40+02:00",
|
||||||
</p>
|
"2019-10-11T13:56:40+02:00"
|
||||||
<p>
|
];
|
||||||
<DateFromNow date="2019-06-30T18:30:00+02:00" {...baseProps} />
|
|
||||||
</p>
|
const Wrapper = styled.div`
|
||||||
<p>
|
padding: 2rem;
|
||||||
<DateFromNow date="2019-10-12T13:56:40+02:00" {...baseProps} />
|
`;
|
||||||
</p>
|
|
||||||
<p>
|
storiesOf("Date", module)
|
||||||
<DateFromNow date="2019-10-11T13:56:40+02:00" {...baseProps} />
|
.add("Date from now", () => (
|
||||||
</p>
|
<Wrapper>
|
||||||
</div>
|
{dates.map(d => (
|
||||||
));
|
<p>
|
||||||
|
<DateFromNow date={d} {...baseProps} />
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</Wrapper>
|
||||||
|
))
|
||||||
|
.add("Short", () => (
|
||||||
|
<Wrapper>
|
||||||
|
{dates.map(d => (
|
||||||
|
<p>
|
||||||
|
<DateShort date={d} {...baseProps} />
|
||||||
|
</p>
|
||||||
|
))}
|
||||||
|
</Wrapper>
|
||||||
|
));
|
||||||
31
scm-ui/ui-components/src/DateElement.ts
Normal file
31
scm-ui/ui-components/src/DateElement.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const DateElement = styled.time`
|
||||||
|
border-bottom: 1px dotted rgba(219, 219, 219);
|
||||||
|
cursor: help;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default DateElement;
|
||||||
@@ -21,109 +21,26 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React from "react";
|
|
||||||
import { withTranslation, WithTranslation } from "react-i18next";
|
|
||||||
import { formatDistance, format, parseISO, Locale } from "date-fns";
|
|
||||||
import { enUS, de, es } from "date-fns/locale";
|
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type LocaleMap = {
|
import React, { FC } from "react";
|
||||||
[key: string]: Locale;
|
import useDateFormatter, { DateProps } from "./useDateFormatter";
|
||||||
|
import DateElement from "./DateElement";
|
||||||
|
|
||||||
|
type Props = DateProps & {
|
||||||
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DateInput = Date | string;
|
const DateFromNow: FC<Props> = ({ className, ...dateProps }) => {
|
||||||
|
const formatter = useDateFormatter(dateProps);
|
||||||
export const supportedLocales: LocaleMap = {
|
if (!formatter) {
|
||||||
enUS,
|
|
||||||
en: enUS,
|
|
||||||
de,
|
|
||||||
es
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
|
||||||
date?: DateInput;
|
|
||||||
timeZone?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* baseDate is the date from which the distance is calculated,
|
|
||||||
* default is the current time (new Date()). This property
|
|
||||||
* is required to keep snapshots tests green over the time on
|
|
||||||
* ci server.
|
|
||||||
*/
|
|
||||||
baseDate?: DateInput;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Options = {
|
|
||||||
addSuffix: boolean;
|
|
||||||
locale: Locale;
|
|
||||||
timeZone?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const DateElement = styled.time`
|
|
||||||
border-bottom: 1px dotted rgba(219, 219, 219);
|
|
||||||
cursor: help;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const chooseLocale = (language: string, languages?: string[]) => {
|
|
||||||
for (const lng of languages || []) {
|
|
||||||
const locale = supportedLocales[lng];
|
|
||||||
if (locale) {
|
|
||||||
return locale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const locale = supportedLocales[language];
|
|
||||||
if (locale) {
|
|
||||||
return locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
return enUS;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DateFromNow extends React.Component<Props> {
|
|
||||||
getLocale = (): Locale => {
|
|
||||||
const { i18n } = this.props;
|
|
||||||
return chooseLocale(i18n.language, i18n.languages);
|
|
||||||
};
|
|
||||||
|
|
||||||
createOptions = () => {
|
|
||||||
const { timeZone } = this.props;
|
|
||||||
const options: Options = {
|
|
||||||
addSuffix: true,
|
|
||||||
locale: this.getLocale()
|
|
||||||
};
|
|
||||||
if (timeZone) {
|
|
||||||
options.timeZone = timeZone;
|
|
||||||
}
|
|
||||||
return options;
|
|
||||||
};
|
|
||||||
|
|
||||||
toDate = (value: DateInput): Date => {
|
|
||||||
if (value instanceof Date) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
return parseISO(value);
|
|
||||||
};
|
|
||||||
|
|
||||||
getBaseDate = () => {
|
|
||||||
const { baseDate } = this.props;
|
|
||||||
if (baseDate) {
|
|
||||||
return this.toDate(baseDate);
|
|
||||||
}
|
|
||||||
return new Date();
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { date } = this.props;
|
|
||||||
if (date) {
|
|
||||||
const isoDate = this.toDate(date);
|
|
||||||
const options = this.createOptions();
|
|
||||||
const distance = formatDistance(isoDate, this.getBaseDate(), options);
|
|
||||||
const formatted = format(isoDate, "yyyy-MM-dd HH:mm:ss", options);
|
|
||||||
return <DateElement title={formatted}>{distance}</DateElement>;
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export default withTranslation()(DateFromNow);
|
return (
|
||||||
|
<DateElement className={className} title={formatter.formatFull()}>
|
||||||
|
{formatter.formatDistance()}
|
||||||
|
</DateElement>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DateFromNow;
|
||||||
|
|||||||
46
scm-ui/ui-components/src/DateShort.tsx
Normal file
46
scm-ui/ui-components/src/DateShort.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import useDateFormatter, { DateProps } from "./useDateFormatter";
|
||||||
|
import DateElement from "./DateElement";
|
||||||
|
|
||||||
|
type Props = DateProps & {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DateShort: FC<Props> = ({ className, ...dateProps }) => {
|
||||||
|
const formatter = useDateFormatter(dateProps);
|
||||||
|
if (!formatter) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DateElement className={className} title={formatter.formatFull()}>
|
||||||
|
{formatter.formatShort()}
|
||||||
|
</DateElement>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DateShort;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,7 @@ import {
|
|||||||
export { validation, urls, repositories };
|
export { validation, urls, repositories };
|
||||||
|
|
||||||
export { default as DateFromNow } from "./DateFromNow";
|
export { default as DateFromNow } from "./DateFromNow";
|
||||||
|
export { default as DateShort } from "./DateShort";
|
||||||
export { default as ErrorNotification } from "./ErrorNotification";
|
export { default as ErrorNotification } from "./ErrorNotification";
|
||||||
export { default as ErrorPage } from "./ErrorPage";
|
export { default as ErrorPage } from "./ErrorPage";
|
||||||
export { default as Icon } from "./Icon";
|
export { default as Icon } from "./Icon";
|
||||||
|
|||||||
131
scm-ui/ui-components/src/repos/annotate/Annotate.stories.tsx
Normal file
131
scm-ui/ui-components/src/repos/annotate/Annotate.stories.tsx
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { storiesOf } from "@storybook/react";
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import Annotate from "./Annotate";
|
||||||
|
import { MemoryRouter } from "react-router-dom";
|
||||||
|
import repository from "../../__resources__/repository";
|
||||||
|
import { Binder, BinderContext } from "@scm-manager/ui-extensions";
|
||||||
|
import { Person } from "../../avatar/Avatar";
|
||||||
|
import { AnnotatedSource } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
margin: 2rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const commitCreateNewApp = {
|
||||||
|
revision: "0d8c1d328f4599b363755671afe667c7ace52bae",
|
||||||
|
author: {
|
||||||
|
name: "Arthur Dent",
|
||||||
|
mail: "arthur.dent@hitchhiker.com"
|
||||||
|
},
|
||||||
|
description: "create new app",
|
||||||
|
when: new Date("2020-04-09T13:07:42Z")
|
||||||
|
};
|
||||||
|
|
||||||
|
const commitFixedMissingImport = {
|
||||||
|
revision: "fab38559ce3ab8c388e067712b4bd7ab94b9fa9b",
|
||||||
|
author: {
|
||||||
|
name: "Tricia Marie McMillan",
|
||||||
|
mail: "trillian@hitchhiker.com"
|
||||||
|
},
|
||||||
|
description: "fixed missing import",
|
||||||
|
when: new Date("2020-05-10T09:18:42Z")
|
||||||
|
};
|
||||||
|
|
||||||
|
const commitImplementMain = {
|
||||||
|
revision: "5203292ab2bc0c020dd22adc4d3897da4930e43f",
|
||||||
|
author: {
|
||||||
|
name: "Ford Prefect",
|
||||||
|
mail: "ford.prefect@hitchhiker.com"
|
||||||
|
},
|
||||||
|
description: "implemented main function",
|
||||||
|
when: new Date("2020-04-12T16:29:42Z")
|
||||||
|
};
|
||||||
|
|
||||||
|
const source: AnnotatedSource = {
|
||||||
|
language: "go",
|
||||||
|
lines: [
|
||||||
|
{
|
||||||
|
lineNumber: 1,
|
||||||
|
code: "package main",
|
||||||
|
...commitCreateNewApp
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineNumber: 2,
|
||||||
|
code: "",
|
||||||
|
...commitCreateNewApp
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineNumber: 3,
|
||||||
|
code: 'import "fmt"',
|
||||||
|
...commitFixedMissingImport
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineNumber: 4,
|
||||||
|
code: "",
|
||||||
|
...commitFixedMissingImport
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineNumber: 5,
|
||||||
|
code: "func main() {",
|
||||||
|
...commitCreateNewApp
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineNumber: 6,
|
||||||
|
code: ' fmt.Println("Hello World")',
|
||||||
|
...commitImplementMain
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineNumber: 7,
|
||||||
|
code: "}",
|
||||||
|
...commitCreateNewApp
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lineNumber: 8,
|
||||||
|
code: "",
|
||||||
|
...commitCreateNewApp
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const Robohash: FC = ({ children }) => {
|
||||||
|
const binder = new Binder("robohash");
|
||||||
|
binder.bind("avatar.factory", (person: Person) => `https://robohash.org/${person.mail}.png`);
|
||||||
|
return <BinderContext.Provider value={binder}>{children}</BinderContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
storiesOf("Annotate", module)
|
||||||
|
.addDecorator(storyFn => <MemoryRouter initialEntries={["/"]}>{storyFn()}</MemoryRouter>)
|
||||||
|
.addDecorator(storyFn => <Wrapper className="box">{storyFn()}</Wrapper>)
|
||||||
|
.add("Default", () => (
|
||||||
|
<Annotate source={source} repository={repository} baseDate={new Date("2020-04-16T09:22:42Z")} />
|
||||||
|
))
|
||||||
|
.add("With Avatars", () => (
|
||||||
|
<Robohash>
|
||||||
|
<Annotate source={source} repository={repository} baseDate={new Date("2020-04-15T09:47:42Z")} />
|
||||||
|
</Robohash>
|
||||||
|
));
|
||||||
157
scm-ui/ui-components/src/repos/annotate/Annotate.tsx
Normal file
157
scm-ui/ui-components/src/repos/annotate/Annotate.tsx
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { FC, useReducer } from "react";
|
||||||
|
import { Repository, AnnotatedSource, AnnotatedLine } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
import { LightAsync as ReactSyntaxHighlighter, createElement } from "react-syntax-highlighter";
|
||||||
|
import { arduinoLight } from "react-syntax-highlighter/dist/cjs/styles/hljs";
|
||||||
|
import { DateInput } from "../../useDateFormatter";
|
||||||
|
import Popover from "./Popover";
|
||||||
|
import AnnotateLine from "./AnnotateLine";
|
||||||
|
import { Action } from "./actions";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
source: AnnotatedSource;
|
||||||
|
repository: Repository;
|
||||||
|
baseDate?: DateInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
annotation?: AnnotatedLine;
|
||||||
|
offset?: number;
|
||||||
|
line?: number;
|
||||||
|
onPopover: boolean;
|
||||||
|
onLine: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
onPopover: false,
|
||||||
|
onLine: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const reducer = (state: State, action: Action): State => {
|
||||||
|
switch (action.type) {
|
||||||
|
case "enter-line": {
|
||||||
|
if (state.onPopover) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
annotation: action.annotation,
|
||||||
|
offset: action.offset,
|
||||||
|
line: action.line,
|
||||||
|
onLine: true,
|
||||||
|
onPopover: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case "leave-line": {
|
||||||
|
if (state.onPopover) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
onLine: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return initialState;
|
||||||
|
}
|
||||||
|
case "enter-popover": {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
onPopover: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case "leave-popover": {
|
||||||
|
if (state.onLine) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
onPopover: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return initialState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Annotate: FC<Props> = ({ source, repository, baseDate }) => {
|
||||||
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
|
||||||
|
const defaultRenderer = ({ rows, stylesheet, useInlineStyles }: any) => {
|
||||||
|
let lastRevision = "";
|
||||||
|
return rows.map((node: React.ReactNode, i: number) => {
|
||||||
|
const line = createElement({
|
||||||
|
node,
|
||||||
|
stylesheet,
|
||||||
|
useInlineStyles,
|
||||||
|
key: `code-segment${i}`
|
||||||
|
});
|
||||||
|
|
||||||
|
if (i + 1 < rows.length) {
|
||||||
|
const annotation = source.lines[i];
|
||||||
|
const newAnnotation = annotation.revision !== lastRevision;
|
||||||
|
lastRevision = annotation.revision;
|
||||||
|
return (
|
||||||
|
<AnnotateLine dispatch={dispatch} annotation={annotation} showAnnotation={newAnnotation} nr={i + 1}>
|
||||||
|
{line}
|
||||||
|
</AnnotateLine>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let popover = null;
|
||||||
|
if ((state.onPopover || state.onLine) && state.annotation) {
|
||||||
|
popover = (
|
||||||
|
<Popover
|
||||||
|
annotation={state.annotation}
|
||||||
|
dispatch={dispatch}
|
||||||
|
offsetTop={state.offset}
|
||||||
|
repository={repository}
|
||||||
|
baseDate={baseDate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = source.lines.reduce((content, line) => {
|
||||||
|
content += line.code + "\n";
|
||||||
|
return content;
|
||||||
|
}, "");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ position: "relative" }}>
|
||||||
|
{popover}
|
||||||
|
<ReactSyntaxHighlighter
|
||||||
|
showLineNumbers={false}
|
||||||
|
language={source.language ? source.language : "text"}
|
||||||
|
style={arduinoLight}
|
||||||
|
renderer={defaultRenderer}
|
||||||
|
>
|
||||||
|
{code}
|
||||||
|
</ReactSyntaxHighlighter>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Annotate;
|
||||||
145
scm-ui/ui-components/src/repos/annotate/AnnotateLine.tsx
Normal file
145
scm-ui/ui-components/src/repos/annotate/AnnotateLine.tsx
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
import React, { FC, Dispatch, useRef } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import AuthorImage from "./AuthorImage";
|
||||||
|
import DateShort from "../../DateShort";
|
||||||
|
import { Action } from "./actions";
|
||||||
|
import { AnnotatedLine } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
const LineElement = styled.div`
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
vertical-align: top;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Author = styled(LineElement)`
|
||||||
|
width: 8em;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const When = styled(LineElement)`
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
width: 6.5em;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
margin: 0 0.5em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LineNumber = styled(LineElement)`
|
||||||
|
width: 3em;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
border-left: 1px solid lightgrey;
|
||||||
|
border-right: 1px solid lightgrey;
|
||||||
|
|
||||||
|
text-align: right;
|
||||||
|
|
||||||
|
padding: 0 0.5em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Line = styled.div`
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 1.5em;
|
||||||
|
vertical-align: top;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Metadata = styled(LineElement)`
|
||||||
|
cursor: help;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const EmptyMetadata = styled(LineElement)`
|
||||||
|
width: 16.7em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const dispatchDeferred = (dispatch: Dispatch<Action>, action: Action) => {
|
||||||
|
setTimeout(() => dispatch(action), 250);
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
annotation: AnnotatedLine;
|
||||||
|
showAnnotation: boolean;
|
||||||
|
nr: number;
|
||||||
|
dispatch: Dispatch<Action>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AnnotateLine: FC<Props> = ({ annotation, showAnnotation, dispatch, nr, children }) => {
|
||||||
|
const link = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const onMouseEnter = () => {
|
||||||
|
if (showAnnotation) {
|
||||||
|
dispatchDeferred(dispatch, {
|
||||||
|
annotation,
|
||||||
|
line: nr,
|
||||||
|
offset: link.current!.offsetTop,
|
||||||
|
type: "enter-line"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const OnMouseLeave = () => {
|
||||||
|
if (showAnnotation) {
|
||||||
|
dispatchDeferred(dispatch, {
|
||||||
|
line: nr,
|
||||||
|
type: "leave-line"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!showAnnotation) {
|
||||||
|
return (
|
||||||
|
<Line>
|
||||||
|
<EmptyMetadata />
|
||||||
|
<LineNumber>{nr}</LineNumber> <LineElement>{children}</LineElement>
|
||||||
|
</Line>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Line>
|
||||||
|
<Metadata className="has-text-info" onMouseOver={onMouseEnter} onMouseOut={OnMouseLeave} ref={link}>
|
||||||
|
<Author>
|
||||||
|
<AuthorImage person={annotation.author} />
|
||||||
|
{annotation.author.name}
|
||||||
|
</Author>{" "}
|
||||||
|
<When>
|
||||||
|
<DateShort date={annotation.when} />
|
||||||
|
</When>{" "}
|
||||||
|
</Metadata>
|
||||||
|
<LineNumber>{nr}</LineNumber> <LineElement>{children}</LineElement>
|
||||||
|
</Line>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AnnotateLine;
|
||||||
36
scm-ui/ui-components/src/repos/annotate/AuthorImage.tsx
Normal file
36
scm-ui/ui-components/src/repos/annotate/AuthorImage.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AvatarImage } from "../../avatar";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const AuthorImage = styled(AvatarImage)`
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
margin-right: 0.2em;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
vertical-align: middle;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default AuthorImage;
|
||||||
142
scm-ui/ui-components/src/repos/annotate/Popover.tsx
Normal file
142
scm-ui/ui-components/src/repos/annotate/Popover.tsx
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { FC, useState, useRef, useLayoutEffect, Dispatch } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import DateFromNow from "../../DateFromNow";
|
||||||
|
import { SingleContributor } from "../changesets";
|
||||||
|
import { DateInput } from "../../useDateFormatter";
|
||||||
|
import { Repository, AnnotatedLine } from "@scm-manager/ui-types";
|
||||||
|
import AuthorImage from "./AuthorImage";
|
||||||
|
import { Action } from "./actions";
|
||||||
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
|
const PopoverContainer = styled.div`
|
||||||
|
position: absolute;
|
||||||
|
left: 2.25em;
|
||||||
|
z-index: 100;
|
||||||
|
width: 30em;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
border-style: solid;
|
||||||
|
pointer-events: none;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
top: 100%;
|
||||||
|
left: 5.5em;
|
||||||
|
border-color: transparent;
|
||||||
|
border-bottom-color: white;
|
||||||
|
border-left-color: white;
|
||||||
|
border-width: 0.4rem;
|
||||||
|
margin-left: -0.4rem;
|
||||||
|
margin-top: -0.4rem;
|
||||||
|
-webkit-transform-origin: center;
|
||||||
|
transform-origin: center;
|
||||||
|
box-shadow: -1px 1px 2px rgba(10, 10, 10, 0.2);
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SmallHr = styled.hr`
|
||||||
|
margin: 0.5em 0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const PopoverHeading = styled.div`
|
||||||
|
height: 1.5em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const PopoverDescription = styled.p`
|
||||||
|
margin-top: 0.5em;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const shortRevision = (revision: string) => {
|
||||||
|
if (revision.length > 7) {
|
||||||
|
return revision.substring(0, 7);
|
||||||
|
}
|
||||||
|
return revision;
|
||||||
|
};
|
||||||
|
|
||||||
|
type PopoverProps = {
|
||||||
|
annotation: AnnotatedLine;
|
||||||
|
offsetTop?: number;
|
||||||
|
repository: Repository;
|
||||||
|
baseDate?: DateInput;
|
||||||
|
dispatch: Dispatch<Action>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Popover: FC<PopoverProps> = ({ annotation, offsetTop, repository, baseDate, dispatch }) => {
|
||||||
|
const [t] = useTranslation("repos");
|
||||||
|
const [height, setHeight] = useState(125);
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
setHeight(ref.current.clientHeight);
|
||||||
|
}
|
||||||
|
}, [ref]);
|
||||||
|
|
||||||
|
const onMouseEnter = () => {
|
||||||
|
dispatch({
|
||||||
|
type: "enter-popover"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const OnMouseLeave = () => {
|
||||||
|
dispatch({
|
||||||
|
type: "leave-popover"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const top = (offsetTop || 0) - height - 5;
|
||||||
|
return (
|
||||||
|
<PopoverContainer
|
||||||
|
ref={ref}
|
||||||
|
onMouseEnter={onMouseEnter}
|
||||||
|
onMouseLeave={OnMouseLeave}
|
||||||
|
className="box"
|
||||||
|
style={{ top: `${top}px` }}
|
||||||
|
>
|
||||||
|
<PopoverHeading className="is-clearfix">
|
||||||
|
<span className="is-pulled-left">
|
||||||
|
<AuthorImage person={annotation.author} />
|
||||||
|
<SingleContributor person={annotation.author} displayTextOnly={true} />
|
||||||
|
</span>
|
||||||
|
<DateFromNow className="is-pulled-right" date={annotation.when} baseDate={baseDate} />
|
||||||
|
</PopoverHeading>
|
||||||
|
<SmallHr />
|
||||||
|
<p>
|
||||||
|
{t("changeset.label") + " "}
|
||||||
|
<Link to={`/repo/${repository.namespace}/${repository.name}/code/changeset/${annotation.revision}`}>
|
||||||
|
{shortRevision(annotation.revision)}
|
||||||
|
</Link>
|
||||||
|
</p>
|
||||||
|
<PopoverDescription className="content">{annotation.description}</PopoverDescription>
|
||||||
|
</PopoverContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Popover;
|
||||||
47
scm-ui/ui-components/src/repos/annotate/actions.ts
Normal file
47
scm-ui/ui-components/src/repos/annotate/actions.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { AnnotatedLine } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
|
type EnterLine = {
|
||||||
|
annotation: AnnotatedLine;
|
||||||
|
offset: number;
|
||||||
|
line: number;
|
||||||
|
type: "enter-line";
|
||||||
|
};
|
||||||
|
|
||||||
|
type LeaveLine = {
|
||||||
|
line: number;
|
||||||
|
type: "leave-line";
|
||||||
|
};
|
||||||
|
|
||||||
|
type EnterPopover = {
|
||||||
|
type: "enter-popover";
|
||||||
|
};
|
||||||
|
|
||||||
|
type LeavePopover = {
|
||||||
|
type: "leave-popover";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Action = EnterLine | LeaveLine | EnterPopover | LeavePopover;
|
||||||
25
scm-ui/ui-components/src/repos/annotate/index.ts
Normal file
25
scm-ui/ui-components/src/repos/annotate/index.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { default as Annotate } from "./Annotate";
|
||||||
@@ -36,6 +36,7 @@ type Props = {
|
|||||||
|
|
||||||
type PersonProps = {
|
type PersonProps = {
|
||||||
person: Person;
|
person: Person;
|
||||||
|
className?: string;
|
||||||
displayTextOnly?: boolean;
|
displayTextOnly?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ const ContributorWithAvatar: FC<PersonAvatarProps> = ({ person, avatar }) => {
|
|||||||
return <ContributorAvatar src={avatar} alt={person.name} title={person.name} />;
|
return <ContributorAvatar src={avatar} alt={person.name} title={person.name} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SingleContributor: FC<PersonProps> = ({ person, displayTextOnly }) => {
|
export const SingleContributor: FC<PersonProps> = ({ person, className, displayTextOnly }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
const avatar = useAvatar(person);
|
const avatar = useAvatar(person);
|
||||||
if (!displayTextOnly && avatar) {
|
if (!displayTextOnly && avatar) {
|
||||||
@@ -78,12 +79,16 @@ const SingleContributor: FC<PersonProps> = ({ person, displayTextOnly }) => {
|
|||||||
}
|
}
|
||||||
if (person.mail) {
|
if (person.mail) {
|
||||||
return (
|
return (
|
||||||
<a href={"mailto:" + person.mail} title={t("changeset.contributors.mailto") + " " + person.mail}>
|
<a
|
||||||
|
className={className}
|
||||||
|
href={"mailto:" + person.mail}
|
||||||
|
title={t("changeset.contributors.mailto") + " " + person.mail}
|
||||||
|
>
|
||||||
{person.name}
|
{person.name}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <>{person.name}</>;
|
return <span className={className}>{person.name}</span>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type PersonsProps = {
|
type PersonsProps = {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
import * as changesets from "./changesets";
|
import * as changesets from "./changesets";
|
||||||
export { changesets };
|
export { changesets };
|
||||||
|
|
||||||
export { default as ChangesetAuthor } from "./ChangesetAuthor";
|
export { default as ChangesetAuthor, SingleContributor } from "./ChangesetAuthor";
|
||||||
export { default as ChangesetButtonGroup } from "./ChangesetButtonGroup";
|
export { default as ChangesetButtonGroup } from "./ChangesetButtonGroup";
|
||||||
export { default as ChangesetDiff } from "./ChangesetDiff";
|
export { default as ChangesetDiff } from "./ChangesetDiff";
|
||||||
export { default as ChangesetId } from "./ChangesetId";
|
export { default as ChangesetId } from "./ChangesetId";
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {
|
|||||||
|
|
||||||
export { diffs };
|
export { diffs };
|
||||||
|
|
||||||
|
export * from "./annotate";
|
||||||
export * from "./changesets";
|
export * from "./changesets";
|
||||||
|
|
||||||
export { default as Diff } from "./Diff";
|
export { default as Diff } from "./Diff";
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { chooseLocale, supportedLocales } from "./DateFromNow";
|
import { chooseLocale, supportedLocales } from "./useDateFormatter";
|
||||||
|
|
||||||
describe("test choose locale", () => {
|
describe("test choose locale", () => {
|
||||||
it("should choose de", () => {
|
it("should choose de", () => {
|
||||||
126
scm-ui/ui-components/src/useDateFormatter.ts
Normal file
126
scm-ui/ui-components/src/useDateFormatter.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { enUS, de, es } from "date-fns/locale";
|
||||||
|
import { formatDistance, format, Locale, parseISO } from "date-fns";
|
||||||
|
|
||||||
|
type LocaleMap = {
|
||||||
|
[key: string]: Locale;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const supportedLocales: LocaleMap = {
|
||||||
|
enUS,
|
||||||
|
en: enUS,
|
||||||
|
de,
|
||||||
|
es
|
||||||
|
};
|
||||||
|
|
||||||
|
type Options = {
|
||||||
|
addSuffix: boolean;
|
||||||
|
locale: Locale;
|
||||||
|
timeZone?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const chooseLocale = (language: string, languages?: string[]) => {
|
||||||
|
for (const lng of languages || []) {
|
||||||
|
const locale = supportedLocales[lng];
|
||||||
|
if (locale) {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const locale = supportedLocales[language];
|
||||||
|
if (locale) {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
return enUS;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DateInput = Date | string;
|
||||||
|
|
||||||
|
export type DateProps = {
|
||||||
|
date?: DateInput;
|
||||||
|
timeZone?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* baseDate is the date from which the distance is calculated,
|
||||||
|
* default is the current time (new Date()). This property
|
||||||
|
* is required to keep snapshots tests green over the time on
|
||||||
|
* ci server.
|
||||||
|
*/
|
||||||
|
baseDate?: DateInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createOptions = (locale: Locale, timeZone?: string) => {
|
||||||
|
const options: Options = {
|
||||||
|
addSuffix: true,
|
||||||
|
locale
|
||||||
|
};
|
||||||
|
if (timeZone) {
|
||||||
|
options.timeZone = timeZone;
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createBaseDate = (baseDate?: DateInput) => {
|
||||||
|
if (baseDate) {
|
||||||
|
return toDate(baseDate);
|
||||||
|
}
|
||||||
|
return new Date();
|
||||||
|
};
|
||||||
|
|
||||||
|
const toDate = (value: DateInput): Date => {
|
||||||
|
if (value instanceof Date) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return parseISO(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useDateFormatter = ({ date, baseDate, timeZone }: DateProps) => {
|
||||||
|
const { i18n } = useTranslation();
|
||||||
|
if (!date) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isoDate = toDate(date);
|
||||||
|
const base = createBaseDate(baseDate);
|
||||||
|
|
||||||
|
const locale = chooseLocale(i18n.language, i18n.languages);
|
||||||
|
const options = createOptions(locale, timeZone);
|
||||||
|
return {
|
||||||
|
formatShort() {
|
||||||
|
return format(isoDate, "yyyy-MM-dd", options);
|
||||||
|
},
|
||||||
|
formatFull() {
|
||||||
|
return format(isoDate, "yyyy-MM-dd HH:mm:ss", options);
|
||||||
|
},
|
||||||
|
formatDistance() {
|
||||||
|
return formatDistance(isoDate, base, options);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useDateFormatter;
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
"react-redux": "^5.0.7",
|
"react-redux": "^5.0.7",
|
||||||
"react-router-dom": "^5.1.2",
|
"react-router-dom": "^5.1.2",
|
||||||
"redux": "^4.0.0",
|
"redux": "^4.0.0",
|
||||||
"styled-components": "^4.4.0"
|
"styled-components": "^5.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@scm-manager/babel-preset": "^2.0.0",
|
"@scm-manager/babel-preset": "^2.0.0",
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
"@types/react": "^16.9.9",
|
"@types/react": "^16.9.9",
|
||||||
"@types/react-redux": "5.0.7",
|
"@types/react-redux": "5.0.7",
|
||||||
"@types/react-router-dom": "^5.1.0",
|
"@types/react-router-dom": "^5.1.0",
|
||||||
"@types/styled-components": "^4.1.19",
|
"@types/styled-components": "^5.1.0",
|
||||||
"jest": "^24.9.0"
|
"jest": "^24.9.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
39
scm-ui/ui-types/src/Annotate.ts
Normal file
39
scm-ui/ui-types/src/Annotate.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Person } from "./Person";
|
||||||
|
|
||||||
|
export type AnnotatedSource = {
|
||||||
|
lines: AnnotatedLine[];
|
||||||
|
language?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AnnotatedLine = {
|
||||||
|
author: Person;
|
||||||
|
code: string;
|
||||||
|
description: string;
|
||||||
|
lineNumber: number;
|
||||||
|
revision: string;
|
||||||
|
when: Date;
|
||||||
|
};
|
||||||
@@ -25,11 +25,7 @@
|
|||||||
import { Collection, Links } from "./hal";
|
import { Collection, Links } from "./hal";
|
||||||
import { Tag } from "./Tags";
|
import { Tag } from "./Tags";
|
||||||
import { Branch } from "./Branches";
|
import { Branch } from "./Branches";
|
||||||
|
import { Person } from "./Person";
|
||||||
export type Person = {
|
|
||||||
name: string;
|
|
||||||
mail?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Changeset = Collection & {
|
export type Changeset = Collection & {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
28
scm-ui/ui-types/src/Person.ts
Normal file
28
scm-ui/ui-types/src/Person.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type Person = {
|
||||||
|
name: string;
|
||||||
|
mail?: string;
|
||||||
|
};
|
||||||
@@ -34,7 +34,11 @@ export { RepositoryType, RepositoryTypeCollection } from "./RepositoryTypes";
|
|||||||
|
|
||||||
export { Branch, BranchRequest } from "./Branches";
|
export { Branch, BranchRequest } from "./Branches";
|
||||||
|
|
||||||
export { Changeset, Person, Contributor, ParentChangeset } from "./Changesets";
|
export { Person } from "./Person";
|
||||||
|
|
||||||
|
export { Changeset, Contributor, ParentChangeset } from "./Changesets";
|
||||||
|
|
||||||
|
export { AnnotatedSource, AnnotatedLine } from "./Annotate";
|
||||||
|
|
||||||
export { Tag } from "./Tags";
|
export { Tag } from "./Tags";
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
"redux-devtools-extension": "^2.13.5",
|
"redux-devtools-extension": "^2.13.5",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"styled-components": "^4.4.0",
|
"styled-components": "^5.1.0",
|
||||||
"systemjs": "0.21.6"
|
"systemjs": "0.21.6"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"@types/react-dom": "^16.9.2",
|
"@types/react-dom": "^16.9.2",
|
||||||
"@types/react-redux": "5.0.7",
|
"@types/react-redux": "5.0.7",
|
||||||
"@types/react-router-dom": "^5.1.0",
|
"@types/react-router-dom": "^5.1.0",
|
||||||
"@types/styled-components": "^4.1.19",
|
"@types/styled-components": "^5.1.0",
|
||||||
"@types/systemjs": "^0.20.6",
|
"@types/systemjs": "^0.20.6",
|
||||||
"fetch-mock": "^7.5.1",
|
"fetch-mock": "^7.5.1",
|
||||||
"react-test-renderer": "^16.10.2",
|
"react-test-renderer": "^16.10.2",
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
"collapseDiffs": "Auf-/Zuklappen"
|
"collapseDiffs": "Auf-/Zuklappen"
|
||||||
},
|
},
|
||||||
"changeset": {
|
"changeset": {
|
||||||
|
"label": "Changeset",
|
||||||
"description": "Beschreibung",
|
"description": "Beschreibung",
|
||||||
"summary": "Changeset <0/> wurde <1/> committet",
|
"summary": "Changeset <0/> wurde <1/> committet",
|
||||||
"shortSummary": "Committet <0/> <1/>",
|
"shortSummary": "Committet <0/> <1/>",
|
||||||
|
|||||||
@@ -82,6 +82,7 @@
|
|||||||
"collapseDiffs": "Collapse"
|
"collapseDiffs": "Collapse"
|
||||||
},
|
},
|
||||||
"changeset": {
|
"changeset": {
|
||||||
|
"label": "Changeset",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
"summary": "Changeset <0/> was committed <1/>",
|
"summary": "Changeset <0/> was committed <1/>",
|
||||||
"shortSummary": "Committed <0/> <1/>",
|
"shortSummary": "Committed <0/> <1/>",
|
||||||
|
|||||||
@@ -24,20 +24,27 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import { Button, ButtonAddons } from "@scm-manager/ui-components";
|
import { Button, ButtonAddons } from "@scm-manager/ui-components";
|
||||||
|
import { SourceViewSelection } from "../../containers/Content";
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
className?: string;
|
className?: string;
|
||||||
historyIsSelected: boolean;
|
selected: SourceViewSelection;
|
||||||
showHistory: (p: boolean) => void;
|
showSources: () => void;
|
||||||
|
showHistory: () => void;
|
||||||
|
showAnnotations: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileButtonAddons extends React.Component<Props> {
|
class FileButtonAddons extends React.Component<Props> {
|
||||||
showHistory = () => {
|
showHistory = () => {
|
||||||
this.props.showHistory(true);
|
this.props.showHistory();
|
||||||
};
|
};
|
||||||
|
|
||||||
showSources = () => {
|
showSources = () => {
|
||||||
this.props.showHistory(false);
|
this.props.showSources();
|
||||||
|
};
|
||||||
|
|
||||||
|
showAnnotations = () => {
|
||||||
|
this.props.showAnnotations();
|
||||||
};
|
};
|
||||||
|
|
||||||
color = (selected: boolean) => {
|
color = (selected: boolean) => {
|
||||||
@@ -45,19 +52,26 @@ class FileButtonAddons extends React.Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { className, t, historyIsSelected } = this.props;
|
const { className, t, selected, showSources, showHistory, showAnnotations } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonAddons className={className}>
|
<ButtonAddons className={className}>
|
||||||
<div title={t("sources.content.sourcesButton")}>
|
<div title={t("sources.content.sourcesButton")}>
|
||||||
<Button action={this.showSources} color={this.color(!historyIsSelected)}>
|
<Button action={showSources} color={this.color(selected === "source")}>
|
||||||
<span className="icon">
|
<span className="icon">
|
||||||
<i className="fas fa-code" />
|
<i className="fas fa-code" />
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<div title={t("sources.content.annotateButton")}>
|
||||||
|
<Button action={showAnnotations} color={this.color(selected === "annotations")}>
|
||||||
|
<span className="icon">
|
||||||
|
<i className="fas fa-user-clock" />
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
<div title={t("sources.content.historyButton")}>
|
<div title={t("sources.content.historyButton")}>
|
||||||
<Button action={this.showHistory} color={this.color(historyIsSelected)}>
|
<Button action={showHistory} color={this.color(selected === "history")}>
|
||||||
<span className="icon">
|
<span className="icon">
|
||||||
<i className="fas fa-history" />
|
<i className="fas fa-history" />
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { FC, useEffect, useState } from "react";
|
||||||
|
import { Link, Repository, File, AnnotatedSource } from "@scm-manager/ui-types";
|
||||||
|
import { Annotate, apiClient, ErrorNotification, Loading } from "@scm-manager/ui-components";
|
||||||
|
import { getContentType } from "./contentType";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
file: File;
|
||||||
|
repository: Repository;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AnnotateView: FC<Props> = ({ file, repository }) => {
|
||||||
|
const [annotation, setAnnotation] = useState<AnnotatedSource | undefined>(undefined);
|
||||||
|
const [language, setLanguage] = useState<string | undefined>(undefined);
|
||||||
|
const [error, setError] = useState<Error | undefined>(undefined);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const languagePromise = getContentType((file._links.self as Link).href).then(result =>
|
||||||
|
setLanguage(result.language)
|
||||||
|
);
|
||||||
|
|
||||||
|
const apiClientPromise = apiClient
|
||||||
|
.get((file._links.annotate as Link).href)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(setAnnotation);
|
||||||
|
|
||||||
|
Promise.all([languagePromise, apiClientPromise])
|
||||||
|
.then(() => setLoading(false))
|
||||||
|
.catch(setError);
|
||||||
|
}, [file]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return <ErrorNotification error={error} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!annotation || loading) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Annotate source={{ ...annotation, language }} repository={repository} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AnnotateView;
|
||||||
@@ -33,6 +33,7 @@ import { getSources } from "../modules/sources";
|
|||||||
import FileButtonAddons from "../components/content/FileButtonAddons";
|
import FileButtonAddons from "../components/content/FileButtonAddons";
|
||||||
import SourcesView from "./SourcesView";
|
import SourcesView from "./SourcesView";
|
||||||
import HistoryView from "./HistoryView";
|
import HistoryView from "./HistoryView";
|
||||||
|
import AnnotateView from "./AnnotateView";
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -45,7 +46,7 @@ type Props = WithTranslation & {
|
|||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
showHistory: boolean;
|
selected: SourceViewSelection;
|
||||||
errorFromExtension?: Error;
|
errorFromExtension?: Error;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -81,13 +82,15 @@ const LighterGreyBackgroundTable = styled.table`
|
|||||||
background-color: #fbfbfb;
|
background-color: #fbfbfb;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export type SourceViewSelection = "source" | "history" | "annotations";
|
||||||
|
|
||||||
class Content extends React.Component<Props, State> {
|
class Content extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
collapsed: true,
|
collapsed: true,
|
||||||
showHistory: false
|
selected: "source"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,13 +100,6 @@ class Content extends React.Component<Props, State> {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
setShowHistoryState(showHistory: boolean) {
|
|
||||||
this.setState({
|
|
||||||
...this.state,
|
|
||||||
showHistory
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleExtensionError = (error: Error) => {
|
handleExtensionError = (error: Error) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
errorFromExtension: error
|
errorFromExtension: error
|
||||||
@@ -112,14 +108,15 @@ class Content extends React.Component<Props, State> {
|
|||||||
|
|
||||||
showHeader() {
|
showHeader() {
|
||||||
const { repository, file, revision } = this.props;
|
const { repository, file, revision } = this.props;
|
||||||
const { showHistory, collapsed } = this.state;
|
const { selected, collapsed } = this.state;
|
||||||
const icon = collapsed ? "angle-right" : "angle-down";
|
const icon = collapsed ? "angle-right" : "angle-down";
|
||||||
|
|
||||||
const selector = file._links.history ? (
|
const selector = file._links.history ? (
|
||||||
<RightMarginFileButtonAddons
|
<RightMarginFileButtonAddons
|
||||||
file={file}
|
selected={selected}
|
||||||
historyIsSelected={showHistory}
|
showSources={() => this.setState({ selected: "source" })}
|
||||||
showHistory={(changeShowHistory: boolean) => this.setShowHistoryState(changeShowHistory)}
|
showHistory={() => this.setState({ selected: "history" })}
|
||||||
|
showAnnotations={() => this.setState({ selected: "annotations" })}
|
||||||
/>
|
/>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
@@ -212,15 +209,26 @@ class Content extends React.Component<Props, State> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { file, revision, repository, path, breadcrumb } = this.props;
|
const { file, revision, repository, path, breadcrumb } = this.props;
|
||||||
const { showHistory, errorFromExtension } = this.state;
|
const { selected, errorFromExtension } = this.state;
|
||||||
|
|
||||||
const header = this.showHeader();
|
const header = this.showHeader();
|
||||||
const content =
|
let content;
|
||||||
showHistory && file._links.history ? (
|
switch (selected) {
|
||||||
<HistoryView file={file} repository={repository} />
|
case "source":
|
||||||
) : (
|
content = (
|
||||||
<SourcesView revision={revision} file={file} repository={repository} path={path} />
|
<SourcesView revision={revision} file={file} repository={repository} path={path}/>
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
|
case "history":
|
||||||
|
content = (
|
||||||
|
<HistoryView file={file} repository={repository}/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "annotations":
|
||||||
|
content = (
|
||||||
|
<AnnotateView file={file} repository={repository} />
|
||||||
|
);
|
||||||
|
}
|
||||||
const moreInformation = this.showMoreInformation();
|
const moreInformation = this.showMoreInformation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -24,18 +24,18 @@
|
|||||||
|
|
||||||
import { apiClient } from "@scm-manager/ui-components";
|
import { apiClient } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
export function getContentType(url: string) {
|
export type ContentType = {
|
||||||
|
type : string;
|
||||||
|
language?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getContentType(url: string) : Promise<ContentType> {
|
||||||
return apiClient
|
return apiClient
|
||||||
.head(url)
|
.head(url)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
return {
|
return {
|
||||||
type: response.headers.get("Content-Type"),
|
type: response.headers.get("Content-Type") || "application/octet-stream",
|
||||||
language: response.headers.get("X-Programming-Language")
|
language: response.headers.get("X-Programming-Language") || undefined
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.catch(err => {
|
|
||||||
return {
|
|
||||||
error: err
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
|
import sonia.scm.repository.api.RepositoryService;
|
||||||
|
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||||
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class AnnotateResource {
|
||||||
|
|
||||||
|
private final RepositoryServiceFactory serviceFactory;
|
||||||
|
private final BlameResultToBlameDtoMapper mapper;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AnnotateResource(RepositoryServiceFactory serviceFactory, BlameResultToBlameDtoMapper mapper) {
|
||||||
|
this.serviceFactory = serviceFactory;
|
||||||
|
this.mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content of a file with additional information for each line regarding the last commit that
|
||||||
|
* changed this line: The revision, the author, the date, and the description of the commit.
|
||||||
|
*
|
||||||
|
* @param namespace the namespace of the repository
|
||||||
|
* @param name the name of the repository
|
||||||
|
* @param revision the revision
|
||||||
|
* @param path The path of the file
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("{revision}/{path: .*}")
|
||||||
|
@Produces(VndMediaType.ANNOTATE)
|
||||||
|
@Operation(summary = "File content by revision", description = "Returns the annotated file for the given revision in the repository.", tags = "Repository")
|
||||||
|
@ApiResponse(responseCode = "200", description = "success")
|
||||||
|
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||||
|
@ApiResponse(responseCode = "403", description = "not authorized, the current user has no privileges to read the repository")
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "404",
|
||||||
|
description = "not found, no repository with the specified name available in the namespace",
|
||||||
|
content = @Content(
|
||||||
|
mediaType = VndMediaType.ERROR_TYPE,
|
||||||
|
schema = @Schema(implementation = ErrorDto.class)
|
||||||
|
))
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "500",
|
||||||
|
description = "internal server error",
|
||||||
|
content = @Content(
|
||||||
|
mediaType = VndMediaType.ERROR_TYPE,
|
||||||
|
schema = @Schema(implementation = ErrorDto.class)
|
||||||
|
))
|
||||||
|
public BlameDto annotate(
|
||||||
|
@PathParam("namespace") String namespace,
|
||||||
|
@PathParam("name") String name,
|
||||||
|
@PathParam("revision") String revision,
|
||||||
|
@PathParam("path") String path
|
||||||
|
) throws IOException {
|
||||||
|
NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name);
|
||||||
|
try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) {
|
||||||
|
return mapper.map(repositoryService.getBlameCommand().setRevision(revision).getBlameResult(path), namespaceAndName, revision, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
@@ -63,6 +63,7 @@ abstract class BaseFileObjectDtoMapper extends HalAppenderMapper implements Inst
|
|||||||
} else {
|
} else {
|
||||||
links.self(resourceLinks.source().content(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path));
|
links.self(resourceLinks.source().content(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path));
|
||||||
links.single(link("history", resourceLinks.fileHistory().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path)));
|
links.single(link("history", resourceLinks.fileHistory().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path)));
|
||||||
|
links.single(link("annotate", resourceLinks.annotate().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path)));
|
||||||
}
|
}
|
||||||
if (fileObject.isTruncated()) {
|
if (fileObject.isTruncated()) {
|
||||||
links.single(link("proceed", resourceLinks.source().content(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path) + "?offset=" + (offset + BrowseCommandRequest.DEFAULT_REQUEST_LIMIT)));
|
links.single(link("proceed", resourceLinks.source().content(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path) + "?offset=" + (offset + BrowseCommandRequest.DEFAULT_REQUEST_LIMIT)));
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
import de.otto.edison.hal.Links;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BlameDto extends HalRepresentation {
|
||||||
|
|
||||||
|
private List<BlameLineDto> lines;
|
||||||
|
|
||||||
|
public BlameDto(Links links) {
|
||||||
|
super(links);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BlameLineDto {
|
||||||
|
|
||||||
|
private PersonDto author;
|
||||||
|
private String code;
|
||||||
|
private String description;
|
||||||
|
private int lineNumber;
|
||||||
|
private String revision;
|
||||||
|
private Instant when;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import de.otto.edison.hal.Links;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.ObjectFactory;
|
||||||
|
import sonia.scm.repository.BlameLine;
|
||||||
|
import sonia.scm.repository.BlameResult;
|
||||||
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
|
import sonia.scm.repository.Person;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public abstract class BlameResultToBlameDtoMapper implements InstantAttributeMapper {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ResourceLinks resourceLinks;
|
||||||
|
|
||||||
|
BlameDto map(BlameResult result, NamespaceAndName namespaceAndName, String revision, String path) {
|
||||||
|
BlameDto dto = createDto(namespaceAndName, revision, path);
|
||||||
|
dto.setLines(result.getBlameLines().stream().map(this::map).collect(Collectors.toList()));
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract BlameLineDto map(BlameLine line);
|
||||||
|
|
||||||
|
abstract PersonDto map(Person person);
|
||||||
|
|
||||||
|
@ObjectFactory
|
||||||
|
BlameDto createDto(NamespaceAndName namespaceAndName, String revision, String path) {
|
||||||
|
return new BlameDto(Links.linkingTo()
|
||||||
|
.self(
|
||||||
|
resourceLinks.annotate()
|
||||||
|
.self(
|
||||||
|
namespaceAndName.getNamespace(),
|
||||||
|
namespaceAndName.getName(),
|
||||||
|
revision,
|
||||||
|
path))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void setResourceLinks(ResourceLinks resourceLinks) {
|
||||||
|
this.resourceLinks = resourceLinks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
@@ -32,46 +32,48 @@ import sonia.scm.web.api.RepositoryToHalMapper;
|
|||||||
public class MapperModule extends AbstractModule {
|
public class MapperModule extends AbstractModule {
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(UserDtoToUserMapper.class).to(Mappers.getMapper(UserDtoToUserMapper.class).getClass());
|
bind(UserDtoToUserMapper.class).to(Mappers.getMapperClass(UserDtoToUserMapper.class));
|
||||||
bind(UserToUserDtoMapper.class).to(Mappers.getMapper(UserToUserDtoMapper.class).getClass());
|
bind(UserToUserDtoMapper.class).to(Mappers.getMapperClass(UserToUserDtoMapper.class));
|
||||||
bind(UserCollectionToDtoMapper.class);
|
bind(UserCollectionToDtoMapper.class);
|
||||||
|
|
||||||
bind(GroupDtoToGroupMapper.class).to(Mappers.getMapper(GroupDtoToGroupMapper.class).getClass());
|
bind(GroupDtoToGroupMapper.class).to(Mappers.getMapperClass(GroupDtoToGroupMapper.class));
|
||||||
bind(GroupToGroupDtoMapper.class).to(Mappers.getMapper(GroupToGroupDtoMapper.class).getClass());
|
bind(GroupToGroupDtoMapper.class).to(Mappers.getMapperClass(GroupToGroupDtoMapper.class));
|
||||||
bind(GroupCollectionToDtoMapper.class);
|
bind(GroupCollectionToDtoMapper.class);
|
||||||
|
|
||||||
bind(ScmConfigurationToConfigDtoMapper.class).to(Mappers.getMapper(ScmConfigurationToConfigDtoMapper.class).getClass());
|
bind(ScmConfigurationToConfigDtoMapper.class).to(Mappers.getMapperClass(ScmConfigurationToConfigDtoMapper.class));
|
||||||
bind(ConfigDtoToScmConfigurationMapper.class).to(Mappers.getMapper(ConfigDtoToScmConfigurationMapper.class).getClass());
|
bind(ConfigDtoToScmConfigurationMapper.class).to(Mappers.getMapperClass(ConfigDtoToScmConfigurationMapper.class));
|
||||||
|
|
||||||
bind(RepositoryToRepositoryDtoMapper.class).to(Mappers.getMapper(RepositoryToRepositoryDtoMapper.class).getClass());
|
bind(RepositoryToRepositoryDtoMapper.class).to(Mappers.getMapperClass(RepositoryToRepositoryDtoMapper.class));
|
||||||
bind(RepositoryDtoToRepositoryMapper.class).to(Mappers.getMapper(RepositoryDtoToRepositoryMapper.class).getClass());
|
bind(RepositoryDtoToRepositoryMapper.class).to(Mappers.getMapperClass(RepositoryDtoToRepositoryMapper.class));
|
||||||
|
|
||||||
bind(RepositoryTypeToRepositoryTypeDtoMapper.class).to(Mappers.getMapper(RepositoryTypeToRepositoryTypeDtoMapper.class).getClass());
|
bind(RepositoryTypeToRepositoryTypeDtoMapper.class).to(Mappers.getMapperClass(RepositoryTypeToRepositoryTypeDtoMapper.class));
|
||||||
bind(RepositoryTypeCollectionToDtoMapper.class);
|
bind(RepositoryTypeCollectionToDtoMapper.class);
|
||||||
|
|
||||||
bind(BranchToBranchDtoMapper.class).to(Mappers.getMapper(BranchToBranchDtoMapper.class).getClass());
|
bind(BranchToBranchDtoMapper.class).to(Mappers.getMapperClass(BranchToBranchDtoMapper.class));
|
||||||
bind(RepositoryPermissionDtoToRepositoryPermissionMapper.class).to(Mappers.getMapper(RepositoryPermissionDtoToRepositoryPermissionMapper.class).getClass());
|
bind(RepositoryPermissionDtoToRepositoryPermissionMapper.class).to(Mappers.getMapperClass(RepositoryPermissionDtoToRepositoryPermissionMapper.class));
|
||||||
bind(RepositoryPermissionToRepositoryPermissionDtoMapper.class).to(Mappers.getMapper(RepositoryPermissionToRepositoryPermissionDtoMapper.class).getClass());
|
bind(RepositoryPermissionToRepositoryPermissionDtoMapper.class).to(Mappers.getMapperClass(RepositoryPermissionToRepositoryPermissionDtoMapper.class));
|
||||||
|
|
||||||
bind(RepositoryRoleToRepositoryRoleDtoMapper.class).to(Mappers.getMapper(RepositoryRoleToRepositoryRoleDtoMapper.class).getClass());
|
bind(RepositoryRoleToRepositoryRoleDtoMapper.class).to(Mappers.getMapperClass(RepositoryRoleToRepositoryRoleDtoMapper.class));
|
||||||
bind(RepositoryRoleDtoToRepositoryRoleMapper.class).to(Mappers.getMapper(RepositoryRoleDtoToRepositoryRoleMapper.class).getClass());
|
bind(RepositoryRoleDtoToRepositoryRoleMapper.class).to(Mappers.getMapperClass(RepositoryRoleDtoToRepositoryRoleMapper.class));
|
||||||
bind(RepositoryRoleCollectionToDtoMapper.class);
|
bind(RepositoryRoleCollectionToDtoMapper.class);
|
||||||
|
|
||||||
bind(ChangesetToChangesetDtoMapper.class).to(Mappers.getMapper(DefaultChangesetToChangesetDtoMapper.class).getClass());
|
bind(ChangesetToChangesetDtoMapper.class).to(Mappers.getMapperClass(DefaultChangesetToChangesetDtoMapper.class));
|
||||||
bind(ChangesetToParentDtoMapper.class).to(Mappers.getMapper(ChangesetToParentDtoMapper.class).getClass());
|
bind(ChangesetToParentDtoMapper.class).to(Mappers.getMapperClass(ChangesetToParentDtoMapper.class));
|
||||||
|
|
||||||
bind(TagToTagDtoMapper.class).to(Mappers.getMapper(TagToTagDtoMapper.class).getClass());
|
bind(TagToTagDtoMapper.class).to(Mappers.getMapperClass(TagToTagDtoMapper.class));
|
||||||
|
|
||||||
bind(BrowserResultToFileObjectDtoMapper.class).to(Mappers.getMapper(BrowserResultToFileObjectDtoMapper.class).getClass());
|
bind(BrowserResultToFileObjectDtoMapper.class).to(Mappers.getMapperClass(BrowserResultToFileObjectDtoMapper.class));
|
||||||
bind(ModificationsToDtoMapper.class).to(Mappers.getMapper(ModificationsToDtoMapper.class).getClass());
|
bind(ModificationsToDtoMapper.class).to(Mappers.getMapperClass(ModificationsToDtoMapper.class));
|
||||||
|
|
||||||
bind(ReducedObjectModelToDtoMapper.class).to(Mappers.getMapper(ReducedObjectModelToDtoMapper.class).getClass());
|
bind(ReducedObjectModelToDtoMapper.class).to(Mappers.getMapperClass(ReducedObjectModelToDtoMapper.class));
|
||||||
|
|
||||||
bind(ResteasyViolationExceptionToErrorDtoMapper.class).to(Mappers.getMapper(ResteasyViolationExceptionToErrorDtoMapper.class).getClass());
|
bind(ResteasyViolationExceptionToErrorDtoMapper.class).to(Mappers.getMapperClass(ResteasyViolationExceptionToErrorDtoMapper.class));
|
||||||
bind(ScmViolationExceptionToErrorDtoMapper.class).to(Mappers.getMapper(ScmViolationExceptionToErrorDtoMapper.class).getClass());
|
bind(ScmViolationExceptionToErrorDtoMapper.class).to(Mappers.getMapperClass(ScmViolationExceptionToErrorDtoMapper.class));
|
||||||
bind(ExceptionWithContextToErrorDtoMapper.class).to(Mappers.getMapper(ExceptionWithContextToErrorDtoMapper.class).getClass());
|
bind(ExceptionWithContextToErrorDtoMapper.class).to(Mappers.getMapperClass(ExceptionWithContextToErrorDtoMapper.class));
|
||||||
|
|
||||||
bind(RepositoryToHalMapper.class).to(Mappers.getMapper(RepositoryToRepositoryDtoMapper.class).getClass());
|
bind(RepositoryToHalMapper.class).to(Mappers.getMapperClass(RepositoryToRepositoryDtoMapper.class));
|
||||||
|
|
||||||
|
bind(BlameResultToBlameDtoMapper.class).to(Mappers.getMapperClass(BlameResultToBlameDtoMapper.class));
|
||||||
|
|
||||||
// no mapstruct required
|
// no mapstruct required
|
||||||
bind(MeDtoFactory.class);
|
bind(MeDtoFactory.class);
|
||||||
@@ -80,6 +82,6 @@ public class MapperModule extends AbstractModule {
|
|||||||
|
|
||||||
bind(ScmPathInfoStore.class).in(ServletScopes.REQUEST);
|
bind(ScmPathInfoStore.class).in(ServletScopes.REQUEST);
|
||||||
|
|
||||||
bind(PluginDtoMapper.class).to(Mappers.getMapper(PluginDtoMapper.class).getClass());
|
bind(PluginDtoMapper.class).to(Mappers.getMapperClass(PluginDtoMapper.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
|
||||||
|
public class RepositoryBasedResourceProvider {
|
||||||
|
private final Provider<TagRootResource> tagRootResource;
|
||||||
|
private final Provider<BranchRootResource> branchRootResource;
|
||||||
|
private final Provider<ChangesetRootResource> changesetRootResource;
|
||||||
|
private final Provider<SourceRootResource> sourceRootResource;
|
||||||
|
private final Provider<ContentResource> contentResource;
|
||||||
|
private final Provider<RepositoryPermissionRootResource> permissionRootResource;
|
||||||
|
private final Provider<DiffRootResource> diffRootResource;
|
||||||
|
private final Provider<ModificationsRootResource> modificationsRootResource;
|
||||||
|
private final Provider<FileHistoryRootResource> fileHistoryRootResource;
|
||||||
|
private final Provider<IncomingRootResource> incomingRootResource;
|
||||||
|
private final Provider<AnnotateResource> annotateResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public RepositoryBasedResourceProvider(
|
||||||
|
Provider<TagRootResource> tagRootResource,
|
||||||
|
Provider<BranchRootResource> branchRootResource,
|
||||||
|
Provider<ChangesetRootResource> changesetRootResource,
|
||||||
|
Provider<SourceRootResource> sourceRootResource,
|
||||||
|
Provider<ContentResource> contentResource,
|
||||||
|
Provider<RepositoryPermissionRootResource> permissionRootResource,
|
||||||
|
Provider<DiffRootResource> diffRootResource,
|
||||||
|
Provider<ModificationsRootResource> modificationsRootResource,
|
||||||
|
Provider<FileHistoryRootResource> fileHistoryRootResource,
|
||||||
|
Provider<IncomingRootResource> incomingRootResource, Provider<AnnotateResource> annotateResource) {
|
||||||
|
this.tagRootResource = tagRootResource;
|
||||||
|
this.branchRootResource = branchRootResource;
|
||||||
|
this.changesetRootResource = changesetRootResource;
|
||||||
|
this.sourceRootResource = sourceRootResource;
|
||||||
|
this.contentResource = contentResource;
|
||||||
|
this.permissionRootResource = permissionRootResource;
|
||||||
|
this.diffRootResource = diffRootResource;
|
||||||
|
this.modificationsRootResource = modificationsRootResource;
|
||||||
|
this.fileHistoryRootResource = fileHistoryRootResource;
|
||||||
|
this.incomingRootResource = incomingRootResource;
|
||||||
|
this.annotateResource = annotateResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagRootResource getTagRootResource() {
|
||||||
|
return tagRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BranchRootResource getBranchRootResource() {
|
||||||
|
return branchRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangesetRootResource getChangesetRootResource() {
|
||||||
|
return changesetRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceRootResource getSourceRootResource() {
|
||||||
|
return sourceRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentResource getContentResource() {
|
||||||
|
return contentResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RepositoryPermissionRootResource getPermissionRootResource() {
|
||||||
|
return permissionRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiffRootResource getDiffRootResource() {
|
||||||
|
return diffRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModificationsRootResource getModificationsRootResource() {
|
||||||
|
return modificationsRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileHistoryRootResource getFileHistoryRootResource() {
|
||||||
|
return fileHistoryRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncomingRootResource getIncomingRootResource() {
|
||||||
|
return incomingRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnotateResource getAnnotateResource() {
|
||||||
|
return annotateResource.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
@@ -58,46 +58,19 @@ public class RepositoryResource {
|
|||||||
|
|
||||||
private final RepositoryManager manager;
|
private final RepositoryManager manager;
|
||||||
private final SingleResourceManagerAdapter<Repository, RepositoryDto> adapter;
|
private final SingleResourceManagerAdapter<Repository, RepositoryDto> adapter;
|
||||||
private final Provider<TagRootResource> tagRootResource;
|
private final RepositoryBasedResourceProvider resourceProvider;
|
||||||
private final Provider<BranchRootResource> branchRootResource;
|
|
||||||
private final Provider<ChangesetRootResource> changesetRootResource;
|
|
||||||
private final Provider<SourceRootResource> sourceRootResource;
|
|
||||||
private final Provider<ContentResource> contentResource;
|
|
||||||
private final Provider<RepositoryPermissionRootResource> permissionRootResource;
|
|
||||||
private final Provider<DiffRootResource> diffRootResource;
|
|
||||||
private final Provider<ModificationsRootResource> modificationsRootResource;
|
|
||||||
private final Provider<FileHistoryRootResource> fileHistoryRootResource;
|
|
||||||
private final Provider<IncomingRootResource> incomingRootResource;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public RepositoryResource(
|
public RepositoryResource(
|
||||||
RepositoryToRepositoryDtoMapper repositoryToDtoMapper,
|
RepositoryToRepositoryDtoMapper repositoryToDtoMapper,
|
||||||
RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, RepositoryManager manager,
|
RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, RepositoryManager manager,
|
||||||
Provider<TagRootResource> tagRootResource,
|
RepositoryBasedResourceProvider resourceProvider
|
||||||
Provider<BranchRootResource> branchRootResource,
|
|
||||||
Provider<ChangesetRootResource> changesetRootResource,
|
|
||||||
Provider<SourceRootResource> sourceRootResource, Provider<ContentResource> contentResource,
|
|
||||||
Provider<RepositoryPermissionRootResource> permissionRootResource,
|
|
||||||
Provider<DiffRootResource> diffRootResource,
|
|
||||||
Provider<ModificationsRootResource> modificationsRootResource,
|
|
||||||
Provider<FileHistoryRootResource> fileHistoryRootResource,
|
|
||||||
Provider<IncomingRootResource> incomingRootResource
|
|
||||||
) {
|
) {
|
||||||
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
|
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.repositoryToDtoMapper = repositoryToDtoMapper;
|
this.repositoryToDtoMapper = repositoryToDtoMapper;
|
||||||
this.adapter = new SingleResourceManagerAdapter<>(manager, Repository.class);
|
this.adapter = new SingleResourceManagerAdapter<>(manager, Repository.class);
|
||||||
this.tagRootResource = tagRootResource;
|
this.resourceProvider = resourceProvider;
|
||||||
this.branchRootResource = branchRootResource;
|
|
||||||
this.changesetRootResource = changesetRootResource;
|
|
||||||
this.sourceRootResource = sourceRootResource;
|
|
||||||
this.contentResource = contentResource;
|
|
||||||
this.permissionRootResource = permissionRootResource;
|
|
||||||
this.diffRootResource = diffRootResource;
|
|
||||||
this.modificationsRootResource = modificationsRootResource;
|
|
||||||
this.fileHistoryRootResource = fileHistoryRootResource;
|
|
||||||
this.incomingRootResource = incomingRootResource;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,52 +184,57 @@ public class RepositoryResource {
|
|||||||
|
|
||||||
@Path("tags/")
|
@Path("tags/")
|
||||||
public TagRootResource tags() {
|
public TagRootResource tags() {
|
||||||
return tagRootResource.get();
|
return resourceProvider.getTagRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("diff/")
|
@Path("diff/")
|
||||||
public DiffRootResource diff() {
|
public DiffRootResource diff() {
|
||||||
return diffRootResource.get();
|
return resourceProvider.getDiffRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("branches/")
|
@Path("branches/")
|
||||||
public BranchRootResource branches() {
|
public BranchRootResource branches() {
|
||||||
return branchRootResource.get();
|
return resourceProvider.getBranchRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("changesets/")
|
@Path("changesets/")
|
||||||
public ChangesetRootResource changesets() {
|
public ChangesetRootResource changesets() {
|
||||||
return changesetRootResource.get();
|
return resourceProvider.getChangesetRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("history/")
|
@Path("history/")
|
||||||
public FileHistoryRootResource history() {
|
public FileHistoryRootResource history() {
|
||||||
return fileHistoryRootResource.get();
|
return resourceProvider.getFileHistoryRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("sources/")
|
@Path("sources/")
|
||||||
public SourceRootResource sources() {
|
public SourceRootResource sources() {
|
||||||
return sourceRootResource.get();
|
return resourceProvider.getSourceRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("content/")
|
@Path("content/")
|
||||||
public ContentResource content() {
|
public ContentResource content() {
|
||||||
return contentResource.get();
|
return resourceProvider.getContentResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("permissions/")
|
@Path("permissions/")
|
||||||
public RepositoryPermissionRootResource permissions() {
|
public RepositoryPermissionRootResource permissions() {
|
||||||
return permissionRootResource.get();
|
return resourceProvider.getPermissionRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("modifications/")
|
@Path("modifications/")
|
||||||
public ModificationsRootResource modifications() {
|
public ModificationsRootResource modifications() {
|
||||||
return modificationsRootResource.get();
|
return resourceProvider.getModificationsRootResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Path("incoming/")
|
@Path("incoming/")
|
||||||
public IncomingRootResource incoming() {
|
public IncomingRootResource incoming() {
|
||||||
return incomingRootResource.get();
|
return resourceProvider.getIncomingRootResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("annotate/")
|
||||||
|
public AnnotateResource annotate() {
|
||||||
|
return resourceProvider.getAnnotateResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Supplier<Repository> loadBy(String namespace, String name) {
|
private Supplier<Repository> loadBy(String namespace, String name) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import sonia.scm.repository.NamespaceAndName;
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
@@ -566,6 +566,22 @@ class ResourceLinks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AnnotateLinks annotate() {
|
||||||
|
return new AnnotateLinks(scmPathInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AnnotateLinks {
|
||||||
|
private final LinkBuilder annotateLinkBuilder;
|
||||||
|
|
||||||
|
AnnotateLinks(ScmPathInfo pathInfo) {
|
||||||
|
this.annotateLinkBuilder = new LinkBuilder(pathInfo, RepositoryRootResource.class, RepositoryResource.class, AnnotateResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self(String namespace, String name, String revision, String path) {
|
||||||
|
return annotateLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("annotate").parameters().method("annotate").parameters(revision, path).href();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RepositoryVerbLinks repositoryVerbs() {
|
RepositoryVerbLinks repositoryVerbs() {
|
||||||
return new RepositoryVerbLinks(scmPathInfoStore.get());
|
return new RepositoryVerbLinks(scmPathInfoStore.get());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-present Cloudogu GmbH and 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
|
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||||
|
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Answers;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import sonia.scm.repository.BlameLine;
|
||||||
|
import sonia.scm.repository.BlameResult;
|
||||||
|
import sonia.scm.repository.NamespaceAndName;
|
||||||
|
import sonia.scm.repository.Person;
|
||||||
|
import sonia.scm.repository.api.BlameCommandBuilder;
|
||||||
|
import sonia.scm.repository.api.RepositoryService;
|
||||||
|
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||||
|
import sonia.scm.web.RestDispatcher;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class AnnotateResourceTest extends RepositoryTestBase {
|
||||||
|
|
||||||
|
public static final NamespaceAndName NAMESPACE_AND_NAME = new NamespaceAndName("space", "X");
|
||||||
|
public static final String REVISION = "123";
|
||||||
|
public static final String PATH = "some/file";
|
||||||
|
@Mock
|
||||||
|
private RepositoryServiceFactory serviceFactory;
|
||||||
|
@Mock
|
||||||
|
private RepositoryService service;
|
||||||
|
@Mock
|
||||||
|
private BlameCommandBuilder blameCommandBuilder;
|
||||||
|
|
||||||
|
private final RestDispatcher dispatcher = new RestDispatcher();
|
||||||
|
private final MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void initResource() {
|
||||||
|
BlameResultToBlameDtoMapperImpl mapper = new BlameResultToBlameDtoMapperImpl();
|
||||||
|
mapper.setResourceLinks(ResourceLinksMock.createMock(URI.create("/")));
|
||||||
|
annotateResource = new AnnotateResource(serviceFactory, mapper);
|
||||||
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void initRepositoryService() {
|
||||||
|
when(serviceFactory.create(NAMESPACE_AND_NAME)).thenReturn(service);
|
||||||
|
when(service.getBlameCommand()).thenReturn(blameCommandBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void initBlameCommand() throws IOException {
|
||||||
|
BlameLine line1 = new BlameLine(
|
||||||
|
0,
|
||||||
|
"100",
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
new Person("Arthur Dent", "arthur@hitchhiker.com"),
|
||||||
|
"first try",
|
||||||
|
"jump"
|
||||||
|
);
|
||||||
|
BlameLine line2 = new BlameLine(
|
||||||
|
1,
|
||||||
|
"42",
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
new Person("Zaphod Beeblebrox", "zaphod@hitchhiker.com"),
|
||||||
|
"got it",
|
||||||
|
"heart of gold"
|
||||||
|
);
|
||||||
|
BlameResult result = new BlameResult(asList(line1, line2));
|
||||||
|
when(blameCommandBuilder.setRevision(REVISION)).thenReturn(blameCommandBuilder);
|
||||||
|
when(blameCommandBuilder.getBlameResult(PATH)).thenReturn(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldReturnAnnotations() throws URISyntaxException, UnsupportedEncodingException, JsonProcessingException {
|
||||||
|
MockHttpRequest request = MockHttpRequest
|
||||||
|
.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + NAMESPACE_AND_NAME + "/annotate/" + REVISION + "/" + PATH);
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
|
||||||
|
String content = response.getContentAsString();
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode jsonNode = mapper.readTree(content);
|
||||||
|
JsonNode blameLines = jsonNode.get("lines");
|
||||||
|
assertThat(blameLines.isArray()).isTrue();
|
||||||
|
assertThat(jsonNode.get("_links").get("self").get("href").asText())
|
||||||
|
.isEqualTo("/v2/repositories/space/X/annotate/123/some%2Ffile");
|
||||||
|
|
||||||
|
Iterator<JsonNode> lineIterator = blameLines.iterator();
|
||||||
|
JsonNode line1 = lineIterator.next();
|
||||||
|
assertThat(line1.get("author").get("mail").asText()).isEqualTo("arthur@hitchhiker.com");
|
||||||
|
assertThat(line1.get("author").get("name").asText()).isEqualTo("Arthur Dent");
|
||||||
|
assertThat(line1.get("code").asText()).isEqualTo("jump");
|
||||||
|
assertThat(line1.get("description").asText()).isEqualTo("first try");
|
||||||
|
assertThat(line1.get("lineNumber").asInt()).isEqualTo(0);
|
||||||
|
assertThat(line1.get("revision").asText()).isEqualTo("100");
|
||||||
|
|
||||||
|
JsonNode line2 = lineIterator.next();
|
||||||
|
assertThat(line2.get("author").get("mail").asText()).isEqualTo("zaphod@hitchhiker.com");
|
||||||
|
assertThat(line2.get("author").get("name").asText()).isEqualTo("Zaphod Beeblebrox");
|
||||||
|
assertThat(line2.get("code").asText()).isEqualTo("heart of gold");
|
||||||
|
assertThat(line2.get("description").asText()).isEqualTo("got it");
|
||||||
|
assertThat(line2.get("lineNumber").asInt()).isEqualTo(1);
|
||||||
|
assertThat(line2.get("revision").asText()).isEqualTo("42");
|
||||||
|
|
||||||
|
assertThat(lineIterator.hasNext()).isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,8 +103,6 @@ public class BranchRootResourceTest extends RepositoryTestBase {
|
|||||||
|
|
||||||
private BranchChangesetCollectionToDtoMapper changesetCollectionToDtoMapper;
|
private BranchChangesetCollectionToDtoMapper changesetCollectionToDtoMapper;
|
||||||
|
|
||||||
private BranchRootResource branchRootResource;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private BranchCollectionToDtoMapper branchCollectionToDtoMapper;
|
private BranchCollectionToDtoMapper branchCollectionToDtoMapper;
|
||||||
|
|
||||||
@@ -126,7 +124,6 @@ public class BranchRootResourceTest extends RepositoryTestBase {
|
|||||||
changesetCollectionToDtoMapper = new BranchChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
changesetCollectionToDtoMapper = new BranchChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
||||||
BranchCollectionToDtoMapper branchCollectionToDtoMapper = new BranchCollectionToDtoMapper(branchToDtoMapper, resourceLinks);
|
BranchCollectionToDtoMapper branchCollectionToDtoMapper = new BranchCollectionToDtoMapper(branchToDtoMapper, resourceLinks);
|
||||||
branchRootResource = new BranchRootResource(serviceFactory, branchToDtoMapper, branchCollectionToDtoMapper, changesetCollectionToDtoMapper, resourceLinks);
|
branchRootResource = new BranchRootResource(serviceFactory, branchToDtoMapper, branchCollectionToDtoMapper, changesetCollectionToDtoMapper, resourceLinks);
|
||||||
super.branchRootResource = Providers.of(branchRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
||||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ public class ChangesetRootResourceTest extends RepositoryTestBase {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private DefaultChangesetToChangesetDtoMapperImpl changesetToChangesetDtoMapper;
|
private DefaultChangesetToChangesetDtoMapperImpl changesetToChangesetDtoMapper;
|
||||||
|
|
||||||
private ChangesetRootResource changesetRootResource;
|
|
||||||
|
|
||||||
private final Subject subject = mock(Subject.class);
|
private final Subject subject = mock(Subject.class);
|
||||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||||
|
|
||||||
@@ -100,7 +98,6 @@ public class ChangesetRootResourceTest extends RepositoryTestBase {
|
|||||||
public void prepareEnvironment() {
|
public void prepareEnvironment() {
|
||||||
changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
||||||
changesetRootResource = new ChangesetRootResource(serviceFactory, changesetCollectionToDtoMapper, changesetToChangesetDtoMapper);
|
changesetRootResource = new ChangesetRootResource(serviceFactory, changesetCollectionToDtoMapper, changesetToChangesetDtoMapper);
|
||||||
super.changesetRootResource = Providers.of(changesetRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
||||||
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
|
||||||
@@ -90,9 +90,6 @@ public class DiffResourceTest extends RepositoryTestBase {
|
|||||||
@Mock
|
@Mock
|
||||||
private DiffResultToDiffResultDtoMapper diffResultToDiffResultDtoMapper;
|
private DiffResultToDiffResultDtoMapper diffResultToDiffResultDtoMapper;
|
||||||
|
|
||||||
private DiffRootResource diffRootResource;
|
|
||||||
|
|
||||||
|
|
||||||
private final Subject subject = mock(Subject.class);
|
private final Subject subject = mock(Subject.class);
|
||||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||||
|
|
||||||
@@ -100,7 +97,6 @@ public class DiffResourceTest extends RepositoryTestBase {
|
|||||||
@Before
|
@Before
|
||||||
public void prepareEnvironment() {
|
public void prepareEnvironment() {
|
||||||
diffRootResource = new DiffRootResource(serviceFactory, diffResultToDiffResultDtoMapper);
|
diffRootResource = new DiffRootResource(serviceFactory, diffResultToDiffResultDtoMapper);
|
||||||
super.diffRootResource = Providers.of(diffRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
||||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||||
|
|||||||
@@ -92,8 +92,6 @@ public class FileHistoryResourceTest extends RepositoryTestBase {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private DefaultChangesetToChangesetDtoMapperImpl changesetToChangesetDtoMapper;
|
private DefaultChangesetToChangesetDtoMapperImpl changesetToChangesetDtoMapper;
|
||||||
|
|
||||||
private FileHistoryRootResource fileHistoryRootResource;
|
|
||||||
|
|
||||||
private RestDispatcher dispatcher = new RestDispatcher();
|
private RestDispatcher dispatcher = new RestDispatcher();
|
||||||
|
|
||||||
private final Subject subject = mock(Subject.class);
|
private final Subject subject = mock(Subject.class);
|
||||||
@@ -103,7 +101,6 @@ public class FileHistoryResourceTest extends RepositoryTestBase {
|
|||||||
public void prepareEnvironment() {
|
public void prepareEnvironment() {
|
||||||
fileHistoryCollectionToDtoMapper = new FileHistoryCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
fileHistoryCollectionToDtoMapper = new FileHistoryCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
||||||
fileHistoryRootResource = new FileHistoryRootResource(serviceFactory, fileHistoryCollectionToDtoMapper);
|
fileHistoryRootResource = new FileHistoryRootResource(serviceFactory, fileHistoryCollectionToDtoMapper);
|
||||||
super.fileHistoryRootResource = Providers.of(fileHistoryRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
||||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||||
|
|||||||
@@ -110,9 +110,6 @@ public class IncomingRootResourceTest extends RepositoryTestBase {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private DefaultChangesetToChangesetDtoMapperImpl changesetToChangesetDtoMapper;
|
private DefaultChangesetToChangesetDtoMapperImpl changesetToChangesetDtoMapper;
|
||||||
|
|
||||||
private IncomingRootResource incomingRootResource;
|
|
||||||
|
|
||||||
|
|
||||||
private final Subject subject = mock(Subject.class);
|
private final Subject subject = mock(Subject.class);
|
||||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||||
|
|
||||||
@@ -121,7 +118,6 @@ public class IncomingRootResourceTest extends RepositoryTestBase {
|
|||||||
public void prepareEnvironment() {
|
public void prepareEnvironment() {
|
||||||
incomingChangesetCollectionToDtoMapper = new IncomingChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
incomingChangesetCollectionToDtoMapper = new IncomingChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
|
||||||
incomingRootResource = new IncomingRootResource(serviceFactory, incomingChangesetCollectionToDtoMapper, diffResultToDiffResultDtoMapper);
|
incomingRootResource = new IncomingRootResource(serviceFactory, incomingChangesetCollectionToDtoMapper, diffResultToDiffResultDtoMapper);
|
||||||
super.incomingRootResource = Providers.of(incomingRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
||||||
when(serviceFactory.create(REPOSITORY)).thenReturn(repositoryService);
|
when(serviceFactory.create(REPOSITORY)).thenReturn(repositoryService);
|
||||||
|
|||||||
@@ -88,9 +88,6 @@ public class ModificationsResourceTest extends RepositoryTestBase {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private ModificationsToDtoMapperImpl modificationsToDtoMapper;
|
private ModificationsToDtoMapperImpl modificationsToDtoMapper;
|
||||||
|
|
||||||
private ModificationsRootResource modificationsRootResource;
|
|
||||||
|
|
||||||
|
|
||||||
private final Subject subject = mock(Subject.class);
|
private final Subject subject = mock(Subject.class);
|
||||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||||
|
|
||||||
@@ -98,7 +95,6 @@ public class ModificationsResourceTest extends RepositoryTestBase {
|
|||||||
@Before
|
@Before
|
||||||
public void prepareEnvironment() {
|
public void prepareEnvironment() {
|
||||||
modificationsRootResource = new ModificationsRootResource(serviceFactory, modificationsToDtoMapper);
|
modificationsRootResource = new ModificationsRootResource(serviceFactory, modificationsToDtoMapper);
|
||||||
super.modificationsRootResource = Providers.of(modificationsRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
||||||
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
@@ -144,8 +144,6 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase {
|
|||||||
|
|
||||||
private RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper;
|
private RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper;
|
||||||
|
|
||||||
private RepositoryPermissionRootResource repositoryPermissionRootResource;
|
|
||||||
|
|
||||||
private final Subject subject = mock(Subject.class);
|
private final Subject subject = mock(Subject.class);
|
||||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||||
|
|
||||||
@@ -154,8 +152,7 @@ public class RepositoryPermissionRootResourceTest extends RepositoryTestBase {
|
|||||||
public void prepareEnvironment() {
|
public void prepareEnvironment() {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
repositoryPermissionCollectionToDtoMapper = new RepositoryPermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks);
|
repositoryPermissionCollectionToDtoMapper = new RepositoryPermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks);
|
||||||
repositoryPermissionRootResource = new RepositoryPermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, repositoryPermissionCollectionToDtoMapper, resourceLinks, repositoryManager);
|
permissionRootResource = new RepositoryPermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, repositoryPermissionCollectionToDtoMapper, resourceLinks, repositoryManager);
|
||||||
super.permissionRootResource = Providers.of(repositoryPermissionRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
subjectThreadState.bind();
|
subjectThreadState.bind();
|
||||||
ThreadContext.bind(subject);
|
ThreadContext.bind(subject);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.github.sdorra.shiro.ShiroRule;
|
import com.github.sdorra.shiro.ShiroRule;
|
||||||
@@ -122,7 +122,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase {
|
|||||||
super.dtoToRepositoryMapper = dtoToRepositoryMapper;
|
super.dtoToRepositoryMapper = dtoToRepositoryMapper;
|
||||||
super.manager = repositoryManager;
|
super.manager = repositoryManager;
|
||||||
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
|
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
|
||||||
super.repositoryCollectionResource = Providers.of(new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks, repositoryInitializer));
|
super.repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks, repositoryInitializer);
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||||
when(scmPathInfoStore.get()).thenReturn(uriInfo);
|
when(scmPathInfoStore.get()).thenReturn(uriInfo);
|
||||||
|
|||||||
@@ -21,49 +21,53 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.google.inject.util.Providers;
|
|
||||||
import sonia.scm.repository.RepositoryManager;
|
import sonia.scm.repository.RepositoryManager;
|
||||||
|
|
||||||
import javax.inject.Provider;
|
import static com.google.inject.util.Providers.of;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public abstract class RepositoryTestBase {
|
abstract class RepositoryTestBase {
|
||||||
|
|
||||||
|
RepositoryToRepositoryDtoMapper repositoryToDtoMapper;
|
||||||
protected RepositoryToRepositoryDtoMapper repositoryToDtoMapper;
|
RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
|
||||||
protected RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
|
RepositoryManager manager;
|
||||||
protected RepositoryManager manager;
|
TagRootResource tagRootResource;
|
||||||
protected Provider<TagRootResource> tagRootResource;
|
BranchRootResource branchRootResource;
|
||||||
protected Provider<BranchRootResource> branchRootResource;
|
ChangesetRootResource changesetRootResource;
|
||||||
protected Provider<ChangesetRootResource> changesetRootResource;
|
SourceRootResource sourceRootResource;
|
||||||
protected Provider<SourceRootResource> sourceRootResource;
|
ContentResource contentResource;
|
||||||
protected Provider<ContentResource> contentResource;
|
RepositoryPermissionRootResource permissionRootResource;
|
||||||
protected Provider<RepositoryPermissionRootResource> permissionRootResource;
|
DiffRootResource diffRootResource;
|
||||||
protected Provider<DiffRootResource> diffRootResource;
|
ModificationsRootResource modificationsRootResource;
|
||||||
protected Provider<ModificationsRootResource> modificationsRootResource;
|
FileHistoryRootResource fileHistoryRootResource;
|
||||||
protected Provider<FileHistoryRootResource> fileHistoryRootResource;
|
IncomingRootResource incomingRootResource;
|
||||||
protected Provider<RepositoryCollectionResource> repositoryCollectionResource;
|
RepositoryCollectionResource repositoryCollectionResource;
|
||||||
protected Provider<IncomingRootResource> incomingRootResource;
|
AnnotateResource annotateResource;
|
||||||
|
|
||||||
|
|
||||||
RepositoryRootResource getRepositoryRootResource() {
|
RepositoryRootResource getRepositoryRootResource() {
|
||||||
return new RepositoryRootResource(Providers.of(new RepositoryResource(
|
RepositoryBasedResourceProvider repositoryBasedResourceProvider = new RepositoryBasedResourceProvider(
|
||||||
repositoryToDtoMapper,
|
of(tagRootResource),
|
||||||
dtoToRepositoryMapper,
|
of(branchRootResource),
|
||||||
manager,
|
of(changesetRootResource),
|
||||||
tagRootResource,
|
of(sourceRootResource),
|
||||||
branchRootResource,
|
of(contentResource),
|
||||||
changesetRootResource,
|
of(permissionRootResource),
|
||||||
sourceRootResource,
|
of(diffRootResource),
|
||||||
contentResource,
|
of(modificationsRootResource),
|
||||||
permissionRootResource,
|
of(fileHistoryRootResource),
|
||||||
diffRootResource,
|
of(incomingRootResource),
|
||||||
modificationsRootResource,
|
of(annotateResource));
|
||||||
fileHistoryRootResource,
|
return new RepositoryRootResource(
|
||||||
incomingRootResource)), repositoryCollectionResource);
|
of(new RepositoryResource(
|
||||||
|
repositoryToDtoMapper,
|
||||||
|
dtoToRepositoryMapper,
|
||||||
|
manager,
|
||||||
|
repositoryBasedResourceProvider
|
||||||
|
)),
|
||||||
|
of(repositoryCollectionResource));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,12 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -33,47 +34,48 @@ public class ResourceLinksMock {
|
|||||||
public static ResourceLinks createMock(URI baseUri) {
|
public static ResourceLinks createMock(URI baseUri) {
|
||||||
ResourceLinks resourceLinks = mock(ResourceLinks.class);
|
ResourceLinks resourceLinks = mock(ResourceLinks.class);
|
||||||
|
|
||||||
ScmPathInfo uriInfo = mock(ScmPathInfo.class);
|
ScmPathInfo pathInfo = mock(ScmPathInfo.class);
|
||||||
when(uriInfo.getApiRestUri()).thenReturn(baseUri);
|
when(pathInfo.getApiRestUri()).thenReturn(baseUri);
|
||||||
|
|
||||||
ResourceLinks.UserLinks userLinks = new ResourceLinks.UserLinks(uriInfo);
|
ResourceLinks.UserLinks userLinks = new ResourceLinks.UserLinks(pathInfo);
|
||||||
when(resourceLinks.user()).thenReturn(userLinks);
|
lenient().when(resourceLinks.user()).thenReturn(userLinks);
|
||||||
when(resourceLinks.me()).thenReturn(new ResourceLinks.MeLinks(uriInfo,userLinks));
|
lenient().when(resourceLinks.me()).thenReturn(new ResourceLinks.MeLinks(pathInfo,userLinks));
|
||||||
when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.userPermissions()).thenReturn(new ResourceLinks.UserPermissionLinks(uriInfo));
|
lenient().when(resourceLinks.userPermissions()).thenReturn(new ResourceLinks.UserPermissionLinks(pathInfo));
|
||||||
when(resourceLinks.autoComplete()).thenReturn(new ResourceLinks.AutoCompleteLinks(uriInfo));
|
lenient().when(resourceLinks.autoComplete()).thenReturn(new ResourceLinks.AutoCompleteLinks(pathInfo));
|
||||||
when(resourceLinks.group()).thenReturn(new ResourceLinks.GroupLinks(uriInfo));
|
lenient().when(resourceLinks.group()).thenReturn(new ResourceLinks.GroupLinks(pathInfo));
|
||||||
when(resourceLinks.groupCollection()).thenReturn(new ResourceLinks.GroupCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.groupCollection()).thenReturn(new ResourceLinks.GroupCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.groupPermissions()).thenReturn(new ResourceLinks.GroupPermissionLinks(uriInfo));
|
lenient().when(resourceLinks.groupPermissions()).thenReturn(new ResourceLinks.GroupPermissionLinks(pathInfo));
|
||||||
when(resourceLinks.repository()).thenReturn(new ResourceLinks.RepositoryLinks(uriInfo));
|
lenient().when(resourceLinks.repository()).thenReturn(new ResourceLinks.RepositoryLinks(pathInfo));
|
||||||
when(resourceLinks.incoming()).thenReturn(new ResourceLinks.IncomingLinks(uriInfo));
|
lenient().when(resourceLinks.incoming()).thenReturn(new ResourceLinks.IncomingLinks(pathInfo));
|
||||||
when(resourceLinks.repositoryCollection()).thenReturn(new ResourceLinks.RepositoryCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.repositoryCollection()).thenReturn(new ResourceLinks.RepositoryCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.tag()).thenReturn(new ResourceLinks.TagCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.tag()).thenReturn(new ResourceLinks.TagCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.branchCollection()).thenReturn(new ResourceLinks.BranchCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.branchCollection()).thenReturn(new ResourceLinks.BranchCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.changeset()).thenReturn(new ResourceLinks.ChangesetLinks(uriInfo));
|
lenient().when(resourceLinks.changeset()).thenReturn(new ResourceLinks.ChangesetLinks(pathInfo));
|
||||||
when(resourceLinks.fileHistory()).thenReturn(new ResourceLinks.FileHistoryLinks(uriInfo));
|
lenient().when(resourceLinks.fileHistory()).thenReturn(new ResourceLinks.FileHistoryLinks(pathInfo));
|
||||||
when(resourceLinks.source()).thenReturn(new ResourceLinks.SourceLinks(uriInfo));
|
lenient().when(resourceLinks.source()).thenReturn(new ResourceLinks.SourceLinks(pathInfo));
|
||||||
when(resourceLinks.repositoryPermission()).thenReturn(new ResourceLinks.RepositoryPermissionLinks(uriInfo));
|
lenient().when(resourceLinks.repositoryPermission()).thenReturn(new ResourceLinks.RepositoryPermissionLinks(pathInfo));
|
||||||
when(resourceLinks.config()).thenReturn(new ResourceLinks.ConfigLinks(uriInfo));
|
lenient().when(resourceLinks.config()).thenReturn(new ResourceLinks.ConfigLinks(pathInfo));
|
||||||
when(resourceLinks.branch()).thenReturn(new ResourceLinks.BranchLinks(uriInfo));
|
lenient().when(resourceLinks.branch()).thenReturn(new ResourceLinks.BranchLinks(pathInfo));
|
||||||
when(resourceLinks.diff()).thenReturn(new ResourceLinks.DiffLinks(uriInfo));
|
lenient().when(resourceLinks.diff()).thenReturn(new ResourceLinks.DiffLinks(pathInfo));
|
||||||
when(resourceLinks.modifications()).thenReturn(new ResourceLinks.ModificationsLinks(uriInfo));
|
lenient().when(resourceLinks.modifications()).thenReturn(new ResourceLinks.ModificationsLinks(pathInfo));
|
||||||
when(resourceLinks.repositoryType()).thenReturn(new ResourceLinks.RepositoryTypeLinks(uriInfo));
|
lenient().when(resourceLinks.repositoryType()).thenReturn(new ResourceLinks.RepositoryTypeLinks(pathInfo));
|
||||||
when(resourceLinks.repositoryTypeCollection()).thenReturn(new ResourceLinks.RepositoryTypeCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.repositoryTypeCollection()).thenReturn(new ResourceLinks.RepositoryTypeCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.installedPluginCollection()).thenReturn(new ResourceLinks.InstalledPluginCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.installedPluginCollection()).thenReturn(new ResourceLinks.InstalledPluginCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.availablePluginCollection()).thenReturn(new ResourceLinks.AvailablePluginCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.availablePluginCollection()).thenReturn(new ResourceLinks.AvailablePluginCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.pendingPluginCollection()).thenReturn(new ResourceLinks.PendingPluginCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.pendingPluginCollection()).thenReturn(new ResourceLinks.PendingPluginCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.installedPlugin()).thenReturn(new ResourceLinks.InstalledPluginLinks(uriInfo));
|
lenient().when(resourceLinks.installedPlugin()).thenReturn(new ResourceLinks.InstalledPluginLinks(pathInfo));
|
||||||
when(resourceLinks.availablePlugin()).thenReturn(new ResourceLinks.AvailablePluginLinks(uriInfo));
|
lenient().when(resourceLinks.availablePlugin()).thenReturn(new ResourceLinks.AvailablePluginLinks(pathInfo));
|
||||||
when(resourceLinks.uiPluginCollection()).thenReturn(new ResourceLinks.UIPluginCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.uiPluginCollection()).thenReturn(new ResourceLinks.UIPluginCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.uiPlugin()).thenReturn(new ResourceLinks.UIPluginLinks(uriInfo));
|
lenient().when(resourceLinks.uiPlugin()).thenReturn(new ResourceLinks.UIPluginLinks(pathInfo));
|
||||||
when(resourceLinks.authentication()).thenReturn(new ResourceLinks.AuthenticationLinks(uriInfo));
|
lenient().when(resourceLinks.authentication()).thenReturn(new ResourceLinks.AuthenticationLinks(pathInfo));
|
||||||
when(resourceLinks.index()).thenReturn(new ResourceLinks.IndexLinks(uriInfo));
|
lenient().when(resourceLinks.index()).thenReturn(new ResourceLinks.IndexLinks(pathInfo));
|
||||||
when(resourceLinks.permissions()).thenReturn(new ResourceLinks.PermissionsLinks(uriInfo));
|
lenient().when(resourceLinks.permissions()).thenReturn(new ResourceLinks.PermissionsLinks(pathInfo));
|
||||||
when(resourceLinks.repositoryVerbs()).thenReturn(new ResourceLinks.RepositoryVerbLinks(uriInfo));
|
lenient().when(resourceLinks.repositoryVerbs()).thenReturn(new ResourceLinks.RepositoryVerbLinks(pathInfo));
|
||||||
when(resourceLinks.repositoryRole()).thenReturn(new ResourceLinks.RepositoryRoleLinks(uriInfo));
|
lenient().when(resourceLinks.repositoryRole()).thenReturn(new ResourceLinks.RepositoryRoleLinks(pathInfo));
|
||||||
when(resourceLinks.repositoryRoleCollection()).thenReturn(new ResourceLinks.RepositoryRoleCollectionLinks(uriInfo));
|
lenient().when(resourceLinks.repositoryRoleCollection()).thenReturn(new ResourceLinks.RepositoryRoleCollectionLinks(pathInfo));
|
||||||
when(resourceLinks.namespaceStrategies()).thenReturn(new ResourceLinks.NamespaceStrategiesLinks(uriInfo));
|
lenient().when(resourceLinks.namespaceStrategies()).thenReturn(new ResourceLinks.NamespaceStrategiesLinks(pathInfo));
|
||||||
|
lenient().when(resourceLinks.annotate()).thenReturn(new ResourceLinks.AnnotateLinks(pathInfo));
|
||||||
|
|
||||||
return resourceLinks;
|
return resourceLinks;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.google.inject.util.Providers;
|
import com.google.inject.util.Providers;
|
||||||
@@ -74,8 +74,7 @@ public class SourceRootResourceTest extends RepositoryTestBase {
|
|||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
||||||
when(service.getBrowseCommand()).thenReturn(browseCommandBuilder);
|
when(service.getBrowseCommand()).thenReturn(browseCommandBuilder);
|
||||||
|
|
||||||
SourceRootResource sourceRootResource = new SourceRootResource(serviceFactory, browserResultToFileObjectDtoMapper);
|
sourceRootResource = new SourceRootResource(serviceFactory, browserResultToFileObjectDtoMapper);
|
||||||
super.sourceRootResource = Providers.of(sourceRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
import com.google.inject.util.Providers;
|
import com.google.inject.util.Providers;
|
||||||
@@ -84,9 +84,6 @@ public class TagRootResourceTest extends RepositoryTestBase {
|
|||||||
@InjectMocks
|
@InjectMocks
|
||||||
private TagToTagDtoMapperImpl tagToTagDtoMapper;
|
private TagToTagDtoMapperImpl tagToTagDtoMapper;
|
||||||
|
|
||||||
private TagRootResource tagRootResource;
|
|
||||||
|
|
||||||
|
|
||||||
private final Subject subject = mock(Subject.class);
|
private final Subject subject = mock(Subject.class);
|
||||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||||
|
|
||||||
@@ -95,7 +92,6 @@ public class TagRootResourceTest extends RepositoryTestBase {
|
|||||||
public void prepareEnvironment() throws Exception {
|
public void prepareEnvironment() throws Exception {
|
||||||
tagCollectionToDtoMapper = new TagCollectionToDtoMapper(resourceLinks, tagToTagDtoMapper);
|
tagCollectionToDtoMapper = new TagCollectionToDtoMapper(resourceLinks, tagToTagDtoMapper);
|
||||||
tagRootResource = new TagRootResource(serviceFactory, tagCollectionToDtoMapper, tagToTagDtoMapper);
|
tagRootResource = new TagRootResource(serviceFactory, tagCollectionToDtoMapper, tagToTagDtoMapper);
|
||||||
super.tagRootResource = Providers.of(tagRootResource);
|
|
||||||
dispatcher.addSingletonResource(getRepositoryRootResource());
|
dispatcher.addSingletonResource(getRepositoryRootResource());
|
||||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
||||||
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
||||||
|
|||||||
154
yarn.lock
154
yarn.lock
@@ -54,6 +54,16 @@
|
|||||||
semver "^5.4.1"
|
semver "^5.4.1"
|
||||||
source-map "^0.5.0"
|
source-map "^0.5.0"
|
||||||
|
|
||||||
|
"@babel/generator@^7.10.1":
|
||||||
|
version "7.10.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9"
|
||||||
|
integrity sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.10.2"
|
||||||
|
jsesc "^2.5.1"
|
||||||
|
lodash "^4.17.13"
|
||||||
|
source-map "^0.5.0"
|
||||||
|
|
||||||
"@babel/generator@^7.4.0", "@babel/generator@^7.9.6":
|
"@babel/generator@^7.4.0", "@babel/generator@^7.9.6":
|
||||||
version "7.9.6"
|
version "7.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.6.tgz#5408c82ac5de98cda0d77d8124e99fa1f2170a43"
|
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.6.tgz#5408c82ac5de98cda0d77d8124e99fa1f2170a43"
|
||||||
@@ -145,6 +155,15 @@
|
|||||||
"@babel/traverse" "^7.8.3"
|
"@babel/traverse" "^7.8.3"
|
||||||
"@babel/types" "^7.8.3"
|
"@babel/types" "^7.8.3"
|
||||||
|
|
||||||
|
"@babel/helper-function-name@^7.10.1":
|
||||||
|
version "7.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz#92bd63829bfc9215aca9d9defa85f56b539454f4"
|
||||||
|
integrity sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-get-function-arity" "^7.10.1"
|
||||||
|
"@babel/template" "^7.10.1"
|
||||||
|
"@babel/types" "^7.10.1"
|
||||||
|
|
||||||
"@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5":
|
"@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5":
|
||||||
version "7.9.5"
|
version "7.9.5"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c"
|
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c"
|
||||||
@@ -154,6 +173,13 @@
|
|||||||
"@babel/template" "^7.8.3"
|
"@babel/template" "^7.8.3"
|
||||||
"@babel/types" "^7.9.5"
|
"@babel/types" "^7.9.5"
|
||||||
|
|
||||||
|
"@babel/helper-get-function-arity@^7.10.1":
|
||||||
|
version "7.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d"
|
||||||
|
integrity sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.10.1"
|
||||||
|
|
||||||
"@babel/helper-get-function-arity@^7.8.3":
|
"@babel/helper-get-function-arity@^7.8.3":
|
||||||
version "7.8.3"
|
version "7.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
|
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
|
||||||
@@ -248,6 +274,13 @@
|
|||||||
"@babel/template" "^7.8.3"
|
"@babel/template" "^7.8.3"
|
||||||
"@babel/types" "^7.8.3"
|
"@babel/types" "^7.8.3"
|
||||||
|
|
||||||
|
"@babel/helper-split-export-declaration@^7.10.1":
|
||||||
|
version "7.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f"
|
||||||
|
integrity sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.10.1"
|
||||||
|
|
||||||
"@babel/helper-split-export-declaration@^7.8.3":
|
"@babel/helper-split-export-declaration@^7.8.3":
|
||||||
version "7.8.3"
|
version "7.8.3"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
|
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
|
||||||
@@ -951,7 +984,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/template@^7.3.3":
|
"@babel/template@^7.10.1", "@babel/template@^7.3.3":
|
||||||
version "7.10.1"
|
version "7.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
|
||||||
integrity sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==
|
integrity sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==
|
||||||
@@ -969,7 +1002,7 @@
|
|||||||
"@babel/parser" "^7.8.6"
|
"@babel/parser" "^7.8.6"
|
||||||
"@babel/types" "^7.8.6"
|
"@babel/types" "^7.8.6"
|
||||||
|
|
||||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.9.6":
|
"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.9.6":
|
||||||
version "7.9.6"
|
version "7.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.6.tgz#5540d7577697bf619cc57b92aa0f1c231a94f442"
|
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.6.tgz#5540d7577697bf619cc57b92aa0f1c231a94f442"
|
||||||
integrity sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==
|
integrity sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==
|
||||||
@@ -984,6 +1017,21 @@
|
|||||||
globals "^11.1.0"
|
globals "^11.1.0"
|
||||||
lodash "^4.17.13"
|
lodash "^4.17.13"
|
||||||
|
|
||||||
|
"@babel/traverse@^7.4.5":
|
||||||
|
version "7.10.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27"
|
||||||
|
integrity sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/code-frame" "^7.10.1"
|
||||||
|
"@babel/generator" "^7.10.1"
|
||||||
|
"@babel/helper-function-name" "^7.10.1"
|
||||||
|
"@babel/helper-split-export-declaration" "^7.10.1"
|
||||||
|
"@babel/parser" "^7.10.1"
|
||||||
|
"@babel/types" "^7.10.1"
|
||||||
|
debug "^4.1.0"
|
||||||
|
globals "^11.1.0"
|
||||||
|
lodash "^4.17.13"
|
||||||
|
|
||||||
"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5", "@babel/types@^7.9.6":
|
"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5", "@babel/types@^7.9.6":
|
||||||
version "7.9.6"
|
version "7.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.6.tgz#2c5502b427251e9de1bd2dff95add646d95cc9f7"
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.6.tgz#2c5502b427251e9de1bd2dff95add646d95cc9f7"
|
||||||
@@ -993,7 +1041,7 @@
|
|||||||
lodash "^4.17.13"
|
lodash "^4.17.13"
|
||||||
to-fast-properties "^2.0.0"
|
to-fast-properties "^2.0.0"
|
||||||
|
|
||||||
"@babel/types@^7.10.1", "@babel/types@^7.3.3":
|
"@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.3.3":
|
||||||
version "7.10.2"
|
version "7.10.2"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d"
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d"
|
||||||
integrity sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==
|
integrity sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==
|
||||||
@@ -1068,7 +1116,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.6.6.tgz#62266c5f0eac6941fece302abad69f2ee7e25e44"
|
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.6.6.tgz#62266c5f0eac6941fece302abad69f2ee7e25e44"
|
||||||
integrity sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ==
|
integrity sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ==
|
||||||
|
|
||||||
"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.1":
|
"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.8":
|
||||||
version "0.8.8"
|
version "0.8.8"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
|
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
|
||||||
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
|
||||||
@@ -1129,7 +1177,7 @@
|
|||||||
"@emotion/styled-base" "^10.0.27"
|
"@emotion/styled-base" "^10.0.27"
|
||||||
babel-plugin-emotion "^10.0.27"
|
babel-plugin-emotion "^10.0.27"
|
||||||
|
|
||||||
"@emotion/stylis@0.8.5":
|
"@emotion/stylis@0.8.5", "@emotion/stylis@^0.8.4":
|
||||||
version "0.8.5"
|
version "0.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
|
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
|
||||||
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
|
integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
|
||||||
@@ -1139,7 +1187,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.7.1.tgz#50f63225e712d99e2b2b39c19c70fff023793ca5"
|
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.7.1.tgz#50f63225e712d99e2b2b39c19c70fff023793ca5"
|
||||||
integrity sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ==
|
integrity sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ==
|
||||||
|
|
||||||
"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.0":
|
"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4":
|
||||||
version "0.7.5"
|
version "0.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||||
@@ -3260,10 +3308,10 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@storybook/addon-storyshots" "*"
|
"@storybook/addon-storyshots" "*"
|
||||||
|
|
||||||
"@types/styled-components@^4.1.19":
|
"@types/styled-components@^5.1.0":
|
||||||
version "4.4.3"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-4.4.3.tgz#74dd00ad760845a98890a8539361d8afc32059de"
|
resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-5.1.0.tgz#24d3412ba5395aa06e14fbc93c52f9454cebd0d6"
|
||||||
integrity sha512-U0udeNOZBfUkJycmGJwmzun0FBt11rZy08weVQmE2xfUNAbX8AGOEWxWna2d+qAUKxKgMlcG+TZT0+K2FfDcnQ==
|
integrity sha512-ZFlLCuwF5r+4Vb7JUmd+Yr2S0UBdBGmI7ctFTgJMypIp3xOHI4LCFVn2dKMvpk6xDB2hLRykrEWMBwJEpUAUIQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/hoist-non-react-statics" "*"
|
"@types/hoist-non-react-statics" "*"
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
@@ -4098,6 +4146,11 @@ babel-code-frame@^6.22.0:
|
|||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
js-tokens "^3.0.2"
|
js-tokens "^3.0.2"
|
||||||
|
|
||||||
|
babel-core@7.0.0-bridge.0:
|
||||||
|
version "7.0.0-bridge.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece"
|
||||||
|
integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==
|
||||||
|
|
||||||
babel-eslint@^10.0.3:
|
babel-eslint@^10.0.3:
|
||||||
version "10.1.0"
|
version "10.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
|
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232"
|
||||||
@@ -5891,14 +5944,14 @@ css-select@^2.0.0:
|
|||||||
domutils "^1.7.0"
|
domutils "^1.7.0"
|
||||||
nth-check "^1.0.2"
|
nth-check "^1.0.2"
|
||||||
|
|
||||||
css-to-react-native@^2.2.2:
|
css-to-react-native@^3.0.0:
|
||||||
version "2.3.2"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.3.2.tgz#e75e2f8f7aa385b4c3611c52b074b70a002f2e7d"
|
resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756"
|
||||||
integrity sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw==
|
integrity sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
camelize "^1.0.0"
|
camelize "^1.0.0"
|
||||||
css-color-keywords "^1.0.0"
|
css-color-keywords "^1.0.0"
|
||||||
postcss-value-parser "^3.3.0"
|
postcss-value-parser "^4.0.2"
|
||||||
|
|
||||||
css-tree@1.0.0-alpha.37:
|
css-tree@1.0.0-alpha.37:
|
||||||
version "1.0.0-alpha.37"
|
version "1.0.0-alpha.37"
|
||||||
@@ -7435,7 +7488,7 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||||
|
|
||||||
fault@^1.0.0, fault@^1.0.2:
|
fault@^1.0.0:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13"
|
resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13"
|
||||||
integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==
|
integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==
|
||||||
@@ -7969,7 +8022,7 @@ gitconfiglocal@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ini "^1.3.2"
|
ini "^1.3.2"
|
||||||
|
|
||||||
gitdiff-parser@^0.1.2:
|
gitdiff-parser@^0.1.2, "gitdiff-parser@https://github.com/scm-manager/gitdiff-parser#617747460280bf4522bb84d217a9064ac8eb6d3d":
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://github.com/scm-manager/gitdiff-parser#617747460280bf4522bb84d217a9064ac8eb6d3d"
|
resolved "https://github.com/scm-manager/gitdiff-parser#617747460280bf4522bb84d217a9064ac8eb6d3d"
|
||||||
|
|
||||||
@@ -8334,7 +8387,7 @@ hoist-non-react-statics@^2.3.1:
|
|||||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
|
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
|
||||||
integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==
|
integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==
|
||||||
|
|
||||||
hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
|
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||||
@@ -9287,11 +9340,6 @@ is-utf8@^0.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
|
||||||
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
|
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
|
||||||
|
|
||||||
is-what@^3.3.1:
|
|
||||||
version "3.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.8.0.tgz#610bc46a524355f2424eb85eedc6ebbbf7e1ff8c"
|
|
||||||
integrity sha512-UKeBoQfV8bjlM4pmx1FLDHdxslW/1mTksEs8ReVsilPmUv5cORd4+2/wFcviI3cUjrLybxCjzc8DnodAzJ/Wrg==
|
|
||||||
|
|
||||||
is-whitespace-character@^1.0.0:
|
is-whitespace-character@^1.0.0:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
|
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
|
||||||
@@ -10775,7 +10823,7 @@ lower-case@^2.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
|
|
||||||
lowlight@^1.13.0:
|
lowlight@1.13.1, lowlight@^1.13.0, lowlight@~1.11.0:
|
||||||
version "1.13.1"
|
version "1.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.13.1.tgz#c4f0e03906ebd23fedf2d258f6ab2f6324cf90eb"
|
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.13.1.tgz#c4f0e03906ebd23fedf2d258f6ab2f6324cf90eb"
|
||||||
integrity sha512-kQ71/T6RksEVz9AlPq07/2m+SU/1kGvt9k39UtvHX760u4SaWakaYH7hYgH5n6sTsCWk4MVYzUzLU59aN5CSmQ==
|
integrity sha512-kQ71/T6RksEVz9AlPq07/2m+SU/1kGvt9k39UtvHX760u4SaWakaYH7hYgH5n6sTsCWk4MVYzUzLU59aN5CSmQ==
|
||||||
@@ -10783,14 +10831,6 @@ lowlight@^1.13.0:
|
|||||||
fault "^1.0.0"
|
fault "^1.0.0"
|
||||||
highlight.js "~9.16.0"
|
highlight.js "~9.16.0"
|
||||||
|
|
||||||
lowlight@~1.11.0:
|
|
||||||
version "1.11.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.11.0.tgz#1304d83005126d4e8b1dc0f07981e9b689ec2efc"
|
|
||||||
integrity sha512-xrGGN6XLL7MbTMdPD6NfWPwY43SNkjf/d0mecSx/CW36fUZTjRHEq0/Cdug3TWKtRXLWi7iMl1eP0olYxj/a4A==
|
|
||||||
dependencies:
|
|
||||||
fault "^1.0.2"
|
|
||||||
highlight.js "~9.13.0"
|
|
||||||
|
|
||||||
lru-cache@^5.1.1:
|
lru-cache@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||||
@@ -11019,13 +11059,6 @@ meow@^7.0.0:
|
|||||||
type-fest "^0.13.1"
|
type-fest "^0.13.1"
|
||||||
yargs-parser "^18.1.3"
|
yargs-parser "^18.1.3"
|
||||||
|
|
||||||
merge-anything@^2.2.4:
|
|
||||||
version "2.4.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-2.4.4.tgz#6226b2ac3d3d3fc5fb9e8d23aa400df25f98fdf0"
|
|
||||||
integrity sha512-l5XlriUDJKQT12bH+rVhAHjwIuXWdAIecGwsYjv2LJo+dA1AeRTmeQS+3QBpO6lEthBMDi2IUMpLC1yyRvGlwQ==
|
|
||||||
dependencies:
|
|
||||||
is-what "^3.3.1"
|
|
||||||
|
|
||||||
merge-deep@^3.0.2:
|
merge-deep@^3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2"
|
resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2"
|
||||||
@@ -12783,7 +12816,7 @@ postcss-unique-selectors@^4.0.1:
|
|||||||
postcss "^7.0.0"
|
postcss "^7.0.0"
|
||||||
uniqs "^2.0.0"
|
uniqs "^2.0.0"
|
||||||
|
|
||||||
postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0:
|
postcss-value-parser@^3.0.0:
|
||||||
version "3.3.1"
|
version "3.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
|
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
|
||||||
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
|
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
|
||||||
@@ -12877,7 +12910,7 @@ pretty-hrtime@^1.0.3:
|
|||||||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||||
integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
|
integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
|
||||||
|
|
||||||
prismjs@^1.8.4:
|
prismjs@^1.16.0, prismjs@^1.8.4:
|
||||||
version "1.20.0"
|
version "1.20.0"
|
||||||
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.20.0.tgz#9b685fc480a3514ee7198eac6a3bf5024319ff03"
|
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.20.0.tgz#9b685fc480a3514ee7198eac6a3bf5024319ff03"
|
||||||
integrity sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ==
|
integrity sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ==
|
||||||
@@ -12975,7 +13008,7 @@ prop-types-exact@^1.2.0:
|
|||||||
object.assign "^4.1.0"
|
object.assign "^4.1.0"
|
||||||
reflect.ownkeys "^0.2.0"
|
reflect.ownkeys "^0.2.0"
|
||||||
|
|
||||||
prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||||
version "15.7.2"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||||
@@ -13492,6 +13525,16 @@ react-syntax-highlighter@^11.0.2:
|
|||||||
prismjs "^1.8.4"
|
prismjs "^1.8.4"
|
||||||
refractor "^2.4.1"
|
refractor "^2.4.1"
|
||||||
|
|
||||||
|
"react-syntax-highlighter@https://github.com/conorhastings/react-syntax-highlighter#08bcf49b1aa7877ce94f7208e73dfa6bef8b26e7":
|
||||||
|
version "12.0.2"
|
||||||
|
resolved "https://github.com/conorhastings/react-syntax-highlighter#08bcf49b1aa7877ce94f7208e73dfa6bef8b26e7"
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.3.1"
|
||||||
|
highlight.js "~9.13.0"
|
||||||
|
lowlight "~1.11.0"
|
||||||
|
prismjs "^1.16.0"
|
||||||
|
refractor "^2.10.1"
|
||||||
|
|
||||||
react-test-renderer@^16.0.0-0, react-test-renderer@^16.10.2:
|
react-test-renderer@^16.0.0-0, react-test-renderer@^16.10.2:
|
||||||
version "16.13.1"
|
version "16.13.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1"
|
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1"
|
||||||
@@ -13804,7 +13847,7 @@ reflect.ownkeys@^0.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460"
|
resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460"
|
||||||
integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=
|
integrity sha1-dJrO7H8/34tj+SegSAnpDFwLNGA=
|
||||||
|
|
||||||
refractor@^2.4.1:
|
refractor@^2.10.1, refractor@^2.4.1:
|
||||||
version "2.10.1"
|
version "2.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e"
|
resolved "https://registry.yarnpkg.com/refractor/-/refractor-2.10.1.tgz#166c32f114ed16fd96190ad21d5193d3afc7d34e"
|
||||||
integrity sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw==
|
integrity sha512-Xh9o7hQiQlDbxo5/XkOX6H+x/q8rmlmZKr97Ie1Q8ZM32IRRd3B/UxuA/yXDW79DBSXGWxm2yRTbcTVmAciJRw==
|
||||||
@@ -15138,23 +15181,20 @@ style-loader@^1.0.0:
|
|||||||
loader-utils "^2.0.0"
|
loader-utils "^2.0.0"
|
||||||
schema-utils "^2.6.6"
|
schema-utils "^2.6.6"
|
||||||
|
|
||||||
styled-components@^4.4.0:
|
styled-components@^5.1.0:
|
||||||
version "4.4.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.4.1.tgz#e0631e889f01db67df4de576fedaca463f05c2f2"
|
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.1.1.tgz#96dfb02a8025794960863b9e8e365e3b6be5518d"
|
||||||
integrity sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g==
|
integrity sha512-1ps8ZAYu2Husx+Vz8D+MvXwEwvMwFv+hqqUwhNlDN5ybg6A+3xyW1ECrAgywhvXapNfXiz79jJyU0x22z0FFTg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/helper-module-imports" "^7.0.0"
|
"@babel/helper-module-imports" "^7.0.0"
|
||||||
"@babel/traverse" "^7.0.0"
|
"@babel/traverse" "^7.4.5"
|
||||||
"@emotion/is-prop-valid" "^0.8.1"
|
"@emotion/is-prop-valid" "^0.8.8"
|
||||||
"@emotion/unitless" "^0.7.0"
|
"@emotion/stylis" "^0.8.4"
|
||||||
|
"@emotion/unitless" "^0.7.4"
|
||||||
babel-plugin-styled-components ">= 1"
|
babel-plugin-styled-components ">= 1"
|
||||||
css-to-react-native "^2.2.2"
|
css-to-react-native "^3.0.0"
|
||||||
memoize-one "^5.0.0"
|
hoist-non-react-statics "^3.0.0"
|
||||||
merge-anything "^2.2.4"
|
shallowequal "^1.1.0"
|
||||||
prop-types "^15.5.4"
|
|
||||||
react-is "^16.6.0"
|
|
||||||
stylis "^3.5.0"
|
|
||||||
stylis-rule-sheet "^0.0.10"
|
|
||||||
supports-color "^5.5.0"
|
supports-color "^5.5.0"
|
||||||
|
|
||||||
stylehacks@^4.0.0:
|
stylehacks@^4.0.0:
|
||||||
|
|||||||
Reference in New Issue
Block a user