mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-07 22:15:45 +01:00
re integrate @scm-manager/ui-types into @scm-manager/ui-components to reduce maven modules
This commit is contained in:
1
pom.xml
1
pom.xml
@@ -69,6 +69,7 @@
|
|||||||
<module>scm-annotation-processor</module>
|
<module>scm-annotation-processor</module>
|
||||||
<module>scm-core</module>
|
<module>scm-core</module>
|
||||||
<module>scm-test</module>
|
<module>scm-test</module>
|
||||||
|
<module>scm-ui-components</module>
|
||||||
<module>scm-plugins</module>
|
<module>scm-plugins</module>
|
||||||
<module>scm-dao-xml</module>
|
<module>scm-dao-xml</module>
|
||||||
<module>scm-ui</module>
|
<module>scm-ui</module>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
.*/node_modules/module-deps/.*
|
.*/node_modules/module-deps/.*
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
../ui-types/.*
|
|
||||||
|
|
||||||
[libs]
|
[libs]
|
||||||
|
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
"@scm-manager/ui-extensions": "^0.0.7"
|
"@scm-manager/ui-extensions": "^0.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@scm-manager/ui-bundler": "^0.0.7"
|
"@scm-manager/ui-bundler": "^0.0.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,33 @@
|
|||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.sdorra</groupId>
|
||||||
|
<artifactId>buildfrontend-maven-plugin</artifactId>
|
||||||
|
<version>2.1.0</version>
|
||||||
|
<configuration>
|
||||||
|
<node>
|
||||||
|
<version>8.11.4</version>
|
||||||
|
</node>
|
||||||
|
<pkgManager>
|
||||||
|
<type>YARN</type>
|
||||||
|
<version>1.9.4</version>
|
||||||
|
</pkgManager>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>link-components</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>install-link</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<pkg>@scm-manager/ui-components</pkg>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
|
import { Image } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
};
|
};
|
||||||
@@ -7,8 +8,7 @@ type Props = {
|
|||||||
class GitAvatar extends React.Component<Props> {
|
class GitAvatar extends React.Component<Props> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// TODO we have to use Image from ui-components
|
return <Image src="/images/git-logo.png" alt="Git Logo" />;
|
||||||
return <img src="/scm/images/git-logo.png" alt="Git Logo" />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
//@flow
|
//@flow
|
||||||
import React from 'react';
|
import React from "react";
|
||||||
|
import { Repository } from "@scm-manager/ui-types";
|
||||||
|
|
||||||
// TODO flow types ???
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Object
|
repository: Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProtocolInformation extends React.Component<Props> {
|
class ProtocolInformation extends React.Component<Props> {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
//@flow
|
||||||
import { binder } from "@scm-manager/ui-extensions";
|
import { binder } from "@scm-manager/ui-extensions";
|
||||||
import ProtocolInformation from './ProtocolInformation';
|
import ProtocolInformation from "./ProtocolInformation";
|
||||||
import GitAvatar from './GitAvatar';
|
import GitAvatar from "./GitAvatar";
|
||||||
|
|
||||||
const gitPredicate = (props: Object) => {
|
const gitPredicate = (props: Object) => {
|
||||||
return props.repository && props.repository.type === "git";
|
return props.repository && props.repository.type === "git";
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
6
scm-ui-components/.babelrc
Normal file
6
scm-ui-components/.babelrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"],
|
||||||
|
"plugins": [
|
||||||
|
"@babel/plugin-proposal-class-properties"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
scm-ui-components/.eslintrc
Normal file
3
scm-ui-components/.eslintrc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "@scm-manager/eslint-config"
|
||||||
|
}
|
||||||
8
scm-ui-components/.flowconfig
Normal file
8
scm-ui-components/.flowconfig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[ignore]
|
||||||
|
.*/node_modules/module-deps/.*
|
||||||
|
|
||||||
|
[include]
|
||||||
|
|
||||||
|
[libs]
|
||||||
|
|
||||||
|
[options]
|
||||||
23
scm-ui-components/flow-typed/npm/classnames_v2.x.x.js
vendored
Normal file
23
scm-ui-components/flow-typed/npm/classnames_v2.x.x.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// flow-typed signature: cf86673cc32d185bdab1d2ea90578d37
|
||||||
|
// flow-typed version: 614bf49aa8/classnames_v2.x.x/flow_>=v0.25.x
|
||||||
|
|
||||||
|
type $npm$classnames$Classes =
|
||||||
|
| string
|
||||||
|
| { [className: string]: * }
|
||||||
|
| false
|
||||||
|
| void
|
||||||
|
| null;
|
||||||
|
|
||||||
|
declare module "classnames" {
|
||||||
|
declare module.exports: (
|
||||||
|
...classes: Array<$npm$classnames$Classes | $npm$classnames$Classes[]>
|
||||||
|
) => string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "classnames/bind" {
|
||||||
|
declare module.exports: $Exports<"classnames">;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "classnames/dedupe" {
|
||||||
|
declare module.exports: $Exports<"classnames">;
|
||||||
|
}
|
||||||
1108
scm-ui-components/flow-typed/npm/jest_v23.x.x.js
vendored
Normal file
1108
scm-ui-components/flow-typed/npm/jest_v23.x.x.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
331
scm-ui-components/flow-typed/npm/moment_v2.3.x.js
vendored
Normal file
331
scm-ui-components/flow-typed/npm/moment_v2.3.x.js
vendored
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
// flow-typed signature: 23b805356f90ad9384dd88489654e380
|
||||||
|
// flow-typed version: e9374c5fe9/moment_v2.3.x/flow_>=v0.25.x
|
||||||
|
|
||||||
|
type moment$MomentOptions = {
|
||||||
|
y?: number | string,
|
||||||
|
year?: number | string,
|
||||||
|
years?: number | string,
|
||||||
|
M?: number | string,
|
||||||
|
month?: number | string,
|
||||||
|
months?: number | string,
|
||||||
|
d?: number | string,
|
||||||
|
day?: number | string,
|
||||||
|
days?: number | string,
|
||||||
|
date?: number | string,
|
||||||
|
h?: number | string,
|
||||||
|
hour?: number | string,
|
||||||
|
hours?: number | string,
|
||||||
|
m?: number | string,
|
||||||
|
minute?: number | string,
|
||||||
|
minutes?: number | string,
|
||||||
|
s?: number | string,
|
||||||
|
second?: number | string,
|
||||||
|
seconds?: number | string,
|
||||||
|
ms?: number | string,
|
||||||
|
millisecond?: number | string,
|
||||||
|
milliseconds?: number | string
|
||||||
|
};
|
||||||
|
|
||||||
|
type moment$MomentObject = {
|
||||||
|
years: number,
|
||||||
|
months: number,
|
||||||
|
date: number,
|
||||||
|
hours: number,
|
||||||
|
minutes: number,
|
||||||
|
seconds: number,
|
||||||
|
milliseconds: number
|
||||||
|
};
|
||||||
|
|
||||||
|
type moment$MomentCreationData = {
|
||||||
|
input: string,
|
||||||
|
format: string,
|
||||||
|
locale: Object,
|
||||||
|
isUTC: boolean,
|
||||||
|
strict: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
type moment$CalendarFormat = string | ((moment: moment$Moment) => string);
|
||||||
|
|
||||||
|
type moment$CalendarFormats = {
|
||||||
|
sameDay?: moment$CalendarFormat,
|
||||||
|
nextDay?: moment$CalendarFormat,
|
||||||
|
nextWeek?: moment$CalendarFormat,
|
||||||
|
lastDay?: moment$CalendarFormat,
|
||||||
|
lastWeek?: moment$CalendarFormat,
|
||||||
|
sameElse?: moment$CalendarFormat
|
||||||
|
};
|
||||||
|
|
||||||
|
declare class moment$LocaleData {
|
||||||
|
months(moment: moment$Moment): string,
|
||||||
|
monthsShort(moment: moment$Moment): string,
|
||||||
|
monthsParse(month: string): number,
|
||||||
|
weekdays(moment: moment$Moment): string,
|
||||||
|
weekdaysShort(moment: moment$Moment): string,
|
||||||
|
weekdaysMin(moment: moment$Moment): string,
|
||||||
|
weekdaysParse(weekDay: string): number,
|
||||||
|
longDateFormat(dateFormat: string): string,
|
||||||
|
isPM(date: string): boolean,
|
||||||
|
meridiem(hours: number, minutes: number, isLower: boolean): string,
|
||||||
|
calendar(
|
||||||
|
key:
|
||||||
|
| "sameDay"
|
||||||
|
| "nextDay"
|
||||||
|
| "lastDay"
|
||||||
|
| "nextWeek"
|
||||||
|
| "prevWeek"
|
||||||
|
| "sameElse",
|
||||||
|
moment: moment$Moment
|
||||||
|
): string,
|
||||||
|
relativeTime(
|
||||||
|
number: number,
|
||||||
|
withoutSuffix: boolean,
|
||||||
|
key: "s" | "m" | "mm" | "h" | "hh" | "d" | "dd" | "M" | "MM" | "y" | "yy",
|
||||||
|
isFuture: boolean
|
||||||
|
): string,
|
||||||
|
pastFuture(diff: any, relTime: string): string,
|
||||||
|
ordinal(number: number): string,
|
||||||
|
preparse(str: string): any,
|
||||||
|
postformat(str: string): any,
|
||||||
|
week(moment: moment$Moment): string,
|
||||||
|
invalidDate(): string,
|
||||||
|
firstDayOfWeek(): number,
|
||||||
|
firstDayOfYear(): number
|
||||||
|
}
|
||||||
|
declare class moment$MomentDuration {
|
||||||
|
humanize(suffix?: boolean): string,
|
||||||
|
milliseconds(): number,
|
||||||
|
asMilliseconds(): number,
|
||||||
|
seconds(): number,
|
||||||
|
asSeconds(): number,
|
||||||
|
minutes(): number,
|
||||||
|
asMinutes(): number,
|
||||||
|
hours(): number,
|
||||||
|
asHours(): number,
|
||||||
|
days(): number,
|
||||||
|
asDays(): number,
|
||||||
|
months(): number,
|
||||||
|
asWeeks(): number,
|
||||||
|
weeks(): number,
|
||||||
|
asMonths(): number,
|
||||||
|
years(): number,
|
||||||
|
asYears(): number,
|
||||||
|
add(value: number | moment$MomentDuration | Object, unit?: string): this,
|
||||||
|
subtract(value: number | moment$MomentDuration | Object, unit?: string): this,
|
||||||
|
as(unit: string): number,
|
||||||
|
get(unit: string): number,
|
||||||
|
toJSON(): string,
|
||||||
|
toISOString(): string,
|
||||||
|
isValid(): boolean
|
||||||
|
}
|
||||||
|
declare class moment$Moment {
|
||||||
|
static ISO_8601: string,
|
||||||
|
static (
|
||||||
|
string?: string,
|
||||||
|
format?: string | Array<string>,
|
||||||
|
strict?: boolean
|
||||||
|
): moment$Moment,
|
||||||
|
static (
|
||||||
|
string?: string,
|
||||||
|
format?: string | Array<string>,
|
||||||
|
locale?: string,
|
||||||
|
strict?: boolean
|
||||||
|
): moment$Moment,
|
||||||
|
static (
|
||||||
|
initDate: ?Object | number | Date | Array<number> | moment$Moment | string
|
||||||
|
): moment$Moment,
|
||||||
|
static unix(seconds: number): moment$Moment,
|
||||||
|
static utc(): moment$Moment,
|
||||||
|
static utc(number: number | Array<number>): moment$Moment,
|
||||||
|
static utc(
|
||||||
|
str: string,
|
||||||
|
str2?: string | Array<string>,
|
||||||
|
str3?: string
|
||||||
|
): moment$Moment,
|
||||||
|
static utc(moment: moment$Moment): moment$Moment,
|
||||||
|
static utc(date: Date): moment$Moment,
|
||||||
|
static parseZone(): moment$Moment,
|
||||||
|
static parseZone(rawDate: string): moment$Moment,
|
||||||
|
static parseZone(
|
||||||
|
rawDate: string,
|
||||||
|
format: string | Array<string>
|
||||||
|
): moment$Moment,
|
||||||
|
static parseZone(
|
||||||
|
rawDate: string,
|
||||||
|
format: string,
|
||||||
|
strict: boolean
|
||||||
|
): moment$Moment,
|
||||||
|
static parseZone(
|
||||||
|
rawDate: string,
|
||||||
|
format: string,
|
||||||
|
locale: string,
|
||||||
|
strict: boolean
|
||||||
|
): moment$Moment,
|
||||||
|
isValid(): boolean,
|
||||||
|
invalidAt(): 0 | 1 | 2 | 3 | 4 | 5 | 6,
|
||||||
|
creationData(): moment$MomentCreationData,
|
||||||
|
millisecond(number: number): this,
|
||||||
|
milliseconds(number: number): this,
|
||||||
|
millisecond(): number,
|
||||||
|
milliseconds(): number,
|
||||||
|
second(number: number): this,
|
||||||
|
seconds(number: number): this,
|
||||||
|
second(): number,
|
||||||
|
seconds(): number,
|
||||||
|
minute(number: number): this,
|
||||||
|
minutes(number: number): this,
|
||||||
|
minute(): number,
|
||||||
|
minutes(): number,
|
||||||
|
hour(number: number): this,
|
||||||
|
hours(number: number): this,
|
||||||
|
hour(): number,
|
||||||
|
hours(): number,
|
||||||
|
date(number: number): this,
|
||||||
|
dates(number: number): this,
|
||||||
|
date(): number,
|
||||||
|
dates(): number,
|
||||||
|
day(day: number | string): this,
|
||||||
|
days(day: number | string): this,
|
||||||
|
day(): number,
|
||||||
|
days(): number,
|
||||||
|
weekday(number: number): this,
|
||||||
|
weekday(): number,
|
||||||
|
isoWeekday(number: number): this,
|
||||||
|
isoWeekday(): number,
|
||||||
|
dayOfYear(number: number): this,
|
||||||
|
dayOfYear(): number,
|
||||||
|
week(number: number): this,
|
||||||
|
weeks(number: number): this,
|
||||||
|
week(): number,
|
||||||
|
weeks(): number,
|
||||||
|
isoWeek(number: number): this,
|
||||||
|
isoWeeks(number: number): this,
|
||||||
|
isoWeek(): number,
|
||||||
|
isoWeeks(): number,
|
||||||
|
month(number: number): this,
|
||||||
|
months(number: number): this,
|
||||||
|
month(): number,
|
||||||
|
months(): number,
|
||||||
|
quarter(number: number): this,
|
||||||
|
quarter(): number,
|
||||||
|
year(number: number): this,
|
||||||
|
years(number: number): this,
|
||||||
|
year(): number,
|
||||||
|
years(): number,
|
||||||
|
weekYear(number: number): this,
|
||||||
|
weekYear(): number,
|
||||||
|
isoWeekYear(number: number): this,
|
||||||
|
isoWeekYear(): number,
|
||||||
|
weeksInYear(): number,
|
||||||
|
isoWeeksInYear(): number,
|
||||||
|
get(string: string): number,
|
||||||
|
set(unit: string, value: number): this,
|
||||||
|
set(options: { [unit: string]: number }): this,
|
||||||
|
static max(...dates: Array<moment$Moment>): moment$Moment,
|
||||||
|
static max(dates: Array<moment$Moment>): moment$Moment,
|
||||||
|
static min(...dates: Array<moment$Moment>): moment$Moment,
|
||||||
|
static min(dates: Array<moment$Moment>): moment$Moment,
|
||||||
|
add(
|
||||||
|
value: number | moment$MomentDuration | moment$Moment | Object,
|
||||||
|
unit?: string
|
||||||
|
): this,
|
||||||
|
subtract(
|
||||||
|
value: number | moment$MomentDuration | moment$Moment | string | Object,
|
||||||
|
unit?: string
|
||||||
|
): this,
|
||||||
|
startOf(unit: string): this,
|
||||||
|
endOf(unit: string): this,
|
||||||
|
local(): this,
|
||||||
|
utc(): this,
|
||||||
|
utcOffset(
|
||||||
|
offset: number | string,
|
||||||
|
keepLocalTime?: boolean,
|
||||||
|
keepMinutes?: boolean
|
||||||
|
): this,
|
||||||
|
utcOffset(): number,
|
||||||
|
format(format?: string): string,
|
||||||
|
fromNow(removeSuffix?: boolean): string,
|
||||||
|
from(
|
||||||
|
value: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
removePrefix?: boolean
|
||||||
|
): string,
|
||||||
|
toNow(removePrefix?: boolean): string,
|
||||||
|
to(
|
||||||
|
value: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
removePrefix?: boolean
|
||||||
|
): string,
|
||||||
|
calendar(refTime?: any, formats?: moment$CalendarFormats): string,
|
||||||
|
diff(
|
||||||
|
date: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
format?: string,
|
||||||
|
floating?: boolean
|
||||||
|
): number,
|
||||||
|
valueOf(): number,
|
||||||
|
unix(): number,
|
||||||
|
daysInMonth(): number,
|
||||||
|
toDate(): Date,
|
||||||
|
toArray(): Array<number>,
|
||||||
|
toJSON(): string,
|
||||||
|
toISOString(
|
||||||
|
keepOffset?: boolean
|
||||||
|
): string,
|
||||||
|
toObject(): moment$MomentObject,
|
||||||
|
isBefore(
|
||||||
|
date?: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
units?: ?string
|
||||||
|
): boolean,
|
||||||
|
isSame(
|
||||||
|
date?: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
units?: ?string
|
||||||
|
): boolean,
|
||||||
|
isAfter(
|
||||||
|
date?: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
units?: ?string
|
||||||
|
): boolean,
|
||||||
|
isSameOrBefore(
|
||||||
|
date?: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
units?: ?string
|
||||||
|
): boolean,
|
||||||
|
isSameOrAfter(
|
||||||
|
date?: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
units?: ?string
|
||||||
|
): boolean,
|
||||||
|
isBetween(
|
||||||
|
fromDate: moment$Moment | string | number | Date | Array<number>,
|
||||||
|
toDate?: ?moment$Moment | string | number | Date | Array<number>,
|
||||||
|
granularity?: ?string,
|
||||||
|
inclusion?: ?string
|
||||||
|
): boolean,
|
||||||
|
isDST(): boolean,
|
||||||
|
isDSTShifted(): boolean,
|
||||||
|
isLeapYear(): boolean,
|
||||||
|
clone(): moment$Moment,
|
||||||
|
static isMoment(obj: any): boolean,
|
||||||
|
static isDate(obj: any): boolean,
|
||||||
|
static locale(locale: string, localeData?: Object): string,
|
||||||
|
static updateLocale(locale: string, localeData?: ?Object): void,
|
||||||
|
static locale(locales: Array<string>): string,
|
||||||
|
locale(locale: string, customization?: Object | null): moment$Moment,
|
||||||
|
locale(): string,
|
||||||
|
static months(): Array<string>,
|
||||||
|
static monthsShort(): Array<string>,
|
||||||
|
static weekdays(): Array<string>,
|
||||||
|
static weekdaysShort(): Array<string>,
|
||||||
|
static weekdaysMin(): Array<string>,
|
||||||
|
static months(): string,
|
||||||
|
static monthsShort(): string,
|
||||||
|
static weekdays(): string,
|
||||||
|
static weekdaysShort(): string,
|
||||||
|
static weekdaysMin(): string,
|
||||||
|
static localeData(key?: string): moment$LocaleData,
|
||||||
|
static duration(
|
||||||
|
value: number | Object | string,
|
||||||
|
unit?: string
|
||||||
|
): moment$MomentDuration,
|
||||||
|
static isDuration(obj: any): boolean,
|
||||||
|
static normalizeUnits(unit: string): string,
|
||||||
|
static invalid(object: any): moment$Moment
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "moment" {
|
||||||
|
declare module.exports: Class<moment$Moment>;
|
||||||
|
}
|
||||||
137
scm-ui-components/flow-typed/npm/react-jss_vx.x.x.js
vendored
Normal file
137
scm-ui-components/flow-typed/npm/react-jss_vx.x.x.js
vendored
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
// flow-typed signature: ba35d02d668b0d0a3e04a63a6847974e
|
||||||
|
// flow-typed version: <<STUB>>/react-jss_v8.6.1/flow_v0.79.1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an autogenerated libdef stub for:
|
||||||
|
*
|
||||||
|
* 'react-jss'
|
||||||
|
*
|
||||||
|
* Fill this stub out by replacing all the `any` types.
|
||||||
|
*
|
||||||
|
* Once filled out, we encourage you to share your work with the
|
||||||
|
* community by sending a pull request to:
|
||||||
|
* https://github.com/flowtype/flow-typed
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare module 'react-jss' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We include stubs for each file inside this npm package in case you need to
|
||||||
|
* require those files directly. Feel free to delete any files that aren't
|
||||||
|
* needed.
|
||||||
|
*/
|
||||||
|
declare module 'react-jss/dist/react-jss' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/dist/react-jss.min' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/compose' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/compose.test' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/contextTypes' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/createHoc' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/getDisplayName' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/index' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/index.test' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/injectSheet' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/injectSheet.test' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/jss' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/JssProvider' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/JssProvider.test' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/ns' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'react-jss/lib/propTypes' {
|
||||||
|
declare module.exports: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filename aliases
|
||||||
|
declare module 'react-jss/dist/react-jss.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/dist/react-jss'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/dist/react-jss.min.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/dist/react-jss.min'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/compose.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/compose'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/compose.test.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/compose.test'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/contextTypes.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/contextTypes'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/createHoc.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/createHoc'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/getDisplayName.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/getDisplayName'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/index.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/index'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/index.test.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/index.test'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/injectSheet.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/injectSheet'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/injectSheet.test.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/injectSheet.test'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/jss.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/jss'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/JssProvider.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/JssProvider'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/JssProvider.test.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/JssProvider.test'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/ns.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/ns'>;
|
||||||
|
}
|
||||||
|
declare module 'react-jss/lib/propTypes.js' {
|
||||||
|
declare module.exports: $Exports<'react-jss/lib/propTypes'>;
|
||||||
|
}
|
||||||
43
scm-ui-components/package.json
Normal file
43
scm-ui-components/package.json
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "@scm-manager/ui-components",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "UI Components for SCM-Manager and its plugins",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"repository": "https://bitbucket.org/sdorra/scm-manager",
|
||||||
|
"author": "Sebastian Sdorra <s.sdorra@gmail.com>",
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"update-index": "create-index -r src",
|
||||||
|
"eslint-fix": "eslint src --fix"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@scm-manager/ui-bundler": "^0.0.12",
|
||||||
|
"create-index": "^2.3.0",
|
||||||
|
"enzyme": "^3.5.0",
|
||||||
|
"enzyme-adapter-react-16": "^1.3.1",
|
||||||
|
"flow-bin": "^0.79.1",
|
||||||
|
"flow-typed": "^2.5.1",
|
||||||
|
"jest": "^23.5.0",
|
||||||
|
"raf": "^3.4.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"moment": "^2.22.2",
|
||||||
|
"react": "^16.4.2",
|
||||||
|
"react-dom": "^16.4.2",
|
||||||
|
"react-i18next": "^7.11.0",
|
||||||
|
"react-jss": "^8.6.1",
|
||||||
|
"react-router-dom": "^4.3.1"
|
||||||
|
},
|
||||||
|
"browserify": {
|
||||||
|
"transform": [
|
||||||
|
[
|
||||||
|
"babelify",
|
||||||
|
{
|
||||||
|
"plugins": ["@babel/plugin-proposal-class-properties"],
|
||||||
|
"presets": ["@babel/preset-env", "@babel/preset-flow", "@babel/preset-react"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
47
scm-ui-components/pom.xml
Normal file
47
scm-ui-components/pom.xml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>sonia.scm</groupId>
|
||||||
|
<artifactId>scm</artifactId>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>sonia.scm</groupId>
|
||||||
|
<artifactId>scm-ui-components</artifactId>
|
||||||
|
<packaging>pom</packaging>
|
||||||
|
<version>2.0.0-SNAPSHOT</version>
|
||||||
|
<name>scm-ui-components</name>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.sdorra</groupId>
|
||||||
|
<artifactId>buildfrontend-maven-plugin</artifactId>
|
||||||
|
<version>2.1.0</version>
|
||||||
|
<configuration>
|
||||||
|
<node>
|
||||||
|
<version>8.11.4</version>
|
||||||
|
</node>
|
||||||
|
<pkgManager>
|
||||||
|
<type>YARN</type>
|
||||||
|
<version>1.9.4</version>
|
||||||
|
</pkgManager>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>link</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>link</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
||||||
32
scm-ui-components/src/DateFromNow.js
Normal file
32
scm-ui-components/src/DateFromNow.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import moment from "moment";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
date?: string,
|
||||||
|
|
||||||
|
// context props
|
||||||
|
i18n: any
|
||||||
|
};
|
||||||
|
|
||||||
|
class DateFromNow extends React.Component<Props> {
|
||||||
|
static format(locale: string, date?: string) {
|
||||||
|
let fromNow = "";
|
||||||
|
if (date) {
|
||||||
|
fromNow = moment(date)
|
||||||
|
.locale(locale)
|
||||||
|
.fromNow();
|
||||||
|
}
|
||||||
|
return fromNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { i18n, date } = this.props;
|
||||||
|
|
||||||
|
const fromNow = DateFromNow.format(i18n.language, date);
|
||||||
|
return <span>{fromNow}</span>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate()(DateFromNow);
|
||||||
25
scm-ui-components/src/ErrorNotification.js
Normal file
25
scm-ui-components/src/ErrorNotification.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import Notification from "./Notification";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
t: string => string,
|
||||||
|
error?: Error
|
||||||
|
};
|
||||||
|
|
||||||
|
class ErrorNotification extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { t, error } = this.props;
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<Notification type="danger">
|
||||||
|
<strong>{t("error-notification.prefix")}:</strong> {error.message}
|
||||||
|
</Notification>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("commons")(ErrorNotification);
|
||||||
27
scm-ui-components/src/ErrorPage.js
Normal file
27
scm-ui-components/src/ErrorPage.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import ErrorNotification from "./ErrorNotification";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
error: Error,
|
||||||
|
title: string,
|
||||||
|
subtitle: string
|
||||||
|
};
|
||||||
|
|
||||||
|
class ErrorPage extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { title, subtitle, error } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="section">
|
||||||
|
<div className="box column is-4 is-offset-4 container">
|
||||||
|
<h1 className="title">{title}</h1>
|
||||||
|
<p className="subtitle">{subtitle}</p>
|
||||||
|
<ErrorNotification error={error} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorPage;
|
||||||
18
scm-ui-components/src/Image.js
Normal file
18
scm-ui-components/src/Image.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { withContextPath } from "./urls";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
src: string,
|
||||||
|
alt: string,
|
||||||
|
className?: any
|
||||||
|
};
|
||||||
|
|
||||||
|
class Image extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { src, alt, className } = this.props;
|
||||||
|
return <img className={className} src={withContextPath(src)} alt={alt} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Image;
|
||||||
51
scm-ui-components/src/Loading.js
Normal file
51
scm-ui-components/src/Loading.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import injectSheet from "react-jss";
|
||||||
|
import Image from "./Image";
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
wrapper: {
|
||||||
|
position: "relative"
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
width: "128px",
|
||||||
|
height: "128px",
|
||||||
|
|
||||||
|
position: "absolute",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
|
||||||
|
margin: "64px 0 0 -64px"
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
width: "128px",
|
||||||
|
height: "128px"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
t: string => string,
|
||||||
|
message?: string,
|
||||||
|
classes: any
|
||||||
|
};
|
||||||
|
|
||||||
|
class Loading extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { message, t, classes } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classes.wrapper}>
|
||||||
|
<div className={classes.loading}>
|
||||||
|
<Image
|
||||||
|
className={classes.image}
|
||||||
|
src="/images/loading.svg"
|
||||||
|
alt={t("loading.alt")}
|
||||||
|
/>
|
||||||
|
<p className="has-text-centered">{message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default injectSheet(styles)(translate("commons")(Loading));
|
||||||
17
scm-ui-components/src/Logo.js
Normal file
17
scm-ui-components/src/Logo.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import Image from "./Image";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
t: string => string
|
||||||
|
};
|
||||||
|
|
||||||
|
class Logo extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { t } = this.props;
|
||||||
|
return <Image src="/images/logo.png" alt={t("logo.alt")} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("commons")(Logo);
|
||||||
18
scm-ui-components/src/MailLink.js
Normal file
18
scm-ui-components/src/MailLink.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// @flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
address?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
class MailLink extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { address } = this.props;
|
||||||
|
if (!address) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return <a href={"mailto: " + address}>{address}</a>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MailLink;
|
||||||
37
scm-ui-components/src/Notification.js
Normal file
37
scm-ui-components/src/Notification.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
type NotificationType = "primary" | "info" | "success" | "warning" | "danger";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
type: NotificationType,
|
||||||
|
onClose?: () => void,
|
||||||
|
children?: React.Node
|
||||||
|
};
|
||||||
|
|
||||||
|
class Notification extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
type: "info"
|
||||||
|
};
|
||||||
|
|
||||||
|
renderCloseButton() {
|
||||||
|
const { onClose } = this.props;
|
||||||
|
if (onClose) {
|
||||||
|
return <button className="delete" onClick={onClose} />;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { type, children } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classNames("notification", "is-" + type)}>
|
||||||
|
{this.renderCloseButton()}
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Notification;
|
||||||
124
scm-ui-components/src/Paginator.js
Normal file
124
scm-ui-components/src/Paginator.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import type { PagedCollection } from "./types";
|
||||||
|
import { Button } from "./buttons";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
collection: PagedCollection,
|
||||||
|
onPageChange?: string => void,
|
||||||
|
t: string => string
|
||||||
|
};
|
||||||
|
|
||||||
|
class Paginator extends React.Component<Props> {
|
||||||
|
isLinkUnavailable(linkType: string) {
|
||||||
|
return !this.props.collection || !this.props.collection._links[linkType];
|
||||||
|
}
|
||||||
|
|
||||||
|
createAction = (linkType: string) => () => {
|
||||||
|
const { collection, onPageChange } = this.props;
|
||||||
|
if (onPageChange) {
|
||||||
|
const link = collection._links[linkType].href;
|
||||||
|
onPageChange(link);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderFirstButton() {
|
||||||
|
return this.renderPageButton(1, "first");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPreviousButton() {
|
||||||
|
const { t } = this.props;
|
||||||
|
return this.renderButton(
|
||||||
|
"pagination-previous",
|
||||||
|
t("paginator.previous"),
|
||||||
|
"prev"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderNextButton() {
|
||||||
|
const { t } = this.props;
|
||||||
|
return this.renderButton("pagination-next", t("paginator.next"), "next");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLastButton() {
|
||||||
|
const { collection } = this.props;
|
||||||
|
return this.renderPageButton(collection.pageTotal, "last");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPageButton(page: number, linkType: string) {
|
||||||
|
return this.renderButton("pagination-link", page.toString(), linkType);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderButton(className: string, label: string, linkType: string) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
className={className}
|
||||||
|
label={label}
|
||||||
|
disabled={this.isLinkUnavailable(linkType)}
|
||||||
|
action={this.createAction(linkType)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
seperator() {
|
||||||
|
return <span className="pagination-ellipsis">…</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPage(page: number) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
className="pagination-link is-current"
|
||||||
|
label={page}
|
||||||
|
disabled={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pageLinks() {
|
||||||
|
const { collection } = this.props;
|
||||||
|
|
||||||
|
const links = [];
|
||||||
|
const page = collection.page + 1;
|
||||||
|
const pageTotal = collection.pageTotal;
|
||||||
|
if (page > 1) {
|
||||||
|
links.push(this.renderFirstButton());
|
||||||
|
}
|
||||||
|
if (page > 3) {
|
||||||
|
links.push(this.seperator());
|
||||||
|
}
|
||||||
|
if (page > 2) {
|
||||||
|
links.push(this.renderPageButton(page - 1, "prev"));
|
||||||
|
}
|
||||||
|
|
||||||
|
links.push(this.currentPage(page));
|
||||||
|
|
||||||
|
if (page + 1 < pageTotal) {
|
||||||
|
links.push(this.renderPageButton(page + 1, "next"));
|
||||||
|
}
|
||||||
|
if (page + 2 < pageTotal)
|
||||||
|
//if there exists pages between next and last
|
||||||
|
links.push(this.seperator());
|
||||||
|
if (page < pageTotal) {
|
||||||
|
links.push(this.renderLastButton());
|
||||||
|
}
|
||||||
|
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<nav className="pagination is-centered" aria-label="pagination">
|
||||||
|
{this.renderPreviousButton()}
|
||||||
|
{this.renderNextButton()}
|
||||||
|
<ul className="pagination-list">
|
||||||
|
{this.pageLinks().map((link, index) => {
|
||||||
|
return <li key={index}>{link}</li>;
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("commons")(Paginator);
|
||||||
253
scm-ui-components/src/Paginator.test.js
Normal file
253
scm-ui-components/src/Paginator.test.js
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
// @flow
|
||||||
|
import React from "react";
|
||||||
|
import { mount, shallow } from "enzyme";
|
||||||
|
import "./tests/enzyme";
|
||||||
|
import "./tests/i18n";
|
||||||
|
|
||||||
|
import Paginator from "./Paginator";
|
||||||
|
|
||||||
|
describe("paginator rendering tests", () => {
|
||||||
|
const dummyLink = {
|
||||||
|
href: "https://dummy"
|
||||||
|
};
|
||||||
|
|
||||||
|
it("should render all buttons but disabled, without links", () => {
|
||||||
|
const collection = {
|
||||||
|
page: 10,
|
||||||
|
pageTotal: 20,
|
||||||
|
_links: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginator = shallow(<Paginator collection={collection} />);
|
||||||
|
const buttons = paginator.find("Button");
|
||||||
|
expect(buttons.length).toBe(7);
|
||||||
|
for (let button of buttons) {
|
||||||
|
expect(button.props.disabled).toBeTruthy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render buttons for first page", () => {
|
||||||
|
const collection = {
|
||||||
|
page: 0,
|
||||||
|
pageTotal: 148,
|
||||||
|
_links: {
|
||||||
|
first: dummyLink,
|
||||||
|
next: dummyLink,
|
||||||
|
last: dummyLink
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginator = shallow(<Paginator collection={collection} />);
|
||||||
|
const buttons = paginator.find("Button");
|
||||||
|
expect(buttons.length).toBe(5);
|
||||||
|
|
||||||
|
// previous button
|
||||||
|
expect(buttons.get(0).props.disabled).toBeTruthy();
|
||||||
|
// last button
|
||||||
|
expect(buttons.get(1).props.disabled).toBeFalsy();
|
||||||
|
// first button
|
||||||
|
const firstButton = buttons.get(2).props;
|
||||||
|
expect(firstButton.disabled).toBeTruthy();
|
||||||
|
expect(firstButton.label).toBe(1);
|
||||||
|
|
||||||
|
// next button
|
||||||
|
const nextButton = buttons.get(3).props;
|
||||||
|
expect(nextButton.disabled).toBeFalsy();
|
||||||
|
expect(nextButton.label).toBe("2");
|
||||||
|
|
||||||
|
// last button
|
||||||
|
const lastButton = buttons.get(4).props;
|
||||||
|
expect(lastButton.disabled).toBeFalsy();
|
||||||
|
expect(lastButton.label).toBe("148");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render buttons for second page", () => {
|
||||||
|
const collection = {
|
||||||
|
page: 1,
|
||||||
|
pageTotal: 148,
|
||||||
|
_links: {
|
||||||
|
first: dummyLink,
|
||||||
|
prev: dummyLink,
|
||||||
|
next: dummyLink,
|
||||||
|
last: dummyLink
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginator = shallow(<Paginator collection={collection} />);
|
||||||
|
const buttons = paginator.find("Button");
|
||||||
|
expect(buttons.length).toBe(6);
|
||||||
|
|
||||||
|
// previous button
|
||||||
|
expect(buttons.get(0).props.disabled).toBeFalsy();
|
||||||
|
// last button
|
||||||
|
expect(buttons.get(1).props.disabled).toBeFalsy();
|
||||||
|
// first button
|
||||||
|
const firstButton = buttons.get(2).props;
|
||||||
|
expect(firstButton.disabled).toBeFalsy();
|
||||||
|
expect(firstButton.label).toBe("1");
|
||||||
|
|
||||||
|
// current button
|
||||||
|
const currentButton = buttons.get(3).props;
|
||||||
|
expect(currentButton.disabled).toBeTruthy();
|
||||||
|
expect(currentButton.label).toBe(2);
|
||||||
|
|
||||||
|
// next button
|
||||||
|
const nextButton = buttons.get(4).props;
|
||||||
|
expect(nextButton.disabled).toBeFalsy();
|
||||||
|
expect(nextButton.label).toBe("3");
|
||||||
|
|
||||||
|
// last button
|
||||||
|
const lastButton = buttons.get(5).props;
|
||||||
|
expect(lastButton.disabled).toBeFalsy();
|
||||||
|
expect(lastButton.label).toBe("148");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render buttons for last page", () => {
|
||||||
|
const collection = {
|
||||||
|
page: 147,
|
||||||
|
pageTotal: 148,
|
||||||
|
_links: {
|
||||||
|
first: dummyLink,
|
||||||
|
prev: dummyLink
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginator = shallow(<Paginator collection={collection} />);
|
||||||
|
const buttons = paginator.find("Button");
|
||||||
|
expect(buttons.length).toBe(5);
|
||||||
|
|
||||||
|
// previous button
|
||||||
|
expect(buttons.get(0).props.disabled).toBeFalsy();
|
||||||
|
// last button
|
||||||
|
expect(buttons.get(1).props.disabled).toBeTruthy();
|
||||||
|
// first button
|
||||||
|
const firstButton = buttons.get(2).props;
|
||||||
|
expect(firstButton.disabled).toBeFalsy();
|
||||||
|
expect(firstButton.label).toBe("1");
|
||||||
|
|
||||||
|
// next button
|
||||||
|
const nextButton = buttons.get(3).props;
|
||||||
|
expect(nextButton.disabled).toBeFalsy();
|
||||||
|
expect(nextButton.label).toBe("147");
|
||||||
|
|
||||||
|
// last button
|
||||||
|
const lastButton = buttons.get(4).props;
|
||||||
|
expect(lastButton.disabled).toBeTruthy();
|
||||||
|
expect(lastButton.label).toBe(148);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render buttons for penultimate page", () => {
|
||||||
|
const collection = {
|
||||||
|
page: 146,
|
||||||
|
pageTotal: 148,
|
||||||
|
_links: {
|
||||||
|
first: dummyLink,
|
||||||
|
prev: dummyLink,
|
||||||
|
next: dummyLink,
|
||||||
|
last: dummyLink
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginator = shallow(<Paginator collection={collection} />);
|
||||||
|
const buttons = paginator.find("Button");
|
||||||
|
expect(buttons.length).toBe(6);
|
||||||
|
|
||||||
|
// previous button
|
||||||
|
expect(buttons.get(0).props.disabled).toBeFalsy();
|
||||||
|
// last button
|
||||||
|
expect(buttons.get(1).props.disabled).toBeFalsy();
|
||||||
|
|
||||||
|
// first button
|
||||||
|
const firstButton = buttons.get(2).props;
|
||||||
|
expect(firstButton.disabled).toBeFalsy();
|
||||||
|
expect(firstButton.label).toBe("1");
|
||||||
|
|
||||||
|
const currentButton = buttons.get(3).props;
|
||||||
|
expect(currentButton.disabled).toBeFalsy();
|
||||||
|
expect(currentButton.label).toBe("146");
|
||||||
|
|
||||||
|
// current button
|
||||||
|
const nextButton = buttons.get(4).props;
|
||||||
|
expect(nextButton.disabled).toBeTruthy();
|
||||||
|
expect(nextButton.label).toBe(147);
|
||||||
|
|
||||||
|
// last button
|
||||||
|
const lastButton = buttons.get(5).props;
|
||||||
|
expect(lastButton.disabled).toBeFalsy();
|
||||||
|
expect(lastButton.label).toBe("148");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should render buttons for a page in the middle", () => {
|
||||||
|
const collection = {
|
||||||
|
page: 41,
|
||||||
|
pageTotal: 148,
|
||||||
|
_links: {
|
||||||
|
first: dummyLink,
|
||||||
|
prev: dummyLink,
|
||||||
|
next: dummyLink,
|
||||||
|
last: dummyLink
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginator = shallow(<Paginator collection={collection} />);
|
||||||
|
const buttons = paginator.find("Button");
|
||||||
|
expect(buttons.length).toBe(7);
|
||||||
|
|
||||||
|
// previous button
|
||||||
|
expect(buttons.get(0).props.disabled).toBeFalsy();
|
||||||
|
// next button
|
||||||
|
expect(buttons.get(1).props.disabled).toBeFalsy();
|
||||||
|
|
||||||
|
// first button
|
||||||
|
const firstButton = buttons.get(2).props;
|
||||||
|
expect(firstButton.disabled).toBeFalsy();
|
||||||
|
expect(firstButton.label).toBe("1");
|
||||||
|
|
||||||
|
// previous Button
|
||||||
|
const previousButton = buttons.get(3).props;
|
||||||
|
expect(previousButton.disabled).toBeFalsy();
|
||||||
|
expect(previousButton.label).toBe("41");
|
||||||
|
|
||||||
|
// current button
|
||||||
|
const currentButton = buttons.get(4).props;
|
||||||
|
expect(currentButton.disabled).toBeTruthy();
|
||||||
|
expect(currentButton.label).toBe(42);
|
||||||
|
|
||||||
|
// next button
|
||||||
|
const nextButton = buttons.get(5).props;
|
||||||
|
expect(nextButton.disabled).toBeFalsy();
|
||||||
|
expect(nextButton.label).toBe("43");
|
||||||
|
|
||||||
|
// last button
|
||||||
|
const lastButton = buttons.get(6).props;
|
||||||
|
expect(lastButton.disabled).toBeFalsy();
|
||||||
|
expect(lastButton.label).toBe("148");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should call the function with the last previous url", () => {
|
||||||
|
const collection = {
|
||||||
|
page: 41,
|
||||||
|
pageTotal: 148,
|
||||||
|
_links: {
|
||||||
|
first: dummyLink,
|
||||||
|
prev: {
|
||||||
|
href: "https://www.scm-manager.org"
|
||||||
|
},
|
||||||
|
next: dummyLink,
|
||||||
|
last: dummyLink
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let urlToOpen;
|
||||||
|
const callMe = (url: string) => {
|
||||||
|
urlToOpen = url;
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginator = mount(
|
||||||
|
<Paginator collection={collection} onPageChange={callMe} />
|
||||||
|
);
|
||||||
|
paginator.find("Button.pagination-previous").simulate("click");
|
||||||
|
|
||||||
|
expect(urlToOpen).toBe("https://www.scm-manager.org");
|
||||||
|
});
|
||||||
|
});
|
||||||
39
scm-ui-components/src/ProtectedRoute.js
Normal file
39
scm-ui-components/src/ProtectedRoute.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
//@flow
|
||||||
|
import React, { Component } from "react";
|
||||||
|
import { Route, Redirect, withRouter } from "react-router-dom";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
authenticated?: boolean,
|
||||||
|
component: Component<any, any>
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProtectedRoute extends React.Component<Props> {
|
||||||
|
renderRoute = (Component: any, authenticated?: boolean) => {
|
||||||
|
return (routeProps: any) => {
|
||||||
|
if (authenticated) {
|
||||||
|
return <Component {...routeProps} />;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Redirect
|
||||||
|
to={{
|
||||||
|
pathname: "/login",
|
||||||
|
state: { from: routeProps.location }
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { component, authenticated, ...routeProps } = this.props;
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
{...routeProps}
|
||||||
|
render={this.renderRoute(component, authenticated)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(ProtectedRoute);
|
||||||
11
scm-ui-components/src/buttons/AddButton.js
Normal file
11
scm-ui-components/src/buttons/AddButton.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import Button, { type ButtonProps } from "./Button";
|
||||||
|
|
||||||
|
class AddButton extends React.Component<ButtonProps> {
|
||||||
|
render() {
|
||||||
|
return <Button color="default" {...this.props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddButton;
|
||||||
69
scm-ui-components/src/buttons/Button.js
Normal file
69
scm-ui-components/src/buttons/Button.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
export type ButtonProps = {
|
||||||
|
label: string,
|
||||||
|
loading?: boolean,
|
||||||
|
disabled?: boolean,
|
||||||
|
action?: (event: Event) => void,
|
||||||
|
link?: string,
|
||||||
|
fullWidth?: boolean,
|
||||||
|
className?: string,
|
||||||
|
classes: any
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = ButtonProps & {
|
||||||
|
type: string,
|
||||||
|
color: string
|
||||||
|
};
|
||||||
|
|
||||||
|
class Button extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
type: "button",
|
||||||
|
color: "default"
|
||||||
|
};
|
||||||
|
|
||||||
|
renderButton = () => {
|
||||||
|
const {
|
||||||
|
label,
|
||||||
|
loading,
|
||||||
|
disabled,
|
||||||
|
type,
|
||||||
|
color,
|
||||||
|
action,
|
||||||
|
fullWidth,
|
||||||
|
className
|
||||||
|
} = this.props;
|
||||||
|
const loadingClass = loading ? "is-loading" : "";
|
||||||
|
const fullWidthClass = fullWidth ? "is-fullwidth" : "";
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type={type}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={action ? action : (event: Event) => {}}
|
||||||
|
className={classNames(
|
||||||
|
"button",
|
||||||
|
"is-" + color,
|
||||||
|
loadingClass,
|
||||||
|
fullWidthClass,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { link } = this.props;
|
||||||
|
if (link) {
|
||||||
|
return <Link to={link}>{this.renderButton()}</Link>;
|
||||||
|
} else {
|
||||||
|
return this.renderButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Button;
|
||||||
24
scm-ui-components/src/buttons/CreateButton.js
Normal file
24
scm-ui-components/src/buttons/CreateButton.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import injectSheet from "react-jss";
|
||||||
|
import AddButton, { type ButtonProps } from "./Button";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
spacing: {
|
||||||
|
margin: "1em 0 0 1em"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CreateButton extends React.Component<ButtonProps> {
|
||||||
|
render() {
|
||||||
|
const { classes } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classNames("is-pulled-right", classes.spacing)}>
|
||||||
|
<AddButton {...this.props} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default injectSheet(styles)(CreateButton);
|
||||||
11
scm-ui-components/src/buttons/DeleteButton.js
Normal file
11
scm-ui-components/src/buttons/DeleteButton.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import Button, { type ButtonProps } from "./Button";
|
||||||
|
|
||||||
|
class DeleteButton extends React.Component<ButtonProps> {
|
||||||
|
render() {
|
||||||
|
return <Button color="warning" {...this.props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DeleteButton;
|
||||||
11
scm-ui-components/src/buttons/EditButton.js
Normal file
11
scm-ui-components/src/buttons/EditButton.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import Button, { type ButtonProps } from "./Button";
|
||||||
|
|
||||||
|
class EditButton extends React.Component<ButtonProps> {
|
||||||
|
render() {
|
||||||
|
return <Button color="default" {...this.props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EditButton;
|
||||||
33
scm-ui-components/src/buttons/RemoveEntryOfTableButton.js
Normal file
33
scm-ui-components/src/buttons/RemoveEntryOfTableButton.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { DeleteButton } from ".";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
entryname: string,
|
||||||
|
removeEntry: string => void,
|
||||||
|
disabled: boolean,
|
||||||
|
label: string
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {};
|
||||||
|
|
||||||
|
class RemoveEntryOfTableButton extends React.Component<Props, State> {
|
||||||
|
render() {
|
||||||
|
const { label, entryname, removeEntry, disabled } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={classNames("is-pulled-right")}>
|
||||||
|
<DeleteButton
|
||||||
|
label={label}
|
||||||
|
action={(event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
removeEntry(entryname);
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RemoveEntryOfTableButton;
|
||||||
11
scm-ui-components/src/buttons/SubmitButton.js
Normal file
11
scm-ui-components/src/buttons/SubmitButton.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import Button, { type ButtonProps } from "./Button";
|
||||||
|
|
||||||
|
class SubmitButton extends React.Component<ButtonProps> {
|
||||||
|
render() {
|
||||||
|
return <Button type="submit" color="primary" {...this.props} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SubmitButton;
|
||||||
10
scm-ui-components/src/buttons/index.js
Normal file
10
scm-ui-components/src/buttons/index.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// @create-index
|
||||||
|
|
||||||
|
export { default as AddButton } from "./AddButton.js";
|
||||||
|
export { default as Button } from "./Button.js";
|
||||||
|
export { default as CreateButton } from "./CreateButton.js";
|
||||||
|
export { default as DeleteButton } from "./DeleteButton.js";
|
||||||
|
export { default as EditButton } from "./EditButton.js";
|
||||||
|
export { default as RemoveEntryOfTableButton } from "./RemoveEntryOfTableButton.js";
|
||||||
|
export { default as SubmitButton } from "./SubmitButton.js";
|
||||||
|
|
||||||
68
scm-ui-components/src/forms/AddEntryToTableField.js
Normal file
68
scm-ui-components/src/forms/AddEntryToTableField.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { AddButton } from "../buttons";
|
||||||
|
import InputField from "./InputField";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
addEntry: string => void,
|
||||||
|
disabled: boolean,
|
||||||
|
buttonLabel: string,
|
||||||
|
fieldLabel: string,
|
||||||
|
errorMessage: string
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
entryToAdd: string
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddEntryToTableField extends React.Component<Props, State> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
entryToAdd: ""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { disabled, buttonLabel, fieldLabel, errorMessage } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="field">
|
||||||
|
<InputField
|
||||||
|
label={fieldLabel}
|
||||||
|
errorMessage={errorMessage}
|
||||||
|
onChange={this.handleAddEntryChange}
|
||||||
|
validationError={false}
|
||||||
|
value={this.state.entryToAdd}
|
||||||
|
onReturnPressed={this.appendEntry}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
<AddButton
|
||||||
|
label={buttonLabel}
|
||||||
|
action={this.addButtonClicked}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addButtonClicked = (event: Event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
this.appendEntry();
|
||||||
|
};
|
||||||
|
|
||||||
|
appendEntry = () => {
|
||||||
|
const { entryToAdd } = this.state;
|
||||||
|
this.props.addEntry(entryToAdd);
|
||||||
|
this.setState({ ...this.state, entryToAdd: "" });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleAddEntryChange = (entryname: string) => {
|
||||||
|
this.setState({
|
||||||
|
...this.state,
|
||||||
|
entryToAdd: entryname
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddEntryToTableField;
|
||||||
36
scm-ui-components/src/forms/Checkbox.js
Normal file
36
scm-ui-components/src/forms/Checkbox.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label?: string,
|
||||||
|
checked: boolean,
|
||||||
|
onChange?: boolean => void,
|
||||||
|
disabled?: boolean
|
||||||
|
};
|
||||||
|
class Checkbox extends React.Component<Props> {
|
||||||
|
onCheckboxChange = (event: SyntheticInputEvent<HTMLInputElement>) => {
|
||||||
|
if (this.props.onChange) {
|
||||||
|
this.props.onChange(event.target.checked);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="field">
|
||||||
|
<div className="control">
|
||||||
|
<label className="checkbox" disabled={this.props.disabled}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={this.props.checked}
|
||||||
|
onChange={this.onCheckboxChange}
|
||||||
|
disabled={this.props.disabled}
|
||||||
|
/>
|
||||||
|
{this.props.label}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Checkbox;
|
||||||
94
scm-ui-components/src/forms/InputField.js
Normal file
94
scm-ui-components/src/forms/InputField.js
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label?: string,
|
||||||
|
placeholder?: string,
|
||||||
|
value?: string,
|
||||||
|
type?: string,
|
||||||
|
autofocus?: boolean,
|
||||||
|
onChange: string => void,
|
||||||
|
onReturnPressed?: () => void,
|
||||||
|
validationError: boolean,
|
||||||
|
errorMessage: string,
|
||||||
|
disabled?: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputField extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
type: "text",
|
||||||
|
placeholder: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
field: ?HTMLInputElement;
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.autofocus && this.field) {
|
||||||
|
this.field.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInput = (event: SyntheticInputEvent<HTMLInputElement>) => {
|
||||||
|
this.props.onChange(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderLabel = () => {
|
||||||
|
const label = this.props.label;
|
||||||
|
if (label) {
|
||||||
|
return <label className="label">{label}</label>;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
handleKeyPress = (event: SyntheticKeyboardEvent<HTMLInputElement>) => {
|
||||||
|
const onReturnPressed = this.props.onReturnPressed;
|
||||||
|
if (!onReturnPressed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
event.preventDefault();
|
||||||
|
onReturnPressed();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
type,
|
||||||
|
placeholder,
|
||||||
|
value,
|
||||||
|
validationError,
|
||||||
|
errorMessage,
|
||||||
|
disabled
|
||||||
|
} = this.props;
|
||||||
|
const errorView = validationError ? "is-danger" : "";
|
||||||
|
const helper = validationError ? (
|
||||||
|
<p className="help is-danger">{errorMessage}</p>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="field">
|
||||||
|
{this.renderLabel()}
|
||||||
|
<div className="control">
|
||||||
|
<input
|
||||||
|
ref={input => {
|
||||||
|
this.field = input;
|
||||||
|
}}
|
||||||
|
className={classNames("input", errorView)}
|
||||||
|
type={type}
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={value}
|
||||||
|
onChange={this.handleInput}
|
||||||
|
onKeyPress={this.handleKeyPress}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{helper}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputField;
|
||||||
67
scm-ui-components/src/forms/Select.js
Normal file
67
scm-ui-components/src/forms/Select.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export type SelectItem = {
|
||||||
|
value: string,
|
||||||
|
label: string
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label?: string,
|
||||||
|
options: SelectItem[],
|
||||||
|
value?: SelectItem,
|
||||||
|
onChange: string => void
|
||||||
|
};
|
||||||
|
|
||||||
|
class Select extends React.Component<Props> {
|
||||||
|
field: ?HTMLSelectElement;
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// trigger change after render, if value is null to set it to the first value
|
||||||
|
// of the given options.
|
||||||
|
if (!this.props.value && this.field && this.field.value) {
|
||||||
|
this.props.onChange(this.field.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInput = (event: SyntheticInputEvent<HTMLSelectElement>) => {
|
||||||
|
this.props.onChange(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderLabel = () => {
|
||||||
|
const label = this.props.label;
|
||||||
|
if (label) {
|
||||||
|
return <label className="label">{label}</label>;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { options, value } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="field">
|
||||||
|
{this.renderLabel()}
|
||||||
|
<div className="control select">
|
||||||
|
<select
|
||||||
|
ref={input => {
|
||||||
|
this.field = input;
|
||||||
|
}}
|
||||||
|
value={value}
|
||||||
|
onChange={this.handleInput}
|
||||||
|
>
|
||||||
|
{options.map(opt => {
|
||||||
|
return (
|
||||||
|
<option value={opt.value} key={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Select;
|
||||||
53
scm-ui-components/src/forms/Textarea.js
Normal file
53
scm-ui-components/src/forms/Textarea.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export type SelectItem = {
|
||||||
|
value: string,
|
||||||
|
label: string
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label?: string,
|
||||||
|
placeholder?: SelectItem[],
|
||||||
|
value?: string,
|
||||||
|
onChange: string => void
|
||||||
|
};
|
||||||
|
|
||||||
|
class Textarea extends React.Component<Props> {
|
||||||
|
field: ?HTMLTextAreaElement;
|
||||||
|
|
||||||
|
handleInput = (event: SyntheticInputEvent<HTMLTextAreaElement>) => {
|
||||||
|
this.props.onChange(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
renderLabel = () => {
|
||||||
|
const label = this.props.label;
|
||||||
|
if (label) {
|
||||||
|
return <label className="label">{label}</label>;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { placeholder, value } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="field">
|
||||||
|
{this.renderLabel()}
|
||||||
|
<div className="control">
|
||||||
|
<textarea
|
||||||
|
className="textarea"
|
||||||
|
ref={input => {
|
||||||
|
this.field = input;
|
||||||
|
}}
|
||||||
|
placeholder={placeholder}
|
||||||
|
onChange={this.handleInput}
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Textarea;
|
||||||
8
scm-ui-components/src/forms/index.js
Normal file
8
scm-ui-components/src/forms/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// @create-index
|
||||||
|
|
||||||
|
export { default as AddEntryToTableField } from "./AddEntryToTableField.js";
|
||||||
|
export { default as Checkbox } from "./Checkbox.js";
|
||||||
|
export { default as InputField } from "./InputField.js";
|
||||||
|
export { default as Select } from "./Select.js";
|
||||||
|
export { default as Textarea } from "./Textarea.js";
|
||||||
|
|
||||||
15
scm-ui-components/src/index.js
Normal file
15
scm-ui-components/src/index.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// @create-index
|
||||||
|
|
||||||
|
export { default as DateFromNow } from "./DateFromNow.js";
|
||||||
|
export { default as ErrorNotification } from "./ErrorNotification.js";
|
||||||
|
export { default as ErrorPage } from "./ErrorPage.js";
|
||||||
|
export { default as Image } from "./Image.js";
|
||||||
|
export { default as Loading } from "./Loading.js";
|
||||||
|
export { default as Logo } from "./Logo.js";
|
||||||
|
export { default as MailLink } from "./MailLink.js";
|
||||||
|
export { default as Notification } from "./Notification.js";
|
||||||
|
export { default as Paginator } from "./Paginator.js";
|
||||||
|
export { default as ProtectedRoute } from "./ProtectedRoute.js";
|
||||||
|
export { default as urls } from "./urls.js";
|
||||||
|
export { default as validation } from "./validation.js";
|
||||||
|
|
||||||
25
scm-ui-components/src/layout/Footer.js
Normal file
25
scm-ui-components/src/layout/Footer.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import type { Me } from "../types";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
me?: Me
|
||||||
|
};
|
||||||
|
|
||||||
|
class Footer extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { me } = this.props;
|
||||||
|
if (!me) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<footer className="footer">
|
||||||
|
<div className="container is-centered">
|
||||||
|
<p className="has-text-centered">{me.displayName}</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Footer;
|
||||||
31
scm-ui-components/src/layout/Header.js
Normal file
31
scm-ui-components/src/layout/Header.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
import Logo from "./../Logo";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children?: React.Node
|
||||||
|
};
|
||||||
|
|
||||||
|
class Header extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { children } = this.props;
|
||||||
|
return (
|
||||||
|
<section className="hero is-dark is-small">
|
||||||
|
<div className="hero-body">
|
||||||
|
<div className="container">
|
||||||
|
<div className="columns is-vcentered">
|
||||||
|
<div className="column">
|
||||||
|
<Logo />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="hero-foot">
|
||||||
|
<div className="container">{children}</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header;
|
||||||
44
scm-ui-components/src/layout/Page.js
Normal file
44
scm-ui-components/src/layout/Page.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
import Loading from "./../Loading";
|
||||||
|
import ErrorNotification from "./../ErrorNotification";
|
||||||
|
import Title from "./Title";
|
||||||
|
import Subtitle from "./Subtitle";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title?: string,
|
||||||
|
subtitle?: string,
|
||||||
|
loading?: boolean,
|
||||||
|
error?: Error,
|
||||||
|
showContentOnError?: boolean,
|
||||||
|
children: React.Node
|
||||||
|
};
|
||||||
|
|
||||||
|
class Page extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { title, error, subtitle } = this.props;
|
||||||
|
return (
|
||||||
|
<section className="section">
|
||||||
|
<div className="container">
|
||||||
|
<Title title={title} />
|
||||||
|
<Subtitle subtitle={subtitle} />
|
||||||
|
<ErrorNotification error={error} />
|
||||||
|
{this.renderContent()}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderContent() {
|
||||||
|
const { loading, children, showContentOnError, error } = this.props;
|
||||||
|
if (error && !showContentOnError) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (loading) {
|
||||||
|
return <Loading />;
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
18
scm-ui-components/src/layout/Subtitle.js
Normal file
18
scm-ui-components/src/layout/Subtitle.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// @flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
subtitle?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
class Subtitle extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { subtitle } = this.props;
|
||||||
|
if (subtitle) {
|
||||||
|
return <h1 className="subtitle">{subtitle}</h1>;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Subtitle;
|
||||||
18
scm-ui-components/src/layout/Title.js
Normal file
18
scm-ui-components/src/layout/Title.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// @flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title?: string
|
||||||
|
};
|
||||||
|
|
||||||
|
class Title extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { title } = this.props;
|
||||||
|
if (title) {
|
||||||
|
return <h1 className="title">{title}</h1>;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Title;
|
||||||
8
scm-ui-components/src/layout/index.js
Normal file
8
scm-ui-components/src/layout/index.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// @create-index
|
||||||
|
|
||||||
|
export { default as Footer } from "./Footer.js";
|
||||||
|
export { default as Header } from "./Header.js";
|
||||||
|
export { default as Page } from "./Page.js";
|
||||||
|
export { default as Subtitle } from "./Subtitle.js";
|
||||||
|
export { default as Title } from "./Title.js";
|
||||||
|
|
||||||
102
scm-ui-components/src/modals/ConfirmAlert.css
Normal file
102
scm-ui-components/src/modals/ConfirmAlert.css
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/*modified from https://github.com/GA-MO/react-confirm-alert*/
|
||||||
|
.react-confirm-alert-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 99;
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -moz-flex;
|
||||||
|
display: -ms-flex;
|
||||||
|
display: -o-flex;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
-ms-align-items: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-animation: react-confirm-alert-fadeIn 0.5s 0.2s forwards;
|
||||||
|
-moz-animation: react-confirm-alert-fadeIn 0.5s 0.2s forwards;
|
||||||
|
-o-animation: react-confirm-alert-fadeIn 0.5s 0.2s forwards;
|
||||||
|
animation: react-confirm-alert-fadeIn 0.5s 0.2s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-confirm-alert-body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
width: 400px;
|
||||||
|
padding: 30px;
|
||||||
|
text-align: left;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 20px 75px rgba(0, 0, 0, 0.13);
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-confirm-alert-body > h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-confirm-alert-body > h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-confirm-alert-button-group {
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -moz-flex;
|
||||||
|
display: -ms-flex;
|
||||||
|
display: -o-flex;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.react-confirm-alert-button-group > button {
|
||||||
|
outline: none;
|
||||||
|
background: #333;
|
||||||
|
border: none;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 18px;
|
||||||
|
color: #eee;
|
||||||
|
margin-right: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes react-confirm-alert-fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes react-confirm-alert-fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-o-keyframes react-confirm-alert-fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes react-confirm-alert-fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
82
scm-ui-components/src/modals/ConfirmAlert.js
Normal file
82
scm-ui-components/src/modals/ConfirmAlert.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// @flow
|
||||||
|
//modified from https://github.com/GA-MO/react-confirm-alert
|
||||||
|
|
||||||
|
import * as React from "react";
|
||||||
|
import { render, unmountComponentAtNode } from "react-dom";
|
||||||
|
import "./ConfirmAlert.css";
|
||||||
|
|
||||||
|
type Button = {
|
||||||
|
label: string,
|
||||||
|
onClick: () => void | null
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
title: string,
|
||||||
|
message: string,
|
||||||
|
buttons: Button[]
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfirmAlert extends React.Component<Props> {
|
||||||
|
handleClickButton = (button: Button) => {
|
||||||
|
if (button.onClick) {
|
||||||
|
button.onClick();
|
||||||
|
}
|
||||||
|
this.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
close = () => {
|
||||||
|
removeElementReconfirm();
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { title, message, buttons } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="react-confirm-alert-overlay">
|
||||||
|
<div className="react-confirm-alert">
|
||||||
|
{
|
||||||
|
<div className="react-confirm-alert-body">
|
||||||
|
{title && <h1>{title}</h1>}
|
||||||
|
{message}
|
||||||
|
<div className="react-confirm-alert-button-group">
|
||||||
|
{buttons.map((button, i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
onClick={() => this.handleClickButton(button)}
|
||||||
|
>
|
||||||
|
{button.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createElementReconfirm(properties: Props) {
|
||||||
|
const divTarget = document.createElement("div");
|
||||||
|
divTarget.id = "react-confirm-alert";
|
||||||
|
if (document.body) {
|
||||||
|
document.body.appendChild(divTarget);
|
||||||
|
render(<ConfirmAlert {...properties} />, divTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeElementReconfirm() {
|
||||||
|
const target = document.getElementById("react-confirm-alert");
|
||||||
|
if (target) {
|
||||||
|
unmountComponentAtNode(target);
|
||||||
|
if (target.parentNode) {
|
||||||
|
target.parentNode.removeChild(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function confirmAlert(properties: Props) {
|
||||||
|
createElementReconfirm(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConfirmAlert;
|
||||||
4
scm-ui-components/src/modals/index.js
Normal file
4
scm-ui-components/src/modals/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
// @create-index
|
||||||
|
|
||||||
|
export { default as ConfirmAlert } from "./ConfirmAlert.js";
|
||||||
|
|
||||||
20
scm-ui-components/src/navigation/NavAction.js
Normal file
20
scm-ui-components/src/navigation/NavAction.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label: string,
|
||||||
|
action: () => void
|
||||||
|
};
|
||||||
|
|
||||||
|
class NavAction extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { label, action } = this.props;
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<a onClick={action}>{label}</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NavAction;
|
||||||
37
scm-ui-components/src/navigation/NavLink.js
Normal file
37
scm-ui-components/src/navigation/NavLink.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
import { Route, Link } from "react-router-dom";
|
||||||
|
|
||||||
|
// TODO mostly copy of PrimaryNavigationLink
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
to: string,
|
||||||
|
label: string,
|
||||||
|
activeOnlyWhenExact?: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
class NavLink extends React.Component<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
activeOnlyWhenExact: true
|
||||||
|
};
|
||||||
|
|
||||||
|
renderLink = (route: any) => {
|
||||||
|
const { to, label } = this.props;
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<Link className={route.match ? "is-active" : ""} to={to}>
|
||||||
|
{label}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { to, activeOnlyWhenExact } = this.props;
|
||||||
|
return (
|
||||||
|
<Route path={to} exact={activeOnlyWhenExact} children={this.renderLink} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NavLink;
|
||||||
14
scm-ui-components/src/navigation/Navigation.js
Normal file
14
scm-ui-components/src/navigation/Navigation.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children?: React.Node
|
||||||
|
};
|
||||||
|
|
||||||
|
class Navigation extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
return <aside className="menu">{this.props.children}</aside>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Navigation;
|
||||||
45
scm-ui-components/src/navigation/PrimaryNavigation.js
Normal file
45
scm-ui-components/src/navigation/PrimaryNavigation.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
//@flow
|
||||||
|
import React from "react";
|
||||||
|
import { translate } from "react-i18next";
|
||||||
|
import PrimaryNavigationLink from "./PrimaryNavigationLink";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
t: string => string
|
||||||
|
};
|
||||||
|
|
||||||
|
class PrimaryNavigation extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { t } = this.props;
|
||||||
|
return (
|
||||||
|
<nav className="tabs is-boxed">
|
||||||
|
<ul>
|
||||||
|
<PrimaryNavigationLink
|
||||||
|
to="/repos"
|
||||||
|
match="/(repo|repos)"
|
||||||
|
label={t("primary-navigation.repositories")}
|
||||||
|
/>
|
||||||
|
<PrimaryNavigationLink
|
||||||
|
to="/users"
|
||||||
|
match="/(user|users)"
|
||||||
|
label={t("primary-navigation.users")}
|
||||||
|
/>
|
||||||
|
<PrimaryNavigationLink
|
||||||
|
to="/groups"
|
||||||
|
match="/(group|groups)"
|
||||||
|
label={t("primary-navigation.groups")}
|
||||||
|
/>
|
||||||
|
<PrimaryNavigationLink
|
||||||
|
to="/config"
|
||||||
|
label={t("primary-navigation.config")}
|
||||||
|
/>
|
||||||
|
<PrimaryNavigationLink
|
||||||
|
to="/logout"
|
||||||
|
label={t("primary-navigation.logout")}
|
||||||
|
/>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default translate("commons")(PrimaryNavigation);
|
||||||
35
scm-ui-components/src/navigation/PrimaryNavigationLink.js
Normal file
35
scm-ui-components/src/navigation/PrimaryNavigationLink.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
import { Route, Link } from "react-router-dom";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
to: string,
|
||||||
|
label: string,
|
||||||
|
match?: string,
|
||||||
|
activeOnlyWhenExact?: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
class PrimaryNavigationLink extends React.Component<Props> {
|
||||||
|
renderLink = (route: any) => {
|
||||||
|
const { to, label } = this.props;
|
||||||
|
return (
|
||||||
|
<li className={route.match ? "is-active" : ""}>
|
||||||
|
<Link to={to}>{label}</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { to, match, activeOnlyWhenExact } = this.props;
|
||||||
|
const path = match ? match : to;
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
path={path}
|
||||||
|
exact={activeOnlyWhenExact}
|
||||||
|
children={this.renderLink}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PrimaryNavigationLink;
|
||||||
21
scm-ui-components/src/navigation/Section.js
Normal file
21
scm-ui-components/src/navigation/Section.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
//@flow
|
||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
label: string,
|
||||||
|
children?: React.Node
|
||||||
|
};
|
||||||
|
|
||||||
|
class Section extends React.Component<Props> {
|
||||||
|
render() {
|
||||||
|
const { label, children } = this.props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p className="menu-label">{label}</p>
|
||||||
|
<ul className="menu-list">{children}</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Section;
|
||||||
9
scm-ui-components/src/navigation/index.js
Normal file
9
scm-ui-components/src/navigation/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// @create-index
|
||||||
|
|
||||||
|
export { default as NavAction } from "./NavAction.js";
|
||||||
|
export { default as NavLink } from "./NavLink.js";
|
||||||
|
export { default as Navigation } from "./Navigation.js";
|
||||||
|
export { default as PrimaryNavigation } from "./PrimaryNavigation.js";
|
||||||
|
export { default as PrimaryNavigationLink } from "./PrimaryNavigationLink.js";
|
||||||
|
export { default as Section } from "./Section.js";
|
||||||
|
|
||||||
12
scm-ui-components/src/tests/enzyme.js
Normal file
12
scm-ui-components/src/tests/enzyme.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import "raf/polyfill";
|
||||||
|
import { configure } from "enzyme";
|
||||||
|
import Adapter from "enzyme-adapter-react-16";
|
||||||
|
|
||||||
|
// Temporary hack to suppress error
|
||||||
|
// https://github.com/facebook/create-react-app/issues/3199#issuecomment-345024029
|
||||||
|
window.requestAnimationFrame = function(callback) {
|
||||||
|
setTimeout(callback, 0);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
configure({ adapter: new Adapter() });
|
||||||
7
scm-ui-components/src/tests/i18n.js
Normal file
7
scm-ui-components/src/tests/i18n.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
jest.mock("react-i18next", () => ({
|
||||||
|
// this mock makes sure any components using the translate HoC receive the t function as a prop
|
||||||
|
translate: () => Component => {
|
||||||
|
Component.defaultProps = { ...Component.defaultProps, t: key => key };
|
||||||
|
return Component;
|
||||||
|
}
|
||||||
|
}));
|
||||||
7
scm-ui-components/src/types/Action.js
Normal file
7
scm-ui-components/src/types/Action.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// @flow
|
||||||
|
export type Action = {
|
||||||
|
type: string,
|
||||||
|
payload?: any,
|
||||||
|
itemId?: string | number,
|
||||||
|
resetPending?: boolean
|
||||||
|
};
|
||||||
27
scm-ui-components/src/types/Config.js
Normal file
27
scm-ui-components/src/types/Config.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//@flow
|
||||||
|
import type { Links } from "./hal";
|
||||||
|
|
||||||
|
export type Config = {
|
||||||
|
proxyPassword: string | null,
|
||||||
|
proxyPort: number,
|
||||||
|
proxyServer: string,
|
||||||
|
proxyUser: string | null,
|
||||||
|
enableProxy: boolean,
|
||||||
|
realmDescription: string,
|
||||||
|
enableRepositoryArchive: boolean,
|
||||||
|
disableGroupingGrid: boolean,
|
||||||
|
dateFormat: string,
|
||||||
|
anonymousAccessEnabled: boolean,
|
||||||
|
adminGroups: string[],
|
||||||
|
adminUsers: string[],
|
||||||
|
baseUrl: string,
|
||||||
|
forceBaseUrl: boolean,
|
||||||
|
loginAttemptLimit: number,
|
||||||
|
proxyExcludes: string[],
|
||||||
|
skipFailedAuthenticators: boolean,
|
||||||
|
pluginUrl: string,
|
||||||
|
loginAttemptLimitTimeout: number,
|
||||||
|
enabledXsrfProtection: boolean,
|
||||||
|
defaultNamespaceStrategy: string,
|
||||||
|
_links: Links
|
||||||
|
};
|
||||||
19
scm-ui-components/src/types/Group.js
Normal file
19
scm-ui-components/src/types/Group.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
//@flow
|
||||||
|
import type { Collection, Links } from "./hal";
|
||||||
|
|
||||||
|
export type Member = {
|
||||||
|
name: string,
|
||||||
|
_links: Links
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Group = Collection & {
|
||||||
|
name: string,
|
||||||
|
description: string,
|
||||||
|
type: string,
|
||||||
|
members: string[],
|
||||||
|
_embedded: {
|
||||||
|
members: Member[]
|
||||||
|
},
|
||||||
|
creationDate?: string,
|
||||||
|
lastModified?: string
|
||||||
|
};
|
||||||
6
scm-ui-components/src/types/Me.js
Normal file
6
scm-ui-components/src/types/Me.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
export type Me = {
|
||||||
|
name: string,
|
||||||
|
displayName: string
|
||||||
|
};
|
||||||
24
scm-ui-components/src/types/Repositories.js
Normal file
24
scm-ui-components/src/types/Repositories.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//@flow
|
||||||
|
import type { PagedCollection, Links } from "./hal";
|
||||||
|
|
||||||
|
export type Repository = {
|
||||||
|
namespace: string,
|
||||||
|
name: string,
|
||||||
|
type: string,
|
||||||
|
contact?: string,
|
||||||
|
description?: string,
|
||||||
|
creationDate?: string,
|
||||||
|
lastModified?: string,
|
||||||
|
_links: Links
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RepositoryCollection = PagedCollection & {
|
||||||
|
_embedded: {
|
||||||
|
repositories: Repository[] | string[]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RepositoryGroup = {
|
||||||
|
name: string,
|
||||||
|
repositories: Repository[]
|
||||||
|
};
|
||||||
14
scm-ui-components/src/types/RepositoryTypes.js
Normal file
14
scm-ui-components/src/types/RepositoryTypes.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import type { Collection } from "./hal";
|
||||||
|
|
||||||
|
export type RepositoryType = {
|
||||||
|
name: string,
|
||||||
|
displayName: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RepositoryTypeCollection = Collection & {
|
||||||
|
_embedded: {
|
||||||
|
repositoryTypes: RepositoryType[]
|
||||||
|
}
|
||||||
|
};
|
||||||
15
scm-ui-components/src/types/User.js
Normal file
15
scm-ui-components/src/types/User.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
//@flow
|
||||||
|
import type { Links } from "./hal";
|
||||||
|
|
||||||
|
export type User = {
|
||||||
|
displayName: string,
|
||||||
|
name: string,
|
||||||
|
mail: string,
|
||||||
|
password: string,
|
||||||
|
admin: boolean,
|
||||||
|
active: boolean,
|
||||||
|
type?: string,
|
||||||
|
creationDate?: string,
|
||||||
|
lastModified?: string,
|
||||||
|
_links: Links
|
||||||
|
};
|
||||||
16
scm-ui-components/src/types/hal.js
Normal file
16
scm-ui-components/src/types/hal.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// @flow
|
||||||
|
export type Link = {
|
||||||
|
href: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Links = { [string]: Link };
|
||||||
|
|
||||||
|
export type Collection = {
|
||||||
|
_embedded: Object,
|
||||||
|
_links: Links
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PagedCollection = Collection & {
|
||||||
|
page: number,
|
||||||
|
pageTotal: number
|
||||||
|
};
|
||||||
12
scm-ui-components/src/types/index.js
Normal file
12
scm-ui-components/src/types/index.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// @flow
|
||||||
|
export type { Action } from "./Action";
|
||||||
|
export type { Link, Links, Collection, PagedCollection } from "./hal";
|
||||||
|
|
||||||
|
export type { Me } from "./Me";
|
||||||
|
export type { User } from "./User";
|
||||||
|
export type { Group, Member } from "./Group";
|
||||||
|
|
||||||
|
export type { Repository, RepositoryCollection, RepositoryGroup } from "./Repositories";
|
||||||
|
export type { RepositoryType, RepositoryTypeCollection } from "./RepositoryTypes";
|
||||||
|
|
||||||
|
export type { Config } from "./Config";
|
||||||
6
scm-ui-components/src/urls.js
Normal file
6
scm-ui-components/src/urls.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// @flow
|
||||||
|
export const contextPath = window.ctxPath || "";
|
||||||
|
|
||||||
|
export function withContextPath(path: string) {
|
||||||
|
return contextPath + path;
|
||||||
|
}
|
||||||
16
scm-ui-components/src/validation.js
Normal file
16
scm-ui-components/src/validation.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// @flow
|
||||||
|
const nameRegex = /^([A-z0-9.\-_@]|[^ ]([A-z0-9.\-_@ ]*[A-z0-9.\-_@]|[^\s])?)$/;
|
||||||
|
|
||||||
|
export const isNameValid = (name: string) => {
|
||||||
|
return nameRegex.test(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mailRegex = /^[A-z0-9][\w.-]*@[A-z0-9][\w\-.]*\.[A-z0-9][A-z0-9-]+$/;
|
||||||
|
|
||||||
|
export const isMailValid = (mail: string) => {
|
||||||
|
return mailRegex.test(mail);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isNumberValid = (number: string) => {
|
||||||
|
return !isNaN(number);
|
||||||
|
};
|
||||||
102
scm-ui-components/src/validation.test.js
Normal file
102
scm-ui-components/src/validation.test.js
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// @flow
|
||||||
|
import * as validator from "./validation";
|
||||||
|
|
||||||
|
describe("test name validation", () => {
|
||||||
|
it("should return false", () => {
|
||||||
|
// invalid names taken from ValidationUtilTest.java
|
||||||
|
const invalidNames = [
|
||||||
|
" test 123",
|
||||||
|
" test 123 ",
|
||||||
|
"test 123 ",
|
||||||
|
"test/123",
|
||||||
|
"test%123",
|
||||||
|
"test:123",
|
||||||
|
"t ",
|
||||||
|
" t",
|
||||||
|
" t ",
|
||||||
|
"",
|
||||||
|
|
||||||
|
" invalid_name",
|
||||||
|
"another%one",
|
||||||
|
"!!!",
|
||||||
|
"!_!"
|
||||||
|
];
|
||||||
|
for (let name of invalidNames) {
|
||||||
|
expect(validator.isNameValid(name)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true", () => {
|
||||||
|
// valid names taken from ValidationUtilTest.java
|
||||||
|
const validNames = [
|
||||||
|
"test",
|
||||||
|
"test.git",
|
||||||
|
"Test123.git",
|
||||||
|
"Test123-git",
|
||||||
|
"Test_user-123.git",
|
||||||
|
"test@scm-manager.de",
|
||||||
|
"test 123",
|
||||||
|
"tt",
|
||||||
|
"t",
|
||||||
|
|
||||||
|
"valid_name",
|
||||||
|
"another1",
|
||||||
|
"stillValid",
|
||||||
|
"this.one_as-well",
|
||||||
|
"and@this"
|
||||||
|
];
|
||||||
|
for (let name of validNames) {
|
||||||
|
expect(validator.isNameValid(name)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("test mail validation", () => {
|
||||||
|
it("should return false", () => {
|
||||||
|
// invalid taken from ValidationUtilTest.java
|
||||||
|
const invalid = [
|
||||||
|
"ostfalia.de",
|
||||||
|
"@ostfalia.de",
|
||||||
|
"s.sdorra@",
|
||||||
|
"s.sdorra@ostfalia",
|
||||||
|
"s.sdorra@@ostfalia.de",
|
||||||
|
"s.sdorra@ ostfalia.de",
|
||||||
|
"s.sdorra @ostfalia.de"
|
||||||
|
];
|
||||||
|
for (let mail of invalid) {
|
||||||
|
expect(validator.isMailValid(mail)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return true", () => {
|
||||||
|
// valid taken from ValidationUtilTest.java
|
||||||
|
const valid = [
|
||||||
|
"s.sdorra@ostfalia.de",
|
||||||
|
"sdorra@ostfalia.de",
|
||||||
|
"s.sdorra@hbk-bs.de",
|
||||||
|
"s.sdorra@gmail.com",
|
||||||
|
"s.sdorra@t.co",
|
||||||
|
"s.sdorra@ucla.college",
|
||||||
|
"s.sdorra@example.xn--p1ai",
|
||||||
|
"s.sdorra@scm.solutions"
|
||||||
|
];
|
||||||
|
for (let mail of valid) {
|
||||||
|
expect(validator.isMailValid(mail)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("test number validation", () => {
|
||||||
|
it("should return false", () => {
|
||||||
|
const invalid = ["1a", "35gu", "dj6", "45,5", "test"];
|
||||||
|
for (let number of invalid) {
|
||||||
|
expect(validator.isNumberValid(number)).toBe(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it("should return true", () => {
|
||||||
|
const valid = ["1", "35", "2", "235", "34.4"];
|
||||||
|
for (let number of valid) {
|
||||||
|
expect(validator.isNumberValid(number)).toBe(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
8163
scm-ui-components/yarn.lock
Normal file
8163
scm-ui-components/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -31,8 +31,8 @@
|
|||||||
"webfonts": "copyfiles -f node_modules/@fortawesome/fontawesome-free/webfonts/* target/styles/webfonts",
|
"webfonts": "copyfiles -f node_modules/@fortawesome/fontawesome-free/webfonts/* target/styles/webfonts",
|
||||||
"build-css": "node-sass-chokidar --include-path ./styles --include-path ./node_modules styles/ -o target/styles",
|
"build-css": "node-sass-chokidar --include-path ./styles --include-path ./node_modules styles/ -o target/styles",
|
||||||
"watch-css": "npm run build-css && node-sass-chokidar --include-path ./styles --include-path ./node_modules styles/ -o target/styles --watch --recursive",
|
"watch-css": "npm run build-css && node-sass-chokidar --include-path ./styles --include-path ./node_modules styles/ -o target/styles --watch --recursive",
|
||||||
"start-js": "ui-bundler serve",
|
"start-js": "ui-bundler serve --vendor vendor.bundle.js",
|
||||||
"start": "npm-run-all -p webfonts watch-css build-vendor start-js",
|
"start": "npm-run-all -p webfonts watch-css start-js",
|
||||||
"build-js": "ui-bundler bundle target/scm-ui.bundle.js",
|
"build-js": "ui-bundler bundle target/scm-ui.bundle.js",
|
||||||
"build-vendor": "ui-bundler vendor target/vendor.bundle.js",
|
"build-vendor": "ui-bundler vendor target/vendor.bundle.js",
|
||||||
"build": "npm-run-all -s webfonts build-css build-vendor build-js",
|
"build": "npm-run-all -s webfonts build-css build-vendor build-js",
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
"pre-commit": "jest && flow && eslint src"
|
"pre-commit": "jest && flow && eslint src"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@scm-manager/ui-bundler": "^0.0.9",
|
"@scm-manager/ui-bundler": "^0.0.12",
|
||||||
"copyfiles": "^2.0.0",
|
"copyfiles": "^2.0.0",
|
||||||
"enzyme": "^3.3.0",
|
"enzyme": "^3.3.0",
|
||||||
"enzyme-adapter-react-16": "^1.1.1",
|
"enzyme-adapter-react-16": "^1.1.1",
|
||||||
|
|||||||
@@ -31,18 +31,28 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.github.sdorra</groupId>
|
<groupId>com.github.sdorra</groupId>
|
||||||
<artifactId>buildfrontend-maven-plugin</artifactId>
|
<artifactId>buildfrontend-maven-plugin</artifactId>
|
||||||
<version>2.0.1</version>
|
<version>2.1.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<node>
|
<node>
|
||||||
<version>8.11.3</version>
|
<version>8.11.4</version>
|
||||||
</node>
|
</node>
|
||||||
<pkgManager>
|
<pkgManager>
|
||||||
<type>YARN</type>
|
<type>YARN</type>
|
||||||
<version>1.7.0</version>
|
<version>1.9.4</version>
|
||||||
</pkgManager>
|
</pkgManager>
|
||||||
<script>run</script>
|
<script>run</script>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>link-components</id>
|
||||||
|
<phase>process-resources</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>install-link</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<pkg>@scm-manager/ui-components</pkg>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>install</id>
|
<id>install</id>
|
||||||
<phase>process-resources</phase>
|
<phase>process-resources</phase>
|
||||||
|
|||||||
@@ -732,9 +732,9 @@
|
|||||||
version "0.0.2"
|
version "0.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
|
resolved "https://registry.yarnpkg.com/@scm-manager/eslint-config/-/eslint-config-0.0.2.tgz#94cc8c3fb4f51f870b235893dc134fc6c423ae85"
|
||||||
|
|
||||||
"@scm-manager/ui-bundler@^0.0.9":
|
"@scm-manager/ui-bundler@^0.0.10":
|
||||||
version "0.0.9"
|
version "0.0.10"
|
||||||
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.9.tgz#b61bdccaf6cf0ff3f4856098f95b462223c626c8"
|
resolved "https://registry.yarnpkg.com/@scm-manager/ui-bundler/-/ui-bundler-0.0.10.tgz#94c90ed1c1830352e274e048158843436ce31352"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/core" "^7.0.0"
|
"@babel/core" "^7.0.0"
|
||||||
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
"@babel/plugin-proposal-class-properties" "^7.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user