mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-12-22 00:09:47 +01:00
Replace styled-components with bulma helpers (#1783)
Use Bulma helpers whenever possible instead of custom styled components. This pull request replaces primarily color definitions, spacing and flex instructions.
This commit is contained in:
2
gradle/changelog/simplify_styling.yaml
Normal file
2
gradle/changelog/simplify_styling.yaml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
- type: Changed
|
||||||
|
description: Replace styled-components with bulma helpers ([#1783](https://github.com/scm-manager/scm-manager/pull/1783))
|
||||||
@@ -27,18 +27,14 @@ import { Repository, Link } from "@scm-manager/ui-types";
|
|||||||
import { ButtonAddons, Button } from "@scm-manager/ui-components";
|
import { ButtonAddons, Button } from "@scm-manager/ui-components";
|
||||||
import CloneInformation from "./CloneInformation";
|
import CloneInformation from "./CloneInformation";
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
position: relative;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Switcher = styled(ButtonAddons)`
|
const Switcher = styled(ButtonAddons)`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SmallButton = styled(Button).attrs(props => ({
|
const SmallButton = styled(Button).attrs((props) => ({
|
||||||
className: "is-small"
|
className: "is-small",
|
||||||
}))`
|
}))`
|
||||||
height: inherit;
|
height: inherit;
|
||||||
`;
|
`;
|
||||||
@@ -70,13 +66,13 @@ export default class ProtocolInformation extends React.Component<Props, State> {
|
|||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
selected: selectHttpOrFirst(props.repository)
|
selected: selectHttpOrFirst(props.repository),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
selectProtocol = (protocol: Link) => {
|
selectProtocol = (protocol: Link) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
selected: protocol
|
selected: protocol,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,10 +112,10 @@ export default class ProtocolInformation extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<div className="is-relative">
|
||||||
<Switcher>{protocols.map(this.renderProtocolButton)}</Switcher>
|
<Switcher>{protocols.map(this.renderProtocolButton)}</Switcher>
|
||||||
{cloneInformation}
|
{cloneInformation}
|
||||||
</Wrapper>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ const MinWidthControl = styled.div`
|
|||||||
min-width: 10rem;
|
min-width: 10rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NoBottomMarginField = styled.div`
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BranchSelector: FC<Props> = ({ branches, onSelectBranch, selectedBranch, label, disabled }) => {
|
const BranchSelector: FC<Props> = ({ branches, onSelectBranch, selectedBranch, label, disabled }) => {
|
||||||
if (branches) {
|
if (branches) {
|
||||||
return (
|
return (
|
||||||
@@ -56,7 +52,7 @@ const BranchSelector: FC<Props> = ({ branches, onSelectBranch, selectedBranch, l
|
|||||||
<label className={classNames("label", "is-size-6")}>{label}</label>
|
<label className={classNames("label", "is-size-6")}>{label}</label>
|
||||||
</ZeroflexFieldLabel>
|
</ZeroflexFieldLabel>
|
||||||
<div className="field-body">
|
<div className="field-body">
|
||||||
<NoBottomMarginField className={classNames("field", "is-narrow")}>
|
<div className={classNames("field", "is-narrow", "mb-0")}>
|
||||||
<MinWidthControl className="control">
|
<MinWidthControl className="control">
|
||||||
<Select
|
<Select
|
||||||
className="is-fullwidth"
|
className="is-fullwidth"
|
||||||
@@ -67,7 +63,7 @@ const BranchSelector: FC<Props> = ({ branches, onSelectBranch, selectedBranch, l
|
|||||||
addValueToOptions={true}
|
addValueToOptions={true}
|
||||||
/>
|
/>
|
||||||
</MinWidthControl>
|
</MinWidthControl>
|
||||||
</NoBottomMarginField>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
@@ -30,6 +29,7 @@ import repository from "./__resources__/repository";
|
|||||||
// @ts-ignore ignore unknown png
|
// @ts-ignore ignore unknown png
|
||||||
import Git from "./__resources__/git-logo.png";
|
import Git from "./__resources__/git-logo.png";
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
|
import Icon from "./Icon";
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
margin: 2rem;
|
margin: 2rem;
|
||||||
@@ -42,10 +42,15 @@ const longPath =
|
|||||||
"dream-path/src/main/scm-plugins/javaUtilityHomeHousingLinkReferrer/sonia/scm/repositoryUndergroundSupportManager/spi/SvnRepositoryServiceResolver.java";
|
"dream-path/src/main/scm-plugins/javaUtilityHomeHousingLinkReferrer/sonia/scm/repositoryUndergroundSupportManager/spi/SvnRepositoryServiceResolver.java";
|
||||||
const baseUrl = "scm-manager.org/scm/repo/hitchhiker/heartOfGold/sources";
|
const baseUrl = "scm-manager.org/scm/repo/hitchhiker/heartOfGold/sources";
|
||||||
const sources = Git;
|
const sources = Git;
|
||||||
|
const prefix = (
|
||||||
|
<a href="#link">
|
||||||
|
<Icon name="heart" color="danger" />
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
|
||||||
storiesOf("BreadCrumb", module)
|
storiesOf("BreadCrumb", module)
|
||||||
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||||
.addDecorator(storyFn => <Wrapper>{storyFn()}</Wrapper>)
|
.addDecorator((storyFn) => <Wrapper>{storyFn()}</Wrapper>)
|
||||||
.add("Default", () => (
|
.add("Default", () => (
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
repository={repository}
|
repository={repository}
|
||||||
@@ -69,4 +74,17 @@ storiesOf("BreadCrumb", module)
|
|||||||
revision={"1"}
|
revision={"1"}
|
||||||
permalink={"/" + longPath}
|
permalink={"/" + longPath}
|
||||||
/>
|
/>
|
||||||
|
))
|
||||||
|
.add("With prefix button", () => (
|
||||||
|
<Breadcrumb
|
||||||
|
repository={repository}
|
||||||
|
defaultBranch={master}
|
||||||
|
branch={master}
|
||||||
|
path={path}
|
||||||
|
baseUrl={baseUrl}
|
||||||
|
sources={sources}
|
||||||
|
revision={"1"}
|
||||||
|
permalink={"/" + path}
|
||||||
|
preButtons={prefix}
|
||||||
|
/>
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -93,14 +93,7 @@ const HomeIcon = styled(Icon)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const ActionBar = styled.div`
|
const ActionBar = styled.div`
|
||||||
align-self: center;
|
|
||||||
|
|
||||||
/* order actionbar items horizontal */
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
/* ensure space between action bar items */
|
/* ensure space between action bar items */
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
/*
|
/*
|
||||||
* We have to use important, because plugins could use field or control classes like the editor-plugin does.
|
* We have to use important, because plugins could use field or control classes like the editor-plugin does.
|
||||||
@@ -113,7 +106,6 @@ const ActionBar = styled.div`
|
|||||||
|
|
||||||
const PrefixButton = styled.div`
|
const PrefixButton = styled.div`
|
||||||
border-right: 1px solid lightgray;
|
border-right: 1px solid lightgray;
|
||||||
margin-right: 0.5rem;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Breadcrumb: FC<Props> = ({
|
const Breadcrumb: FC<Props> = ({
|
||||||
@@ -176,7 +168,7 @@ const Breadcrumb: FC<Props> = ({
|
|||||||
const renderBreadcrumbNav = () => {
|
const renderBreadcrumbNav = () => {
|
||||||
let prefixButtons = null;
|
let prefixButtons = null;
|
||||||
if (preButtons) {
|
if (preButtons) {
|
||||||
prefixButtons = <PrefixButton>{preButtons}</PrefixButton>;
|
prefixButtons = <PrefixButton className="mr-2">{preButtons}</PrefixButton>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let homeUrl = baseUrl + "/";
|
let homeUrl = baseUrl + "/";
|
||||||
@@ -227,13 +219,7 @@ const Breadcrumb: FC<Props> = ({
|
|||||||
binder.hasExtension<extensionPoints.ReposSourcesEmptyActionbar>("repos.sources.empty.actionbar") &&
|
binder.hasExtension<extensionPoints.ReposSourcesEmptyActionbar>("repos.sources.empty.actionbar") &&
|
||||||
sources?._embedded?.children?.length === 0
|
sources?._embedded?.children?.length === 0
|
||||||
) {
|
) {
|
||||||
return (
|
return <ExtensionPoint name="repos.sources.empty.actionbar" props={{ repository, sources }} renderAll={true} />;
|
||||||
<ExtensionPoint
|
|
||||||
name="repos.sources.empty.actionbar"
|
|
||||||
props={{ repository, sources }}
|
|
||||||
renderAll={true}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (binder.hasExtension<extensionPoints.ReposSourcesActionbar>("repos.sources.actionbar")) {
|
if (binder.hasExtension<extensionPoints.ReposSourcesActionbar>("repos.sources.actionbar")) {
|
||||||
return <ExtensionPoint name="repos.sources.actionbar" props={extProps} renderAll={true} />;
|
return <ExtensionPoint name="repos.sources.actionbar" props={extProps} renderAll={true} />;
|
||||||
@@ -243,11 +229,15 @@ const Breadcrumb: FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="is-flex is-align-items-center is-justify-content-flex-end">
|
<div className={classNames("is-flex", "is-justify-content-flex-end", "is-align-items-center")}>
|
||||||
{renderBreadcrumbNav()}
|
{renderBreadcrumbNav()}
|
||||||
{<ActionBar className="my-2">{renderExtensionPoints()}</ActionBar>}
|
{
|
||||||
|
<ActionBar className={classNames("is-flex", "is-justify-content-flex-start", "is-align-self-center", "my-2")}>
|
||||||
|
{renderExtensionPoints()}
|
||||||
|
</ActionBar>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<hr className="is-marginless" />
|
<hr className="m-0" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,29 +44,6 @@ const NoEventWrapper = styled.article`
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AvatarWrapper = styled.figure`
|
|
||||||
margin-top: 0.8em;
|
|
||||||
margin-left: 1em !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FlexFullHeight = styled.div`
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
align-self: stretch;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FooterWrapper = styled.div`
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ContentRight = styled.div`
|
|
||||||
margin-left: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const RightMarginDiv = styled.div`
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const InheritFlexShrinkDiv = styled.div`
|
const InheritFlexShrinkDiv = styled.div`
|
||||||
flex-shrink: inherit;
|
flex-shrink: inherit;
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
@@ -81,11 +58,11 @@ const CardColumn: FC<Props> = ({
|
|||||||
footerLeft,
|
footerLeft,
|
||||||
footerRight,
|
footerRight,
|
||||||
action,
|
action,
|
||||||
className
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
const renderAvatar = avatar ? <AvatarWrapper className="media-left">{avatar}</AvatarWrapper> : null;
|
const renderAvatar = avatar ? <figure className="media-left mt-3 ml-4">{avatar}</figure> : null;
|
||||||
const renderDescription = description ? <p className="shorten-text">{description}</p> : null;
|
const renderDescription = description ? <p className="shorten-text">{description}</p> : null;
|
||||||
const renderContentRight = contentRight ? <ContentRight>{contentRight}</ContentRight> : null;
|
const renderContentRight = contentRight ? <div className="ml-auto">{contentRight}</div> : null;
|
||||||
|
|
||||||
let createLink = null;
|
let createLink = null;
|
||||||
if (link) {
|
if (link) {
|
||||||
@@ -94,7 +71,7 @@ const CardColumn: FC<Props> = ({
|
|||||||
createLink = (
|
createLink = (
|
||||||
<a
|
<a
|
||||||
className="overlay-column"
|
className="overlay-column"
|
||||||
onClick={e => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
action();
|
action();
|
||||||
}}
|
}}
|
||||||
@@ -108,7 +85,16 @@ const CardColumn: FC<Props> = ({
|
|||||||
{createLink}
|
{createLink}
|
||||||
<NoEventWrapper className={classNames("media", className)}>
|
<NoEventWrapper className={classNames("media", className)}>
|
||||||
{renderAvatar}
|
{renderAvatar}
|
||||||
<FlexFullHeight className={classNames("media-content", "text-box", "is-flex")}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"media-content",
|
||||||
|
"text-box",
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-direction-column",
|
||||||
|
"is-justify-content-space-around",
|
||||||
|
"is-align-self-stretch"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div className="is-flex">
|
<div className="is-flex">
|
||||||
<div className="is-clipped mb-0">
|
<div className="is-clipped mb-0">
|
||||||
<p className="shorten-text m-0">{title}</p>
|
<p className="shorten-text m-0">{title}</p>
|
||||||
@@ -116,13 +102,13 @@ const CardColumn: FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
{renderContentRight}
|
{renderContentRight}
|
||||||
</div>
|
</div>
|
||||||
<FooterWrapper className={classNames("level", "is-flex")}>
|
<div className={classNames("level", "is-flex", "pb-4")}>
|
||||||
<RightMarginDiv className="level-left is-hidden-mobile">{footerLeft}</RightMarginDiv>
|
<div className={classNames("level-left", "is-hidden-mobile", "mr-2")}>{footerLeft}</div>
|
||||||
<InheritFlexShrinkDiv className="level-right is-block is-mobile m-0 shorten-text">
|
<InheritFlexShrinkDiv className="level-right is-block is-mobile m-0 shorten-text">
|
||||||
{footerRight}
|
{footerRight}
|
||||||
</InheritFlexShrinkDiv>
|
</InheritFlexShrinkDiv>
|
||||||
</FooterWrapper>
|
</div>
|
||||||
</FlexFullHeight>
|
</div>
|
||||||
</NoEventWrapper>
|
</NoEventWrapper>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
name: ReactNode;
|
name: ReactNode;
|
||||||
@@ -36,25 +35,17 @@ type State = {
|
|||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Container = styled.div`
|
|
||||||
margin-bottom: 1em;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
padding: 0 0.75rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class CardColumnGroup extends React.Component<Props, State> {
|
export default class CardColumnGroup extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
collapsed: false
|
collapsed: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleCollapse = () => {
|
toggleCollapse = () => {
|
||||||
this.setState(prevState => ({
|
this.setState((prevState) => ({
|
||||||
collapsed: !prevState.collapsed
|
collapsed: !prevState.collapsed,
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -89,13 +80,13 @@ export default class CardColumnGroup extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<div className="mb-4">
|
||||||
<h2>
|
<h2>
|
||||||
<span className={classNames("is-size-4", "has-cursor-pointer")} onClick={this.toggleCollapse}>
|
<span className={classNames("is-size-4", "is-clickable")} onClick={this.toggleCollapse}>
|
||||||
<i className={classNames("fa", icon)} />
|
<i className={classNames("fa", icon)} />
|
||||||
</span>{" "}
|
</span>{" "}
|
||||||
{url ? (
|
{url ? (
|
||||||
<Link to={url} className={"has-text-dark"}>
|
<Link to={url} className="has-text-dark">
|
||||||
{name}
|
{name}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
@@ -103,9 +94,9 @@ export default class CardColumnGroup extends React.Component<Props, State> {
|
|||||||
)}
|
)}
|
||||||
</h2>
|
</h2>
|
||||||
<hr />
|
<hr />
|
||||||
<Wrapper className={classNames("columns", "card-columns", "is-multiline")}>{content}</Wrapper>
|
<div className={classNames("columns", "card-columns", "is-multiline", "mx-3", "my-0")}>{content}</div>
|
||||||
<div className="is-clearfix" />
|
<div className="is-clearfix" />
|
||||||
</Container>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const Wrapper = styled.div`
|
|||||||
|
|
||||||
const link = "/foo/bar";
|
const link = "/foo/bar";
|
||||||
const icon = <Icon name="icons fa-2x fa-fw" />;
|
const icon = <Icon name="icons fa-2x fa-fw" />;
|
||||||
const contentLeft = <strong className="is-marginless">main content</strong>;
|
const contentLeft = <strong className="m-0">main content</strong>;
|
||||||
const contentRight = <small>more text</small>;
|
const contentRight = <small>more text</small>;
|
||||||
|
|
||||||
storiesOf("CardColumnSmall", module)
|
storiesOf("CardColumnSmall", module)
|
||||||
|
|||||||
@@ -35,22 +35,6 @@ type Props = {
|
|||||||
footer?: ReactNode;
|
footer?: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FlexFullHeight = styled.div`
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-around;
|
|
||||||
align-self: stretch;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ContentLeft = styled.div`
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
overflow: hidden;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ContentRight = styled.div`
|
|
||||||
margin-left: auto;
|
|
||||||
align-items: start;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
const StyledLink = styled(Link)`
|
||||||
color: inherit;
|
color: inherit;
|
||||||
:hover {
|
:hover {
|
||||||
@@ -58,25 +42,30 @@ const StyledLink = styled(Link)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AvatarWrapper = styled.figure`
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const CardColumnSmall: FC<Props> = ({ link, avatar, contentLeft, contentRight, footer }) => {
|
const CardColumnSmall: FC<Props> = ({ link, avatar, contentLeft, contentRight, footer }) => {
|
||||||
const renderAvatar = avatar ? <AvatarWrapper className="media-left">{avatar}</AvatarWrapper> : null;
|
const renderAvatar = avatar ? <figure className={classNames("media-left", "mr-2")}>{avatar}</figure> : null;
|
||||||
const renderFooter = footer ? <small>{footer}</small> : null;
|
const renderFooter = footer ? <small>{footer}</small> : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledLink to={link}>
|
<StyledLink to={link}>
|
||||||
<div className="media">
|
<div className="media">
|
||||||
{renderAvatar}
|
{renderAvatar}
|
||||||
<FlexFullHeight className={classNames("media-content", "text-box", "is-flex")}>
|
<div
|
||||||
<div className="is-flex is-align-items-center">
|
className={classNames(
|
||||||
<ContentLeft>{contentLeft}</ContentLeft>
|
"media-content",
|
||||||
<ContentRight>{contentRight}</ContentRight>
|
"text-box",
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-direction-column",
|
||||||
|
"is-justify-content-space-around",
|
||||||
|
"is-align-self-stretch"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={classNames("is-flex", "is-align-items-center")}>
|
||||||
|
<div className={classNames("is-clipped", "mb-0")}>{contentLeft}</div>
|
||||||
|
<div className={classNames("is-align-items-start", "ml-auto")}>{contentRight}</div>
|
||||||
</div>
|
</div>
|
||||||
{renderFooter}
|
{renderFooter}
|
||||||
</FlexFullHeight>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,43 +22,38 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import DateFromNow from "./DateFromNow";
|
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
|
import DateFromNow from "./DateFromNow";
|
||||||
import DateShort from "./DateShort";
|
import DateShort from "./DateShort";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
const baseProps = {
|
const baseProps = {
|
||||||
timeZone: "Europe/Berlin",
|
timeZone: "Europe/Berlin",
|
||||||
baseDate: "2019-10-12T13:56:42+02:00"
|
baseDate: "2019-10-12T13:56:42+02:00",
|
||||||
};
|
};
|
||||||
|
|
||||||
const dates = [
|
const dates = [
|
||||||
"2009-06-30T18:30:00+02:00",
|
"2009-06-30T18:30:00+02:00",
|
||||||
"2019-06-30T18:30:00+02:00",
|
"2019-06-30T18:30:00+02:00",
|
||||||
"2019-10-12T13:56:40+02:00",
|
"2019-10-12T13:56:40+02:00",
|
||||||
"2019-10-11T13:56:40+02:00"
|
"2019-10-11T13:56:40+02:00",
|
||||||
];
|
];
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
padding: 2rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
storiesOf("Date", module)
|
storiesOf("Date", module)
|
||||||
.add("Date from now", () => (
|
.add("Date from now", () => (
|
||||||
<Wrapper>
|
<div className="p-5">
|
||||||
{dates.map(d => (
|
{dates.map((d) => (
|
||||||
<p>
|
<p>
|
||||||
<DateFromNow date={d} {...baseProps} />
|
<DateFromNow date={d} {...baseProps} />
|
||||||
</p>
|
</p>
|
||||||
))}
|
))}
|
||||||
</Wrapper>
|
</div>
|
||||||
))
|
))
|
||||||
.add("Short", () => (
|
.add("Short", () => (
|
||||||
<Wrapper>
|
<div className="p-5">
|
||||||
{dates.map(d => (
|
{dates.map((d) => (
|
||||||
<p>
|
<p>
|
||||||
<DateShort date={d} {...baseProps} />
|
<DateShort date={d} {...baseProps} />
|
||||||
</p>
|
</p>
|
||||||
))}
|
))}
|
||||||
</Wrapper>
|
</div>
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -22,14 +22,15 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC, ReactNode, useEffect } from "react";
|
import React, { FC, ReactNode, useEffect } from "react";
|
||||||
import ErrorNotification from "./ErrorNotification";
|
|
||||||
import { MissingLinkError, urls, useIndexLink } from "@scm-manager/ui-api";
|
|
||||||
import { RouteComponentProps, useLocation, withRouter } from "react-router-dom";
|
import { RouteComponentProps, useLocation, withRouter } from "react-router-dom";
|
||||||
import ErrorPage from "./ErrorPage";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { MissingLinkError, urls, useIndexLink } from "@scm-manager/ui-api";
|
||||||
|
import ErrorNotification from "./ErrorNotification";
|
||||||
|
import ErrorPage from "./ErrorPage";
|
||||||
import { Subtitle, Title } from "./layout";
|
import { Subtitle, Title } from "./layout";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
error?: Error;
|
error?: Error;
|
||||||
@@ -54,9 +55,6 @@ type ErrorDisplayProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const RedirectIconContainer = styled.div`
|
const RedirectIconContainer = styled.div`
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
min-height: 256px;
|
min-height: 256px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -69,7 +67,14 @@ const RedirectPage = () => {
|
|||||||
<div className="container">
|
<div className="container">
|
||||||
<Title>{t("errorBoundary.redirect.title")}</Title>
|
<Title>{t("errorBoundary.redirect.title")}</Title>
|
||||||
<Subtitle>{t("errorBoundary.redirect.subtitle")}</Subtitle>
|
<Subtitle>{t("errorBoundary.redirect.subtitle")}</Subtitle>
|
||||||
<RedirectIconContainer className="is-flex">
|
<RedirectIconContainer
|
||||||
|
className={classNames(
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-direction-column",
|
||||||
|
"is-justify-content-center",
|
||||||
|
"is-align-items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Icon name="directions" className="fa-7x" />
|
<Icon name="directions" className="fa-7x" />
|
||||||
</RedirectIconContainer>
|
</RedirectIconContainer>
|
||||||
</div>
|
</div>
|
||||||
@@ -108,7 +113,7 @@ const ErrorDisplay: FC<ErrorDisplayProps> = ({ error, errorInfo, fallback: Fallb
|
|||||||
|
|
||||||
const fallbackProps = {
|
const fallbackProps = {
|
||||||
error,
|
error,
|
||||||
errorInfo
|
errorInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <FallbackComponent {...fallbackProps} />;
|
return <FallbackComponent {...fallbackProps} />;
|
||||||
@@ -130,7 +135,7 @@ class ErrorBoundary extends React.Component<Props, State> {
|
|||||||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||||||
this.setState({
|
this.setState({
|
||||||
error,
|
error,
|
||||||
errorInfo
|
errorInfo,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,20 +21,10 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import styled from "styled-components";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import Help from "./Help";
|
import Help from "./Help";
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
margin: 5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Spacing = styled.div`
|
|
||||||
margin-top: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const longContent =
|
const longContent =
|
||||||
"Cleverness nuclear genuine static irresponsibility invited President Zaphod\n" +
|
"Cleverness nuclear genuine static irresponsibility invited President Zaphod\n" +
|
||||||
"Beeblebrox hyperspace ship. Another custard through computer-generated universe\n" +
|
"Beeblebrox hyperspace ship. Another custard through computer-generated universe\n" +
|
||||||
@@ -42,17 +32,17 @@ const longContent =
|
|||||||
"imaginative generator sweep.";
|
"imaginative generator sweep.";
|
||||||
|
|
||||||
storiesOf("Help", module)
|
storiesOf("Help", module)
|
||||||
.addDecorator(storyFn => <Wrapper>{storyFn()}</Wrapper>)
|
.addDecorator((storyFn) => <div className="m-6">{storyFn()}</div>)
|
||||||
.add("Default", () => <Help message="This is a help message" />)
|
.add("Default", () => <Help message="This is a help message" />)
|
||||||
.add("Multiline", () => (
|
.add("Multiline", () => (
|
||||||
<>
|
<>
|
||||||
<Spacing>
|
<div className="mt-4">
|
||||||
<label>With multiline (default):</label>
|
<label>With multiline (default):</label>
|
||||||
<Help message={longContent} />
|
<Help message={longContent} />
|
||||||
</Spacing>
|
</div>
|
||||||
<Spacing>
|
<div className="mt-4">
|
||||||
<label>Without multiline:</label>
|
<label>Without multiline:</label>
|
||||||
<Help message={longContent} multiline={false} />
|
<Help message={longContent} multiline={false} />
|
||||||
</Spacing>
|
</div>
|
||||||
</>
|
</>
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -33,22 +33,21 @@ type Props = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const HelpTooltip = styled(Tooltip)`
|
const AbsolutePositionTooltip = styled(Tooltip)`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding-left: 3px;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Help: FC<Props> = ({ message, multiline, className }) => (
|
const Help: FC<Props> = ({ message, multiline, className }) => (
|
||||||
<HelpTooltip
|
<AbsolutePositionTooltip
|
||||||
className={classNames("is-inline-block", multiline ? "has-tooltip-multiline" : undefined, className)}
|
className={classNames("is-inline-block", "pl-1", multiline ? "has-tooltip-multiline" : undefined, className)}
|
||||||
message={message}
|
message={message}
|
||||||
>
|
>
|
||||||
<HelpIcon />
|
<HelpIcon />
|
||||||
</HelpTooltip>
|
</AbsolutePositionTooltip>
|
||||||
);
|
);
|
||||||
|
|
||||||
Help.defaultProps = {
|
Help.defaultProps = {
|
||||||
multiline: true
|
multiline: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Help;
|
export default Help;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import Image from "./Image";
|
import Image from "./Image";
|
||||||
|
|
||||||
@@ -31,14 +32,10 @@ type Props = WithTranslation & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
min-height: 256px;
|
min-height: 256px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FixedSizedImage = styled(Image)`
|
const FixedSizedImage = styled(Image)`
|
||||||
margin-bottom: 0.75rem;
|
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
`;
|
`;
|
||||||
@@ -47,8 +44,15 @@ class Loading extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
const { message, t } = this.props;
|
const { message, t } = this.props;
|
||||||
return (
|
return (
|
||||||
<Wrapper className="is-flex">
|
<Wrapper
|
||||||
<FixedSizedImage src="/images/loading.svg" alt={t("loading.alt")} />
|
className={classNames(
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-direction-column",
|
||||||
|
"is-justify-content-center",
|
||||||
|
"is-align-items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<FixedSizedImage className="mb-3" src="/images/loading.svg" alt={t("loading.alt")} />
|
||||||
<p className="has-text-centered">{message}</p>
|
<p className="has-text-centered">{message}</p>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ const OverviewPageActions: FC<Props> = ({
|
|||||||
const link = createAbsoluteLink(inputLink);
|
const link = createAbsoluteLink(inputLink);
|
||||||
|
|
||||||
const groupSelector = groups && (
|
const groupSelector = groups && (
|
||||||
<div className={"column is-flex"}>
|
<div className="column is-flex">
|
||||||
<Select
|
<Select
|
||||||
className={"is-fullwidth"}
|
className="is-fullwidth"
|
||||||
options={groups.map((g) => ({ value: g, label: g }))}
|
options={groups.map((g) => ({ value: g, label: g }))}
|
||||||
value={currentGroup}
|
value={currentGroup}
|
||||||
onChange={groupSelected}
|
onChange={groupSelected}
|
||||||
@@ -89,9 +89,9 @@ const OverviewPageActions: FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={"columns is-tablet"}>
|
<div className="columns is-tablet">
|
||||||
{groupSelector}
|
{groupSelector}
|
||||||
<div className={"column"}>
|
<div className="column">
|
||||||
<FilterInput
|
<FilterInput
|
||||||
placeholder={searchPlaceholder}
|
placeholder={searchPlaceholder}
|
||||||
value={urls.getQueryStringFromLocation(location)}
|
value={urls.getQueryStringFromLocation(location)}
|
||||||
|
|||||||
@@ -21,37 +21,33 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Icon } from "@scm-manager/ui-components";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import SplitAndReplace from "./SplitAndReplace";
|
import SplitAndReplace from "./SplitAndReplace";
|
||||||
import { Icon } from "@scm-manager/ui-components";
|
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
margin: 2rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
storiesOf("SplitAndReplace", module).add("Simple replacement", () => {
|
storiesOf("SplitAndReplace", module).add("Simple replacement", () => {
|
||||||
const replacements = [
|
const replacements = [
|
||||||
{
|
{
|
||||||
textToReplace: "'",
|
textToReplace: "'",
|
||||||
replacement: <Icon name={"quote-left"} />,
|
replacement: <Icon name={"quote-left"} />,
|
||||||
replaceAll: true
|
replaceAll: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
textToReplace: "`",
|
textToReplace: "`",
|
||||||
replacement: <Icon name={"quote-right"} />,
|
replacement: <Icon name={"quote-right"} />,
|
||||||
replaceAll: true
|
replaceAll: true,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Wrapper>
|
<div className="m-6">
|
||||||
<SplitAndReplace text={"'So this is it,` said Arthur, 'We are going to die.`"} replacements={replacements} />
|
<SplitAndReplace text={"'So this is it,` said Arthur, 'We are going to die.`"} replacements={replacements} />
|
||||||
</Wrapper>
|
</div>
|
||||||
<Wrapper>
|
<div className="m-6">
|
||||||
<SplitAndReplace text={"'Yes,` said Ford, 'except... no! Wait a minute!`"} replacements={replacements} />
|
<SplitAndReplace text={"'Yes,` said Ford, 'except... no! Wait a minute!`"} replacements={replacements} />
|
||||||
</Wrapper>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,10 +21,9 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC, HTMLAttributes } from "react";
|
import React, { FC } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Color, Size } from "./styleConstants";
|
import { Color, Size } from "./styleConstants";
|
||||||
import styled, { css } from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -39,19 +38,7 @@ type Props = {
|
|||||||
onRemove?: () => void;
|
onRemove?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type InnerTagProps = HTMLAttributes<HTMLSpanElement> & {
|
const smallClassNames = classNames("p-1", "is-size-7", "has-text-weight-bold");
|
||||||
small: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const smallMixin = css`
|
|
||||||
font-size: 0.7rem !important;
|
|
||||||
padding: 0.25rem !important;
|
|
||||||
font-weight: bold;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const InnerTag = styled.span<InnerTagProps>`
|
|
||||||
${(props) => props.small && smallMixin};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Tag: FC<Props> = ({
|
const Tag: FC<Props> = ({
|
||||||
className,
|
className,
|
||||||
@@ -82,20 +69,26 @@ const Tag: FC<Props> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InnerTag
|
<span
|
||||||
className={classNames("tag", `is-${color}`, `is-${size}`, className, {
|
className={classNames(
|
||||||
|
"tag",
|
||||||
|
`is-${color}`,
|
||||||
|
`is-${size}`,
|
||||||
|
className,
|
||||||
|
{
|
||||||
"is-outlined": outlined,
|
"is-outlined": outlined,
|
||||||
"is-rounded": rounded,
|
"is-rounded": rounded,
|
||||||
"has-cursor-pointer": onClick,
|
"is-clickable": onClick,
|
||||||
})}
|
},
|
||||||
|
size === "small" && smallClassNames
|
||||||
|
)}
|
||||||
title={title}
|
title={title}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
small={size === "small"}
|
|
||||||
>
|
>
|
||||||
{showIcon}
|
{showIcon}
|
||||||
{label}
|
{label}
|
||||||
{children}
|
{children}
|
||||||
</InnerTag>
|
</span>
|
||||||
{showDelete}
|
{showDelete}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,17 +24,16 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import Button, { ButtonProps } from "./Button";
|
import Button, { ButtonProps } from "./Button";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
margin-top: 2em;
|
|
||||||
padding: 1em 1em;
|
|
||||||
border: 2px solid #e9f7fd;
|
border: 2px solid #e9f7fd;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default class CreateButton extends React.Component<ButtonProps> {
|
export default class CreateButton extends React.Component<ButtonProps> {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Wrapper className="has-text-centered">
|
<Wrapper className={classNames("has-text-centered", "mt-5", "p-4")}>
|
||||||
<Button color="primary" {...this.props} />
|
<Button color="primary" {...this.props} />
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -37,20 +37,8 @@ type Props = {
|
|||||||
errorMessage: string;
|
errorMessage: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledLevel = styled(Level)`
|
|
||||||
align-items: stretch;
|
|
||||||
margin-bottom: 1rem !important; // same margin as field
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FullWidthInputField = styled(InputField)`
|
const FullWidthInputField = styled(InputField)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-right: 1.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledField = styled.div.attrs(() => ({
|
|
||||||
className: "field"
|
|
||||||
}))`
|
|
||||||
align-self: flex-end;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AddEntryToTableField: FC<Props> = ({
|
const AddEntryToTableField: FC<Props> = ({
|
||||||
@@ -60,7 +48,7 @@ const AddEntryToTableField: FC<Props> = ({
|
|||||||
fieldLabel,
|
fieldLabel,
|
||||||
helpText,
|
helpText,
|
||||||
validateEntry,
|
validateEntry,
|
||||||
errorMessage
|
errorMessage,
|
||||||
}) => {
|
}) => {
|
||||||
const [entryToAdd, setEntryToAdd] = useState("");
|
const [entryToAdd, setEntryToAdd] = useState("");
|
||||||
|
|
||||||
@@ -89,9 +77,11 @@ const AddEntryToTableField: FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledLevel
|
<Level
|
||||||
|
className="is-align-items-stretch mb-4"
|
||||||
children={
|
children={
|
||||||
<FullWidthInputField
|
<FullWidthInputField
|
||||||
|
className="mr-5"
|
||||||
label={fieldLabel}
|
label={fieldLabel}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
onChange={handleAddEntryChange}
|
onChange={handleAddEntryChange}
|
||||||
@@ -103,13 +93,13 @@ const AddEntryToTableField: FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
right={
|
right={
|
||||||
<StyledField>
|
<div className="field is-align-self-flex-end">
|
||||||
<AddButton
|
<AddButton
|
||||||
label={buttonLabel}
|
label={buttonLabel}
|
||||||
action={addButtonClicked}
|
action={addButtonClicked}
|
||||||
disabled={disabled || entryToAdd === "" || !isValid()}
|
disabled={disabled || entryToAdd === "" || !isValid()}
|
||||||
/>
|
/>
|
||||||
</StyledField>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,37 +21,31 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import styled from "styled-components";
|
|
||||||
import { storiesOf } from "@storybook/react";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import AddKeyValueEntryToTableField from "./AddKeyValueEntryToTableField";
|
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
|
import { storiesOf } from "@storybook/react";
|
||||||
const Spacing = styled.div`
|
import AddKeyValueEntryToTableField from "./AddKeyValueEntryToTableField";
|
||||||
padding: 2em;
|
|
||||||
`;
|
|
||||||
|
|
||||||
storiesOf("Forms|AddKeyValueEntryToTableField", module)
|
storiesOf("Forms|AddKeyValueEntryToTableField", module)
|
||||||
.addDecorator(story => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||||
.add("Default", () => (
|
.add("Default", () => (
|
||||||
<Spacing>
|
<div className="m-6">
|
||||||
<AddKeyValueEntryToTableField
|
<AddKeyValueEntryToTableField
|
||||||
keyFieldLabel="Key"
|
keyFieldLabel="Key"
|
||||||
valueFieldLabel="Value"
|
valueFieldLabel="Value"
|
||||||
buttonLabel="Add to table"
|
buttonLabel="Add to Table"
|
||||||
addEntry={(key, value) => {console.log(key, value)}}
|
addEntry={() => null}
|
||||||
/>
|
/>
|
||||||
</Spacing>
|
</div>
|
||||||
))
|
))
|
||||||
.add("Disabled", () => (
|
.add("Disabled", () => (
|
||||||
<Spacing>
|
<div className="m-6">
|
||||||
<AddKeyValueEntryToTableField
|
<AddKeyValueEntryToTableField
|
||||||
keyFieldLabel="Key"
|
keyFieldLabel="Key"
|
||||||
valueFieldLabel="Value"
|
valueFieldLabel="Value"
|
||||||
buttonLabel="Add to table"
|
buttonLabel="Add to Table"
|
||||||
addEntry={() => {}}
|
addEntry={() => null}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
/>
|
/>
|
||||||
</Spacing>
|
</div>
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, useState } from "react";
|
import React, { FC, useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import InputField from "./InputField";
|
import InputField from "./InputField";
|
||||||
@@ -39,13 +38,7 @@ type Props = {
|
|||||||
validateEntry?: (p: string) => boolean;
|
validateEntry?: (p: string) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const InputLevel = styled.div`
|
const FullWidthInputField = styled(InputField)`
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledInputField = styled(InputField)`
|
|
||||||
margin-right: 1.5rem;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -62,7 +55,7 @@ const AddKeyValueEntryToTableField: FC<Props> = ({
|
|||||||
valueHelpText,
|
valueHelpText,
|
||||||
validateEntry,
|
validateEntry,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
addEntry
|
addEntry,
|
||||||
}) => {
|
}) => {
|
||||||
const [key, setKey] = useState("");
|
const [key, setKey] = useState("");
|
||||||
const [value, setValue] = useState("");
|
const [value, setValue] = useState("");
|
||||||
@@ -77,13 +70,14 @@ const AddKeyValueEntryToTableField: FC<Props> = ({
|
|||||||
|
|
||||||
const add = () => {
|
const add = () => {
|
||||||
addEntry(key, value);
|
addEntry(key, value);
|
||||||
setKey("")
|
setKey("");
|
||||||
setValue("");
|
setValue("");
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InputLevel>
|
<div className="is-flex is-justify-content-space-between">
|
||||||
<StyledInputField
|
<FullWidthInputField
|
||||||
|
className="mr-5"
|
||||||
label={keyFieldLabel}
|
label={keyFieldLabel}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
onChange={setKey}
|
onChange={setKey}
|
||||||
@@ -93,7 +87,8 @@ const AddKeyValueEntryToTableField: FC<Props> = ({
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
helpText={keyHelpText}
|
helpText={keyHelpText}
|
||||||
/>
|
/>
|
||||||
<StyledInputField
|
<FullWidthInputField
|
||||||
|
className="mr-5"
|
||||||
label={valueFieldLabel}
|
label={valueFieldLabel}
|
||||||
errorMessage={errorMessage}
|
errorMessage={errorMessage}
|
||||||
onChange={setValue}
|
onChange={setValue}
|
||||||
@@ -108,7 +103,7 @@ const AddKeyValueEntryToTableField: FC<Props> = ({
|
|||||||
action={add}
|
action={add}
|
||||||
disabled={disabled || !key || !value || !isValid(key) || !isValid(value)}
|
disabled={disabled || !key || !value || !isValid(key) || !isValid(value)}
|
||||||
/>
|
/>
|
||||||
</InputLevel>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ type Props = {
|
|||||||
|
|
||||||
const FullWidthAutocomplete = styled(Autocomplete)`
|
const FullWidthAutocomplete = styled(Autocomplete)`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-right: 1.5rem;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AutocompleteAddEntryToTableField: FC<Props> = ({
|
const AutocompleteAddEntryToTableField: FC<Props> = ({
|
||||||
@@ -79,6 +78,7 @@ const AutocompleteAddEntryToTableField: FC<Props> = ({
|
|||||||
<Level
|
<Level
|
||||||
children={
|
children={
|
||||||
<FullWidthAutocomplete
|
<FullWidthAutocomplete
|
||||||
|
className="mr-5"
|
||||||
label={fieldLabel}
|
label={fieldLabel}
|
||||||
loadSuggestions={loadSuggestions}
|
loadSuggestions={loadSuggestions}
|
||||||
valueSelected={handleAddEntryChange}
|
valueSelected={handleAddEntryChange}
|
||||||
|
|||||||
@@ -22,18 +22,9 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { ChangeEvent, FC, FocusEvent } from "react";
|
import React, { ChangeEvent, FC, FocusEvent } from "react";
|
||||||
import { Help } from "../index";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import { createFormFieldWrapper, FieldProps, FieldType, isLegacy, isUsingRef } from "./FormFieldTypes";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
import { Help } from "../index";
|
||||||
const StyledRadio = styled.label`
|
import { createFormFieldWrapper, FieldProps, FieldType, isLegacy, isUsingRef } from "./FormFieldTypes";
|
||||||
margin-right: 0.5em;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const InlineFieldset = styled.fieldset`
|
|
||||||
display: inline-block;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type BaseProps = {
|
type BaseProps = {
|
||||||
label?: string;
|
label?: string;
|
||||||
@@ -47,7 +38,12 @@ type BaseProps = {
|
|||||||
readOnly?: boolean;
|
readOnly?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const InnerRadio: FC<FieldProps<BaseProps, HTMLInputElement, boolean>> = ({ name, defaultChecked, readOnly, ...props }) => {
|
const InnerRadio: FC<FieldProps<BaseProps, HTMLInputElement, boolean>> = ({
|
||||||
|
name,
|
||||||
|
defaultChecked,
|
||||||
|
readOnly,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
const renderHelp = () => {
|
const renderHelp = () => {
|
||||||
const helpText = props.helpText;
|
const helpText = props.helpText;
|
||||||
if (helpText) {
|
if (helpText) {
|
||||||
@@ -76,13 +72,13 @@ const InnerRadio: FC<FieldProps<BaseProps, HTMLInputElement, boolean>> = ({ name
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InlineFieldset disabled={readOnly}>
|
<fieldset className="is-inline-block" disabled={readOnly}>
|
||||||
{/*
|
{/*
|
||||||
we have to ignore the next line,
|
we have to ignore the next line,
|
||||||
because jsx label does not the custom disabled attribute
|
because jsx label does not the custom disabled attribute
|
||||||
but bulma does.
|
but bulma does.
|
||||||
// @ts-ignore */}
|
// @ts-ignore */}
|
||||||
<StyledRadio className={classNames("radio", props.className)} disabled={props.disabled}>
|
<label className={classNames("radio", "mr-2", props.className)} disabled={props.disabled}>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name={name}
|
name={name}
|
||||||
@@ -96,8 +92,8 @@ const InnerRadio: FC<FieldProps<BaseProps, HTMLInputElement, boolean>> = ({ name
|
|||||||
/>{" "}
|
/>{" "}
|
||||||
{props.label}
|
{props.label}
|
||||||
{renderHelp()}
|
{renderHelp()}
|
||||||
</StyledRadio>
|
</label>
|
||||||
</InlineFieldset>
|
</fieldset>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,25 +22,21 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC, ReactNode } from "react";
|
import React, { FC, ReactNode } from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: ReactNode;
|
title: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Title = styled.div`
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Menu = styled.ul`
|
const Menu = styled.ul`
|
||||||
padding-left: 1.1rem;
|
padding-left: 1.1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FooterSection: FC<Props> = ({ title, children }) => {
|
const FooterSection: FC<Props> = ({ title, children }) => {
|
||||||
return (
|
return (
|
||||||
<section className="column is-one-third">
|
<section className={classNames("column", "is-one-third")}>
|
||||||
<Title>{title}</Title>
|
<div className={classNames("has-text-weight-bold", "mb-2")}>{title}</div>
|
||||||
<Menu>{children}</Menu>
|
<Menu>{children}</Menu>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,25 +21,12 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, ReactNode } from "react";
|
import React, { FC, ReactNode } from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
const TitleWrapper = styled.div`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0.75rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: bold;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Separator = styled.div`
|
const Separator = styled.div`
|
||||||
border-bottom: 1px solid rgb(219, 219, 219, 0.5);
|
border-bottom: 1px solid rgb(219, 219, 219, 0.5);
|
||||||
margin: 0 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Box = styled.div`
|
|
||||||
padding: 0.5rem;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -51,14 +38,16 @@ const GroupEntries: FC<Props> = ({ namespaceHeader, elements }) => {
|
|||||||
const content = elements.map((entry, index) => (
|
const content = elements.map((entry, index) => (
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
<div>{entry}</div>
|
<div>{entry}</div>
|
||||||
{index + 1 !== elements.length ? <Separator /> : null}
|
{index + 1 !== elements.length ? <Separator className="mx-4" /> : null}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
));
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TitleWrapper>{namespaceHeader}</TitleWrapper>
|
<div className={classNames("is-flex", "is-align-items-center", "is-size-6", "has-text-weight-bold", "p-3")}>
|
||||||
<Box className="box">{content}</Box>
|
{namespaceHeader}
|
||||||
|
</div>
|
||||||
|
<div className={classNames("box", "p-2")}>{content}</div>
|
||||||
<div className="is-clearfix" />
|
<div className="is-clearfix" />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,7 +22,6 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import styled from "styled-components";
|
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
@@ -31,16 +30,12 @@ import GroupEntry from "./GroupEntry";
|
|||||||
import { Button, ButtonGroup } from "../buttons";
|
import { Button, ButtonGroup } from "../buttons";
|
||||||
import copyToClipboard from "../CopyToClipboard";
|
import copyToClipboard from "../CopyToClipboard";
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
margin: 2rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const link = "/foo/bar";
|
const link = "/foo/bar";
|
||||||
const icon = <Icon name="icons fa-2x fa-fw" />;
|
const icon = <Icon name="icons fa-2x fa-fw" />;
|
||||||
const name = <strong className="is-marginless">main content</strong>;
|
const name = <strong className="m-0">main content</strong>;
|
||||||
const description = <small>more text</small>;
|
const description = <small>more text</small>;
|
||||||
const longName = (
|
const longName = (
|
||||||
<strong className="is-marginless">
|
<strong className="m-0">
|
||||||
Very-important-repository-with-a-particular-long-but-easily-rememberable-name-which-also-is-written-in-kebab-case
|
Very-important-repository-with-a-particular-long-but-easily-rememberable-name-which-also-is-written-in-kebab-case
|
||||||
</strong>
|
</strong>
|
||||||
);
|
);
|
||||||
@@ -56,7 +51,7 @@ const contentRight = (
|
|||||||
|
|
||||||
storiesOf("GroupEntry", module)
|
storiesOf("GroupEntry", module)
|
||||||
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
.addDecorator((story) => <MemoryRouter initialEntries={["/"]}>{story()}</MemoryRouter>)
|
||||||
.addDecorator((storyFn) => <Wrapper>{storyFn()}</Wrapper>)
|
.addDecorator((storyFn) => <div className="m-5">{storyFn()}</div>)
|
||||||
.add("Default", () => (
|
.add("Default", () => (
|
||||||
<GroupEntry link={link} avatar={icon} name={name} description={description} contentRight={contentRight} />
|
<GroupEntry link={link} avatar={icon} name={name} description={description} contentRight={contentRight} />
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -21,18 +21,14 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, ReactNode } from "react";
|
import React, { FC, ReactNode } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
const StyledGroupEntry = styled.div`
|
const StyledGroupEntry = styled.div`
|
||||||
max-height: calc(90px - 1.5rem);
|
max-height: calc(90px - 1.5rem);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0.5rem;
|
|
||||||
align-items: center;
|
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -49,7 +45,6 @@ const OverlayLink = styled(Link)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Avatar = styled.div`
|
const Avatar = styled.div`
|
||||||
padding-right: 1rem;
|
|
||||||
.predefined-avatar {
|
.predefined-avatar {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
@@ -57,12 +52,7 @@ const Avatar = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Name = styled.div`
|
|
||||||
padding: 0 0.25rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Description = styled.p`
|
const Description = styled.p`
|
||||||
padding: 0 0.25rem;
|
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@@ -72,30 +62,14 @@ const Description = styled.p`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const ContentLeft = styled.div`
|
const ContentLeft = styled.div`
|
||||||
display: flex;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
align-items: center;
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ContentRight = styled.div`
|
const ContentRight = styled.div`
|
||||||
display: flex;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
justify-content: flex-end;
|
|
||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
padding-left: 2rem;
|
|
||||||
margin-bottom: -10px;
|
margin-bottom: -10px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NameDescriptionWrapper = styled.div`
|
|
||||||
overflow: hidden;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
|
||||||
position: relative;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title?: string;
|
title?: string;
|
||||||
avatar: string | ReactNode;
|
avatar: string | ReactNode;
|
||||||
@@ -107,19 +81,32 @@ type Props = {
|
|||||||
|
|
||||||
const GroupEntry: FC<Props> = ({ link, avatar, title, name, description, contentRight }) => {
|
const GroupEntry: FC<Props> = ({ link, avatar, title, name, description, contentRight }) => {
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<div className="is-relative">
|
||||||
<OverlayLink to={link} />
|
<OverlayLink to={link} />
|
||||||
<StyledGroupEntry title={title}>
|
<StyledGroupEntry
|
||||||
<ContentLeft>
|
className={classNames("is-flex", "is-justify-content-space-between", "is-align-items-center", "p-2")}
|
||||||
<Avatar>{avatar}</Avatar>
|
title={title}
|
||||||
<NameDescriptionWrapper>
|
>
|
||||||
<Name>{name}</Name>
|
<ContentLeft className={classNames("is-flex", "is-flex-grow-1", "is-align-items-center")}>
|
||||||
<Description>{description}</Description>
|
<Avatar className="mr-4">{avatar}</Avatar>
|
||||||
</NameDescriptionWrapper>
|
<div className={classNames("is-flex-grow-1", "is-clipped")}>
|
||||||
|
<div className="mx-1">{name}</div>
|
||||||
|
<Description className="mx-1">{description}</Description>
|
||||||
|
</div>
|
||||||
</ContentLeft>
|
</ContentLeft>
|
||||||
<ContentRight className="is-hidden-touch">{contentRight}</ContentRight>
|
<ContentRight
|
||||||
|
className={classNames(
|
||||||
|
"is-hidden-touch",
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-shrink-0",
|
||||||
|
"is-justify-content-flex-end",
|
||||||
|
"pl-5"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{contentRight}
|
||||||
|
</ContentRight>
|
||||||
</StyledGroupEntry>
|
</StyledGroupEntry>
|
||||||
</Wrapper>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -45,22 +45,14 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const PageActionContainer = styled.div`
|
const PageActionContainer = styled.div`
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
// every child except first
|
// every child except first
|
||||||
> * ~ * {
|
> * ~ * {
|
||||||
margin-left: 1.25rem;
|
margin-left: 1.25rem;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MarginLeft = styled.div`
|
const MaxTitleHeight = styled.div`
|
||||||
margin-left: 0.5rem;
|
// remove blank space in repo create form
|
||||||
`;
|
|
||||||
|
|
||||||
const FlexContainer = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
height: 2.25rem;
|
height: 2.25rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -98,12 +90,19 @@ export default class Page extends React.Component<Props> {
|
|||||||
|
|
||||||
let pageActions = null;
|
let pageActions = null;
|
||||||
let pageActionsExists = false;
|
let pageActionsExists = false;
|
||||||
React.Children.forEach(children, child => {
|
React.Children.forEach(children, (child) => {
|
||||||
if (child && !error) {
|
if (child && !error) {
|
||||||
if (this.isPageAction(child)) {
|
if (this.isPageAction(child)) {
|
||||||
pageActions = (
|
pageActions = (
|
||||||
<PageActionContainer
|
<PageActionContainer
|
||||||
className={classNames("column", "is-three-fifths", "is-mobile-action-spacing", "is-flex-tablet")}
|
className={classNames(
|
||||||
|
"column",
|
||||||
|
"is-three-fifths",
|
||||||
|
"is-mobile-action-spacing",
|
||||||
|
"is-flex-tablet",
|
||||||
|
"is-justify-content-flex-end",
|
||||||
|
"is-align-items-center"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{child}
|
{child}
|
||||||
</PageActionContainer>
|
</PageActionContainer>
|
||||||
@@ -119,10 +118,10 @@ export default class Page extends React.Component<Props> {
|
|||||||
<>
|
<>
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<FlexContainer>
|
<MaxTitleHeight className="is-flex">
|
||||||
<Title title={this.getTextualTitle()}>{this.getTitleComponent()}</Title>
|
<Title title={this.getTextualTitle()}>{this.getTitleComponent()}</Title>
|
||||||
{afterTitle && <MarginLeft>{afterTitle}</MarginLeft>}
|
{afterTitle && <div className="ml-2">{afterTitle}</div>}
|
||||||
</FlexContainer>
|
</MaxTitleHeight>
|
||||||
{subtitle ? <Subtitle>{subtitle}</Subtitle> : null}
|
{subtitle ? <Subtitle>{subtitle}</Subtitle> : null}
|
||||||
</div>
|
</div>
|
||||||
{pageActions}
|
{pageActions}
|
||||||
@@ -145,7 +144,7 @@ export default class Page extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const content: ReactNode[] = [];
|
const content: ReactNode[] = [];
|
||||||
React.Children.forEach(children, child => {
|
React.Children.forEach(children, (child) => {
|
||||||
if (child) {
|
if (child) {
|
||||||
if (!this.isPageAction(child)) {
|
if (!this.isPageAction(child)) {
|
||||||
content.push(child);
|
content.push(child);
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export const Modal: FC<Props> = ({
|
|||||||
<div className="modal-background" onClick={closeFunction} />
|
<div className="modal-background" onClick={closeFunction} />
|
||||||
<SizedModal className="modal-card" size={size}>
|
<SizedModal className="modal-card" size={size}>
|
||||||
<header className={classNames("modal-card-head", `has-background-${headColor}`)}>
|
<header className={classNames("modal-card-head", `has-background-${headColor}`)}>
|
||||||
<p className={`modal-card-title is-marginless has-text-${headTextColor}`}>{title}</p>
|
<p className={`modal-card-title m-0 has-text-${headTextColor}`}>{title}</p>
|
||||||
<button className="delete" aria-label="close" onClick={closeFunction} />
|
<button className="delete" aria-label="close" onClick={closeFunction} />
|
||||||
</header>
|
</header>
|
||||||
<section className="modal-card-body">{body}</section>
|
<section className="modal-card-body">{body}</section>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ const SecondaryNavigation: FC<Props> = ({ label, children, collapsible = true })
|
|||||||
<SectionContainer className="menu">
|
<SectionContainer className="menu">
|
||||||
<div>
|
<div>
|
||||||
<MenuLabel
|
<MenuLabel
|
||||||
className={classNames("menu-label", { "has-cursor-pointer": collapsible })}
|
className={classNames("menu-label", { "is-clickable": collapsible })}
|
||||||
collapsed={isCollapsed}
|
collapsed={isCollapsed}
|
||||||
onClick={toggleCollapseState}
|
onClick={toggleCollapseState}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type ContainerProps = {
|
|||||||
const PopoverContainer = styled.div<ContainerProps>`
|
const PopoverContainer = styled.div<ContainerProps>`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
width: ${props => props.width}px;
|
width: ${(props) => props.width}px;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
@@ -54,7 +54,7 @@ const PopoverContainer = styled.div<ContainerProps>`
|
|||||||
height: 0;
|
height: 0;
|
||||||
width: 0;
|
width: 0;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
left: ${props => props.width / 2}px;
|
left: ${(props) => props.width / 2}px;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
border-bottom-color: white;
|
border-bottom-color: white;
|
||||||
border-left-color: white;
|
border-left-color: white;
|
||||||
@@ -67,15 +67,11 @@ const PopoverContainer = styled.div<ContainerProps>`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SmallHr = styled.hr`
|
|
||||||
margin: 0.5em 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const PopoverHeading = styled.div`
|
const PopoverHeading = styled.div`
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Popover: FC<Props> = props => {
|
const Popover: FC<Props> = (props) => {
|
||||||
if (!props.show) {
|
if (!props.show) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -93,13 +89,13 @@ const InnerPopover: FC<Props> = ({ title, show, width, offsetTop, offsetLeft, di
|
|||||||
|
|
||||||
const onMouseEnter = () => {
|
const onMouseEnter = () => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "enter-popover"
|
type: "enter-popover",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onMouseLeave = () => {
|
const onMouseLeave = () => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "leave-popover"
|
type: "leave-popover",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,20 +105,20 @@ const InnerPopover: FC<Props> = ({ title, show, width, offsetTop, offsetLeft, di
|
|||||||
<PopoverContainer
|
<PopoverContainer
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
className={"box"}
|
className="box"
|
||||||
style={{ top: `${top}px`, left: `${left}px` }}
|
style={{ top: `${top}px`, left: `${left}px` }}
|
||||||
width={width!}
|
width={width!}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
<PopoverHeading>{title}</PopoverHeading>
|
<PopoverHeading>{title}</PopoverHeading>
|
||||||
<SmallHr />
|
<hr className="my-2" />
|
||||||
{children}
|
{children}
|
||||||
</PopoverContainer>
|
</PopoverContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Popover.defaultProps = {
|
Popover.defaultProps = {
|
||||||
width: 120
|
width: 120,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Popover;
|
export default Popover;
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import Tooltip from "../Tooltip";
|
|||||||
|
|
||||||
const Button = styled.a`
|
const Button = styled.a`
|
||||||
width: 50px;
|
width: 50px;
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #33b2e8;
|
color: #33b2e8;
|
||||||
}
|
}
|
||||||
@@ -47,7 +46,7 @@ const DiffButton: FC<Props> = ({ icon, tooltip, onClick }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip message={tooltip} location="top">
|
<Tooltip message={tooltip} location="top">
|
||||||
<Button aria-label={tooltip} className="button" onClick={handleClick}>
|
<Button aria-label={tooltip} className="button is-clickable" onClick={handleClick}>
|
||||||
<i className={`fas fa-${icon}`} />
|
<i className={`fas fa-${icon}`} />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -69,22 +69,6 @@ const FullWidthTitleHeader = styled.div`
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TitleWrapper = styled.span`
|
|
||||||
margin-left: 0.25rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const AlignRight = styled.div`
|
|
||||||
margin-left: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const HunkDivider = styled.hr`
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ChangeTypeTag = styled(Tag)`
|
|
||||||
margin-left: 0.75rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const MarginlessModalContent = styled.div`
|
const MarginlessModalContent = styled.div`
|
||||||
margin: -1.25rem;
|
margin: -1.25rem;
|
||||||
|
|
||||||
@@ -319,7 +303,7 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
} else if (i > 0) {
|
} else if (i > 0) {
|
||||||
items.push(
|
items.push(
|
||||||
<Decoration>
|
<Decoration>
|
||||||
<HunkDivider />
|
<hr className="my-2" />
|
||||||
</Decoration>
|
</Decoration>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -403,8 +387,8 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
|
|
||||||
const color = value === "added" ? "success" : value === "deleted" ? "danger" : "info";
|
const color = value === "added" ? "success" : value === "deleted" ? "danger" : "info";
|
||||||
return (
|
return (
|
||||||
<ChangeTypeTag
|
<Tag
|
||||||
className={classNames("has-text-weight-normal")}
|
className={classNames("has-text-weight-normal", "ml-3")}
|
||||||
rounded={true}
|
rounded={true}
|
||||||
outlined={true}
|
outlined={true}
|
||||||
color={color}
|
color={color}
|
||||||
@@ -431,7 +415,7 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
|
|
||||||
const fileAnnotations = fileAnnotationFactory ? fileAnnotationFactory(file) : null;
|
const fileAnnotations = fileAnnotationFactory ? fileAnnotationFactory(file) : null;
|
||||||
const innerContent = (
|
const innerContent = (
|
||||||
<div className="panel-block is-paddingless">
|
<div className="panel-block p-0">
|
||||||
{fileAnnotations}
|
{fileAnnotations}
|
||||||
<TokenizedDiffView className={viewType} viewType={viewType} file={file}>
|
<TokenizedDiffView className={viewType} viewType={viewType} file={file}>
|
||||||
{(hunks: HunkType[]) =>
|
{(hunks: HunkType[]) =>
|
||||||
@@ -475,13 +459,13 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
</MenuContext.Consumer>
|
</MenuContext.Consumer>
|
||||||
);
|
);
|
||||||
const headerButtons = (
|
const headerButtons = (
|
||||||
<AlignRight className={classNames("level-right", "is-flex")}>
|
<div className={classNames("level-right", "is-flex", "ml-auto")}>
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
{sideBySideToggle}
|
{sideBySideToggle}
|
||||||
{openInFullscreen}
|
{openInFullscreen}
|
||||||
{fileControls}
|
{fileControls}
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</AlignRight>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
let errorModal;
|
let errorModal;
|
||||||
@@ -506,14 +490,14 @@ class DiffFile extends React.Component<Props, State> {
|
|||||||
<div className="panel-heading">
|
<div className="panel-heading">
|
||||||
<div className={classNames("level", "is-flex-wrap-wrap")}>
|
<div className={classNames("level", "is-flex-wrap-wrap")}>
|
||||||
<FullWidthTitleHeader
|
<FullWidthTitleHeader
|
||||||
className={classNames("level-left", "is-flex", "has-cursor-pointer")}
|
className={classNames("level-left", "is-flex", "is-clickable")}
|
||||||
onClick={this.toggleCollapse}
|
onClick={this.toggleCollapse}
|
||||||
title={this.hoverFileTitle(file)}
|
title={this.hoverFileTitle(file)}
|
||||||
>
|
>
|
||||||
{collapseIcon}
|
{collapseIcon}
|
||||||
<TitleWrapper className={classNames("is-ellipsis-overflow", "is-size-6")}>
|
<span className={classNames("is-ellipsis-overflow", "is-size-6", "ml-1")}>
|
||||||
{this.renderFileTitle(file)}
|
{this.renderFileTitle(file)}
|
||||||
</TitleWrapper>
|
</span>
|
||||||
{this.renderChangeTag(file)}
|
{this.renderChangeTag(file)}
|
||||||
</FullWidthTitleHeader>
|
</FullWidthTitleHeader>
|
||||||
{headerButtons}
|
{headerButtons}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const HealthCheckFailureDetail: FC<Props> = ({ active, closeFunction, failures }
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
body={
|
body={
|
||||||
<div className={"content"}>
|
<div className="content">
|
||||||
<HealthCheckFailureList failures={failures} />
|
<HealthCheckFailureList failures={failures} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,14 +28,12 @@ import styled from "styled-components";
|
|||||||
|
|
||||||
const HunkDivider = styled.div`
|
const HunkDivider = styled.div`
|
||||||
background: #98d8f3;
|
background: #98d8f3;
|
||||||
font-size: 0.7rem;
|
|
||||||
padding-left: 1.78em;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const HunkExpandDivider: FC = ({ children }) => {
|
const HunkExpandDivider: FC = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<Decoration>
|
<Decoration>
|
||||||
<HunkDivider>{children}</HunkDivider>
|
<HunkDivider className="is-size-7 pl-5">{children}</HunkDivider>
|
||||||
</Decoration>
|
</Decoration>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
import React, { FC, useState } from "react";
|
import React, { FC, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
icon: string;
|
icon: string;
|
||||||
@@ -32,10 +31,6 @@ type Props = {
|
|||||||
onClick: () => Promise<any>;
|
onClick: () => Promise<any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExpandLink = styled.span`
|
|
||||||
cursor: pointer;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const HunkExpandLink: FC<Props> = ({ icon, text, onClick }) => {
|
const HunkExpandLink: FC<Props> = ({ icon, text, onClick }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -49,9 +44,9 @@ const HunkExpandLink: FC<Props> = ({ icon, text, onClick }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExpandLink onClick={onClickWithLoadingMarker}>
|
<span className="is-clickable" onClick={onClickWithLoadingMarker}>
|
||||||
<i className={classNames("fa", icon)} /> {loading ? t("diff.expanding") : text}
|
<i className={classNames("fa", icon)} /> {loading ? t("diff.expanding") : text}
|
||||||
</ExpandLink>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,11 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import Tooltip from "../Tooltip";
|
import Tooltip from "../Tooltip";
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
|
|
||||||
const Button = styled(Link)`
|
const Button = styled(Link)`
|
||||||
width: 50px;
|
width: 50px;
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #33b2e8;
|
color: #33b2e8;
|
||||||
}
|
}
|
||||||
@@ -44,7 +42,7 @@ type Props = {
|
|||||||
const JumpToFileButton: FC<Props> = ({ link, tooltip }) => {
|
const JumpToFileButton: FC<Props> = ({ link, tooltip }) => {
|
||||||
return (
|
return (
|
||||||
<Tooltip message={tooltip} location="top">
|
<Tooltip message={tooltip} location="top">
|
||||||
<Button aria-label={tooltip} className="button" to={link}>
|
<Button aria-label={tooltip} className="button is-clickable" to={link}>
|
||||||
<Icon name="file-code" color="inherit" />
|
<Icon name="file-code" color="inherit" />
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -22,16 +22,14 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { NotFoundError, useDiff } from "@scm-manager/ui-api";
|
import { NotFoundError, useDiff } from "@scm-manager/ui-api";
|
||||||
import ErrorNotification from "../ErrorNotification";
|
import ErrorNotification from "../ErrorNotification";
|
||||||
import Notification from "../Notification";
|
|
||||||
|
|
||||||
import Loading from "../Loading";
|
import Loading from "../Loading";
|
||||||
|
import Notification from "../Notification";
|
||||||
|
import Button from "../buttons/Button";
|
||||||
import Diff from "./Diff";
|
import Diff from "./Diff";
|
||||||
import { DiffObjectProps } from "./DiffTypes";
|
import { DiffObjectProps } from "./DiffTypes";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import Button from "../buttons/Button";
|
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = DiffObjectProps & {
|
type Props = DiffObjectProps & {
|
||||||
url: string;
|
url: string;
|
||||||
@@ -44,19 +42,15 @@ type NotificationProps = {
|
|||||||
isFetchingNextPage: boolean;
|
isFetchingNextPage: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledNotification = styled(Notification)`
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const PartialNotification: FC<NotificationProps> = ({ fetchNextPage, isFetchingNextPage }) => {
|
const PartialNotification: FC<NotificationProps> = ({ fetchNextPage, isFetchingNextPage }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
return (
|
return (
|
||||||
<StyledNotification type="info">
|
<Notification className="mt-5" type="info">
|
||||||
<div className="columns is-centered">
|
<div className="columns is-centered">
|
||||||
<div className="column">{t("changesets.moreDiffsAvailable")}</div>
|
<div className="column">{t("changesets.moreDiffsAvailable")}</div>
|
||||||
<Button label={t("changesets.loadMore")} action={fetchNextPage} loading={isFetchingNextPage} />
|
<Button label={t("changesets.loadMore")} action={fetchNextPage} loading={isFetchingNextPage} />
|
||||||
</div>
|
</div>
|
||||||
</StyledNotification>
|
</Notification>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import RepositoryFlags from "./RepositoryFlags";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
type DateProp = Date | string;
|
type DateProp = Date | string;
|
||||||
|
|
||||||
@@ -43,26 +44,9 @@ type Props = {
|
|||||||
|
|
||||||
const ContentRightContainer = styled.div`
|
const ContentRightContainer = styled.div`
|
||||||
height: calc(80px - 1.5rem);
|
height: calc(80px - 1.5rem);
|
||||||
margin-right: 1rem;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const DateWrapper = styled.small`
|
|
||||||
padding-bottom: 0.25rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const QuickActionbar = styled.span`
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: flex-end;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const QuickAction = styled(Icon)`
|
const QuickAction = styled(Icon)`
|
||||||
font-size: 1.25rem;
|
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
color: #363636 !important;
|
color: #363636 !important;
|
||||||
}
|
}
|
||||||
@@ -80,7 +64,15 @@ const RepositoryEntry: FC<Props> = ({ repository, baseDate }) => {
|
|||||||
const [openCloneModal, setOpenCloneModal] = useState(false);
|
const [openCloneModal, setOpenCloneModal] = useState(false);
|
||||||
|
|
||||||
const createContentRight = () => (
|
const createContentRight = () => (
|
||||||
<ContentRightContainer>
|
<ContentRightContainer
|
||||||
|
className={classNames(
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-direction-column",
|
||||||
|
"is-justify-content-space-between",
|
||||||
|
"is-relative",
|
||||||
|
"mr-4"
|
||||||
|
)}
|
||||||
|
>
|
||||||
{openCloneModal && (
|
{openCloneModal && (
|
||||||
<Modal
|
<Modal
|
||||||
size="L"
|
size="L"
|
||||||
@@ -98,18 +90,18 @@ const RepositoryEntry: FC<Props> = ({ repository, baseDate }) => {
|
|||||||
closeFunction={() => setOpenCloneModal(false)}
|
closeFunction={() => setOpenCloneModal(false)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<QuickActionbar>
|
<span className={classNames("is-flex", "is-justify-content-flex-end", "is-align-items-flex-end")}>
|
||||||
<QuickAction
|
<QuickAction
|
||||||
|
className={classNames("is-clickable", "is-size-5")}
|
||||||
name="download"
|
name="download"
|
||||||
color="info"
|
color="info"
|
||||||
className="has-cursor-pointer"
|
|
||||||
onClick={() => setOpenCloneModal(true)}
|
onClick={() => setOpenCloneModal(true)}
|
||||||
title={t("overview.clone")}
|
title={t("overview.clone")}
|
||||||
/>
|
/>
|
||||||
</QuickActionbar>
|
</span>
|
||||||
<DateWrapper>
|
<small className="pb-1">
|
||||||
<DateFromNow baseDate={baseDate} date={repository.lastModified || repository.creationDate} />
|
<DateFromNow baseDate={baseDate} date={repository.lastModified || repository.creationDate} />
|
||||||
</DateWrapper>
|
</small>
|
||||||
</ContentRightContainer>
|
</ContentRightContainer>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import styled from "styled-components";
|
|
||||||
import { Icon } from "@scm-manager/ui-components";
|
import { Icon } from "@scm-manager/ui-components";
|
||||||
import Tooltip from "../Tooltip";
|
import Tooltip from "../Tooltip";
|
||||||
|
|
||||||
@@ -33,10 +32,6 @@ type Props = {
|
|||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PointerEventsLink = styled(Link)`
|
|
||||||
pointer-events: all;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class RepositoryEntryLink extends React.Component<Props> {
|
class RepositoryEntryLink extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { to, icon, tooltip } = this.props;
|
const { to, icon, tooltip } = this.props;
|
||||||
@@ -51,9 +46,9 @@ class RepositoryEntryLink extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PointerEventsLink className="level-item" to={to}>
|
<Link className="level-item is-clickable" to={to}>
|
||||||
{content}
|
{content}
|
||||||
</PointerEventsLink>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,15 +21,15 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, useState } from "react";
|
import React, { FC, useState } from "react";
|
||||||
import RepositoryFlag from "./RepositoryFlag";
|
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
|
||||||
import { Repository } from "@scm-manager/ui-types";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import HealthCheckFailureDetail from "./HealthCheckFailureDetail";
|
import { Repository } from "@scm-manager/ui-types";
|
||||||
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { TooltipLocation } from "../Tooltip";
|
import { TooltipLocation } from "../Tooltip";
|
||||||
|
import RepositoryFlag from "./RepositoryFlag";
|
||||||
|
import HealthCheckFailureDetail from "./HealthCheckFailureDetail";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Repository;
|
repository: Repository;
|
||||||
@@ -37,11 +37,6 @@ type Props = {
|
|||||||
tooltipLocation?: TooltipLocation;
|
tooltipLocation?: TooltipLocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Wrapper = styled.span`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const RepositoryFlagContainer = styled.div`
|
const RepositoryFlagContainer = styled.div`
|
||||||
.tag {
|
.tag {
|
||||||
margin-left: 0.25rem;
|
margin-left: 0.25rem;
|
||||||
@@ -91,13 +86,13 @@ const RepositoryFlags: FC<Props> = ({ repository, className, tooltipLocation = "
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<span className={classNames("is-flex", "is-align-items-center", className)}>
|
||||||
{modal}
|
{modal}
|
||||||
<RepositoryFlagContainer>
|
<RepositoryFlagContainer>
|
||||||
{repositoryFlags}
|
{repositoryFlags}
|
||||||
<ExtensionPoint name="repository.flags" props={{ repository, tooltipLocation }} renderAll={true} />
|
<ExtensionPoint name="repository.flags" props={{ repository, tooltipLocation }} renderAll={true} />
|
||||||
</RepositoryFlagContainer>
|
</RepositoryFlagContainer>
|
||||||
</Wrapper>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import Popover from "./Popover";
|
|||||||
import AnnotateLine from "./AnnotateLine";
|
import AnnotateLine from "./AnnotateLine";
|
||||||
import { Action } from "./actions";
|
import { Action } from "./actions";
|
||||||
import { determineLanguage } from "../../languages";
|
import { determineLanguage } from "../../languages";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
source: AnnotatedSource;
|
source: AnnotatedSource;
|
||||||
@@ -57,11 +56,6 @@ const initialState = {
|
|||||||
onLine: false,
|
onLine: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const NoSpacingReactSyntaxHighlighter = styled(ReactSyntaxHighlighter)`
|
|
||||||
margin: 0 !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const reducer = (state: State, action: Action): State => {
|
const reducer = (state: State, action: Action): State => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "enter-line": {
|
case "enter-line": {
|
||||||
@@ -152,14 +146,15 @@ const Annotate: FC<Props> = ({ source, repository, baseDate }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="panel-block">
|
<div className="panel-block">
|
||||||
{popover}
|
{popover}
|
||||||
<NoSpacingReactSyntaxHighlighter
|
<ReactSyntaxHighlighter
|
||||||
|
className="m-0 p-0"
|
||||||
showLineNumbers={false}
|
showLineNumbers={false}
|
||||||
language={determineLanguage(source.language)}
|
language={determineLanguage(source.language)}
|
||||||
style={highlightingTheme}
|
style={highlightingTheme}
|
||||||
renderer={defaultRenderer}
|
renderer={defaultRenderer}
|
||||||
>
|
>
|
||||||
{code}
|
{code}
|
||||||
</NoSpacingReactSyntaxHighlighter>
|
</ReactSyntaxHighlighter>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ const Author = styled(LineElement)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const When = styled(LineElement)`
|
const When = styled(LineElement)`
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
width: 6.5em;
|
width: 6.5em;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import { DateInput } from "../../useDateFormatter";
|
|||||||
import { Repository, AnnotatedLine } from "@scm-manager/ui-types";
|
import { Repository, AnnotatedLine } from "@scm-manager/ui-types";
|
||||||
import AuthorImage from "./AuthorImage";
|
import AuthorImage from "./AuthorImage";
|
||||||
import { Action } from "./actions";
|
import { Action } from "./actions";
|
||||||
import {useTranslation} from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const PopoverContainer = styled.div`
|
const PopoverContainer = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -62,16 +62,11 @@ const PopoverContainer = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SmallHr = styled.hr`
|
|
||||||
margin: 0.5em 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const PopoverHeading = styled.div`
|
const PopoverHeading = styled.div`
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const PopoverDescription = styled.p`
|
const PopoverDescription = styled.p`
|
||||||
margin-top: 0.5em;
|
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -102,13 +97,13 @@ const Popover: FC<PopoverProps> = ({ annotation, offsetTop, repository, baseDate
|
|||||||
|
|
||||||
const onMouseEnter = () => {
|
const onMouseEnter = () => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "enter-popover"
|
type: "enter-popover",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const OnMouseLeave = () => {
|
const OnMouseLeave = () => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "leave-popover"
|
type: "leave-popover",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -128,14 +123,14 @@ const Popover: FC<PopoverProps> = ({ annotation, offsetTop, repository, baseDate
|
|||||||
</span>
|
</span>
|
||||||
<DateFromNow className="is-pulled-right" date={annotation.when} baseDate={baseDate} />
|
<DateFromNow className="is-pulled-right" date={annotation.when} baseDate={baseDate} />
|
||||||
</PopoverHeading>
|
</PopoverHeading>
|
||||||
<SmallHr />
|
<hr className="my-2" />
|
||||||
<p>
|
<p>
|
||||||
{t("changeset.label") + " "}
|
{t("changeset.label") + " "}
|
||||||
<Link to={`/repo/${repository.namespace}/${repository.name}/code/changeset/${annotation.revision}`}>
|
<Link to={`/repo/${repository.namespace}/${repository.name}/code/changeset/${annotation.revision}`}>
|
||||||
{shortRevision(annotation.revision)}
|
{shortRevision(annotation.revision)}
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
<PopoverDescription className="content">{annotation.description}</PopoverDescription>
|
<PopoverDescription className="content mt-2">{annotation.description}</PopoverDescription>
|
||||||
</PopoverContainer>
|
</PopoverContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class ChangesetButtonGroup extends React.Component<Props> {
|
|||||||
const changesetLink = createChangesetLink(repository, changeset);
|
const changesetLink = createChangesetLink(repository, changeset);
|
||||||
const sourcesLink = createSourcesLink(repository, changeset);
|
const sourcesLink = createSourcesLink(repository, changeset);
|
||||||
return (
|
return (
|
||||||
<ButtonAddons className="is-marginless">
|
<ButtonAddons className="m-0">
|
||||||
<Button link={changesetLink} icon="exchange-alt" label={t("changeset.buttons.details")} reducedMobile={true} />
|
<Button link={changesetLink} icon="exchange-alt" label={t("changeset.buttons.details")} reducedMobile={true} />
|
||||||
<Button link={sourcesLink} icon="code" label={t("changeset.buttons.sources")} reducedMobile={true} />
|
<Button link={sourcesLink} icon="code" label={t("changeset.buttons.sources")} reducedMobile={true} />
|
||||||
</ButtonAddons>
|
</ButtonAddons>
|
||||||
|
|||||||
@@ -52,39 +52,15 @@ const Wrapper = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AvatarFigure = styled.figure`
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FixedSizedAvatar = styled.div`
|
const FixedSizedAvatar = styled.div`
|
||||||
width: 35px;
|
width: 35px;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Metadata = styled.div`
|
const FullWidthDiv = styled.div`
|
||||||
margin-left: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AuthorWrapper = styled.p`
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const VCenteredColumn = styled.div`
|
|
||||||
align-self: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const VCenteredChildColumn = styled.div`
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-end;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FlexRow = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class ChangesetRow extends React.Component<Props> {
|
class ChangesetRow extends React.Component<Props> {
|
||||||
createChangesetId = (changeset: Changeset) => {
|
createChangesetId = (changeset: Changeset) => {
|
||||||
const { repository } = this.props;
|
const { repository } = this.props;
|
||||||
@@ -99,25 +75,25 @@ class ChangesetRow extends React.Component<Props> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<div className="columns is-gapless is-mobile">
|
<div className={classNames("columns", "is-gapless", "is-mobile")}>
|
||||||
<div className="column is-three-fifths">
|
<div className={classNames("column", "is-three-fifths")}>
|
||||||
<div className="columns is-gapless">
|
<div className={classNames("columns", "is-gapless")}>
|
||||||
<div className="column is-four-fifths">
|
<div className={classNames("column", "is-four-fifths")}>
|
||||||
<div className="media">
|
<div className="media">
|
||||||
<AvatarWrapper>
|
<AvatarWrapper>
|
||||||
<AvatarFigure className="media-left">
|
<figure className={classNames("media-left", "mt-2", "mr-2")}>
|
||||||
<FixedSizedAvatar className="image">
|
<FixedSizedAvatar className="image">
|
||||||
<AvatarImage person={changeset.author} />
|
<AvatarImage person={changeset.author} />
|
||||||
</FixedSizedAvatar>
|
</FixedSizedAvatar>
|
||||||
</AvatarFigure>
|
</figure>
|
||||||
</AvatarWrapper>
|
</AvatarWrapper>
|
||||||
<Metadata className="media-right">
|
<FullWidthDiv className={classNames("media-right", "ml-0")}>
|
||||||
<h4 className="has-text-weight-bold is-ellipsis-overflow">
|
<h4 className={classNames("has-text-weight-bold", "is-ellipsis-overflow")}>
|
||||||
<ExtensionPoint
|
<ExtensionPoint
|
||||||
name="changeset.description"
|
name="changeset.description"
|
||||||
props={{
|
props={{
|
||||||
changeset,
|
changeset,
|
||||||
value: description.title
|
value: description.title,
|
||||||
}}
|
}}
|
||||||
renderAll={false}
|
renderAll={false}
|
||||||
>
|
>
|
||||||
@@ -130,36 +106,33 @@ class ChangesetRow extends React.Component<Props> {
|
|||||||
<p className="is-hidden-desktop">
|
<p className="is-hidden-desktop">
|
||||||
<Trans i18nKey="repos:changeset.shortSummary" components={[changesetId, dateFromNow]} />
|
<Trans i18nKey="repos:changeset.shortSummary" components={[changesetId, dateFromNow]} />
|
||||||
</p>
|
</p>
|
||||||
<FlexRow>
|
<div className="is-flex">
|
||||||
<AuthorWrapper className="is-size-7 is-ellipsis-overflow">
|
<p className={classNames("is-size-7", "is-ellipsis-overflow", "mt-2")}>
|
||||||
<ChangesetAuthor changeset={changeset} />
|
<ChangesetAuthor changeset={changeset} />
|
||||||
</AuthorWrapper>
|
</p>
|
||||||
{changeset?.signatures && changeset.signatures.length > 0 && (
|
{changeset?.signatures && changeset.signatures.length > 0 && (
|
||||||
<SignatureIcon
|
<SignatureIcon className={classNames("mx-2", "pt-1")} signatures={changeset.signatures} />
|
||||||
className="mx-2 pt-1"
|
|
||||||
signatures={changeset.signatures}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</FlexRow>
|
</div>
|
||||||
</Metadata>
|
</FullWidthDiv>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<VCenteredColumn className="column">
|
<div className={classNames("column", "is-align-self-center")}>
|
||||||
<ChangesetTags changeset={changeset} />
|
<ChangesetTags changeset={changeset} />
|
||||||
</VCenteredColumn>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<VCenteredChildColumn className={classNames("column", "is-flex")}>
|
</div>
|
||||||
|
<div className={classNames("column", "is-flex", "is-justify-content-flex-end", "is-align-items-center")}>
|
||||||
<ChangesetButtonGroup repository={repository} changeset={changeset} />
|
<ChangesetButtonGroup repository={repository} changeset={changeset} />
|
||||||
<ExtensionPoint
|
<ExtensionPoint
|
||||||
name="changeset.right"
|
name="changeset.right"
|
||||||
props={{
|
props={{
|
||||||
repository,
|
repository,
|
||||||
changeset
|
changeset,
|
||||||
}}
|
}}
|
||||||
renderAll={true}
|
renderAll={true}
|
||||||
/>
|
/>
|
||||||
</VCenteredChildColumn>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import styled from "styled-components";
|
import classNames from "classnames";
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -30,13 +30,8 @@ type Props = {
|
|||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IconWithMarginLeft = styled(Icon)`
|
|
||||||
visibility: ${(props: Props) => (props.isVisible ? "visible" : "hidden")};
|
|
||||||
margin-left: 0.25em;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SortIcon: FC<Props> = (props: Props) => {
|
const SortIcon: FC<Props> = (props: Props) => {
|
||||||
return <IconWithMarginLeft name={props.name} isVisible={props.isVisible} />;
|
return <Icon className={classNames("ml-1", { "is-invisible": !props.isVisible })} name={props.name} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SortIcon;
|
export default SortIcon;
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ const Table: FC<Props> = ({ data, sortable, children, emptyMessage, className })
|
|||||||
<tr>
|
<tr>
|
||||||
{React.Children.map(children, (child, index) => (
|
{React.Children.map(children, (child, index) => (
|
||||||
<th
|
<th
|
||||||
className={isSortable(child) && "has-cursor-pointer"}
|
className={isSortable(child) && "is-clickable"}
|
||||||
onClick={isSortable(child) ? () => tableSort(index) : undefined}
|
onClick={isSortable(child) ? () => tableSort(index) : undefined}
|
||||||
onMouseEnter={() => setHoveredColumnIndex(index)}
|
onMouseEnter={() => setHoveredColumnIndex(index)}
|
||||||
onMouseLeave={() => setHoveredColumnIndex(undefined)}
|
onMouseLeave={() => setHoveredColumnIndex(undefined)}
|
||||||
|
|||||||
@@ -59,11 +59,6 @@ const Container = styled.div<Themeable>`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Title = styled.h1<Themeable>`
|
|
||||||
margin-bottom: 0.25rem;
|
|
||||||
font-weight: bold;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Toast: FC<Props> = ({ children, title, type }) => {
|
const Toast: FC<Props> = ({ children, title, type }) => {
|
||||||
const rootElement = usePortalRootElement("toastRoot");
|
const rootElement = usePortalRootElement("toastRoot");
|
||||||
if (!rootElement) {
|
if (!rootElement) {
|
||||||
@@ -74,7 +69,7 @@ const Toast: FC<Props> = ({ children, title, type }) => {
|
|||||||
const theme = getTheme(type);
|
const theme = getTheme(type);
|
||||||
const content = (
|
const content = (
|
||||||
<Container theme={theme}>
|
<Container theme={theme}>
|
||||||
<Title theme={theme}>{title}</Title>
|
<h1 className="mb-1 has-text-weight-bold">{title}</h1>
|
||||||
<ToastThemeContext.Provider value={theme}>{children}</ToastThemeContext.Provider>
|
<ToastThemeContext.Provider value={theme}>{children}</ToastThemeContext.Provider>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
import React, { FC, useContext, MouseEvent } from "react";
|
import React, { FC, useContext, MouseEvent } from "react";
|
||||||
import { ToastThemeContext, Themeable } from "./themes";
|
import { ToastThemeContext, Themeable } from "./themes";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -30,25 +31,21 @@ type Props = {
|
|||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ThemedButton = styled.button.attrs(props => ({
|
const ThemedButton = styled.button.attrs((props) => ({
|
||||||
className: "button"
|
className: "button",
|
||||||
}))<Themeable>`
|
}))<Themeable>`
|
||||||
color: ${props => props.theme.primary};
|
color: ${(props) => props.theme.primary};
|
||||||
border-color: ${props => props.theme.primary};
|
border-color: ${(props) => props.theme.primary};
|
||||||
background-color: ${props => props.theme.secondary};
|
background-color: ${(props) => props.theme.secondary};
|
||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: ${props => props.theme.primary};
|
color: ${(props) => props.theme.primary};
|
||||||
border-color: ${props => props.theme.tertiary};
|
border-color: ${(props) => props.theme.tertiary};
|
||||||
background-color: ${props => props.theme.tertiary};
|
background-color: ${(props) => props.theme.tertiary};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ToastButtonIcon = styled.i`
|
|
||||||
margin-right: 0.25rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ToastButton: FC<Props> = ({ icon, onClick, children }) => {
|
const ToastButton: FC<Props> = ({ icon, onClick, children }) => {
|
||||||
const theme = useContext(ToastThemeContext);
|
const theme = useContext(ToastThemeContext);
|
||||||
|
|
||||||
@@ -61,7 +58,7 @@ const ToastButton: FC<Props> = ({ icon, onClick, children }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemedButton theme={theme} onClick={handleClick}>
|
<ThemedButton theme={theme} onClick={handleClick}>
|
||||||
{icon && <ToastButtonIcon className={`fas fa-fw fa-${icon}`} />} {children}
|
{icon && <i className={classNames("fas", "fa-fw", `fa-${icon}`, "mr-1")} />} {children}
|
||||||
</ThemedButton>
|
</ThemedButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,9 +24,7 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
const Buttons = styled.div`
|
const FullWidthDiv = styled.div`
|
||||||
display: flex;
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
@@ -38,6 +36,6 @@ const Buttons = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ToastButtons: FC = ({ children }) => <Buttons>{children}</Buttons>;
|
const ToastButtons: FC = ({ children }) => <FullWidthDiv className="is-flex pt-2">{children}</FullWidthDiv>;
|
||||||
|
|
||||||
export default ToastButtons;
|
export default ToastButtons;
|
||||||
|
|||||||
@@ -21,10 +21,10 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getTheme, Themeable, ToastThemeContext, Type } from "./themes";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { getTheme, Themeable, ToastThemeContext, Type } from "./themes";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type: Type;
|
type: Type;
|
||||||
@@ -33,31 +33,22 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Container = styled.div<Themeable>`
|
const Container = styled.div<Themeable>`
|
||||||
color: ${props => props.theme.primary};
|
color: ${(props) => props.theme.primary};
|
||||||
background-color: ${props => props.theme.secondary};
|
background-color: ${(props) => props.theme.secondary};
|
||||||
max-width: 18rem;
|
max-width: 18rem;
|
||||||
font-size: 0.75rem;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 1.5rem;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
|
|
||||||
& > p {
|
& > p {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Title = styled.h1<Themeable>`
|
|
||||||
margin-bottom: 0.25rem;
|
|
||||||
font-weight: bold;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ToastNotification: FC<Props> = ({ children, title, type, close }) => {
|
const ToastNotification: FC<Props> = ({ children, title, type, close }) => {
|
||||||
const theme = getTheme(type);
|
const theme = getTheme(type);
|
||||||
return (
|
return (
|
||||||
<Container className="notification" theme={theme}>
|
<Container className={classNames("notification", "mt-2", "mb-0", "p-5", "is-size-7")} theme={theme}>
|
||||||
{ close ? <button className="delete" onClick={close} /> : null }
|
{close ? <button className="delete" onClick={close} /> : null}
|
||||||
<Title theme={theme}>{title}</Title>
|
<h1 className={classNames("mb-1", "has-text-weight-bold")}>{title}</h1>
|
||||||
<ToastThemeContext.Provider value={theme}>{children}</ToastThemeContext.Provider>
|
<ToastThemeContext.Provider value={theme}>{children}</ToastThemeContext.Provider>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ footer.footer {
|
|||||||
// 6. Import the rest of Bulma
|
// 6. Import the rest of Bulma
|
||||||
@import "bulma/bulma";
|
@import "bulma/bulma";
|
||||||
@import "bulma-tooltip/dist/css/bulma-tooltip.min";
|
@import "bulma-tooltip/dist/css/bulma-tooltip.min";
|
||||||
|
@import "bulma-popover/css/bulma-popover";
|
||||||
|
|
||||||
$dark-75: scale-color($dark, $lightness: 25%);
|
$dark-75: scale-color($dark, $lightness: 25%);
|
||||||
$dark-50: scale-color($dark, $lightness: 50%);
|
$dark-50: scale-color($dark, $lightness: 50%);
|
||||||
@@ -194,7 +195,10 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.has-text-blue-light {
|
.has-text-blue-light {
|
||||||
color: $blue-light !important;
|
color: $blue-light;
|
||||||
|
}
|
||||||
|
.has-background-blue-light {
|
||||||
|
background-color: $blue-light;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-text-high-contrast-warning {
|
.has-text-high-contrast-warning {
|
||||||
@@ -286,10 +290,6 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
|||||||
background-color: $high-contrast-danger-25;
|
background-color: $high-contrast-danger-25;
|
||||||
}
|
}
|
||||||
|
|
||||||
.has-background-blue-light {
|
|
||||||
background-color: $blue-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
.has-background-high-contrast-light-gray {
|
.has-background-high-contrast-light-gray {
|
||||||
background-color: $high-contrast-light-gray;
|
background-color: $high-contrast-light-gray;
|
||||||
}
|
}
|
||||||
@@ -312,7 +312,7 @@ $light-25: darken($high-contrast-light-gray, 45%);
|
|||||||
background-color: $light;
|
background-color: $light;
|
||||||
}
|
}
|
||||||
|
|
||||||
+.is-delete {
|
+ .is-delete {
|
||||||
border-color: #aaa;
|
border-color: #aaa;
|
||||||
border-width: 1px 1px 1px 0;
|
border-width: 1px 1px 1px 0;
|
||||||
}
|
}
|
||||||
@@ -520,7 +520,7 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
.has-border-white {
|
.has-border-white {
|
||||||
border-color: #fff !important;
|
border-color: $white !important;
|
||||||
}
|
}
|
||||||
ul.is-separated {
|
ul.is-separated {
|
||||||
> li:after {
|
> li:after {
|
||||||
@@ -603,7 +603,7 @@ ul.is-separated {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
td,
|
td,
|
||||||
th {
|
th {
|
||||||
border-color: #eee;
|
border-color: $white-ter;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -805,7 +805,6 @@ form .field:not(.is-grouped) {
|
|||||||
.menu {
|
.menu {
|
||||||
div {
|
div {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/*border: 1px solid #eee;*/
|
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -816,7 +815,7 @@ form .field:not(.is-grouped) {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background-color: #bbb;
|
background-color: $blue;
|
||||||
border-radius: 5px 5px 0 0;
|
border-radius: 5px 5px 0 0;
|
||||||
padding: 0.5rem 1rem;
|
padding: 0.5rem 1rem;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
@@ -826,9 +825,6 @@ form .field:not(.is-grouped) {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.menu div:first-child .menu-label {
|
|
||||||
background-color: $blue;
|
|
||||||
}
|
|
||||||
.menu-list {
|
.menu-list {
|
||||||
a {
|
a {
|
||||||
color: #333;
|
color: #333;
|
||||||
@@ -843,7 +839,7 @@ form .field:not(.is-grouped) {
|
|||||||
> li {
|
> li {
|
||||||
ul {
|
ul {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid $white-ter;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
border-right: none;
|
border-right: none;
|
||||||
@@ -866,15 +862,15 @@ form .field:not(.is-grouped) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid $white-ter;
|
||||||
border-left: 1px solid #eee;
|
border-left: 1px solid $white-ter;
|
||||||
border-right: 1px solid #eee;
|
border-right: 1px solid $white-ter;
|
||||||
}
|
}
|
||||||
> li:first-child {
|
> li:first-child {
|
||||||
border-top: none;
|
border-top: none;
|
||||||
}
|
}
|
||||||
li:last-child {
|
li:last-child {
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid $white-ter;
|
||||||
}
|
}
|
||||||
div {
|
div {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@@ -921,7 +917,7 @@ form .field:not(.is-grouped) {
|
|||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursor
|
// NOTE: use .is-clickable instead!
|
||||||
.has-cursor-pointer {
|
.has-cursor-pointer {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
@@ -952,5 +948,3 @@ form .field:not(.is-grouped) {
|
|||||||
@include loader;
|
@include loader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "bulma-popover/css/bulma-popover";
|
|
||||||
|
|||||||
@@ -27,18 +27,10 @@ import styled from "styled-components";
|
|||||||
import { ErrorNotification, Image, Loading, Subtitle, Title } from "@scm-manager/ui-components";
|
import { ErrorNotification, Image, Loading, Subtitle, Title } from "@scm-manager/ui-components";
|
||||||
import { useUpdateInfo, useVersion } from "@scm-manager/ui-api";
|
import { useUpdateInfo, useVersion } from "@scm-manager/ui-api";
|
||||||
|
|
||||||
const BottomMarginDiv = styled.div`
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BoxShadowBox = styled.div`
|
const BoxShadowBox = styled.div`
|
||||||
box-shadow: 0 2px 3px rgba(40, 177, 232, 0.1), 0 0 0 2px rgba(40, 177, 232, 0.2);
|
box-shadow: 0 2px 3px rgba(40, 177, 232, 0.1), 0 0 0 2px rgba(40, 177, 232, 0.2);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NoBottomMarginSubtitle = styled(Subtitle)`
|
|
||||||
margin-bottom: 0.25rem !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ImageWrapper = styled.div`
|
const ImageWrapper = styled.div`
|
||||||
padding: 0.2rem 0.4rem;
|
padding: 0.2rem 0.4rem;
|
||||||
`;
|
`;
|
||||||
@@ -68,7 +60,7 @@ const AdminDetails: FC = () => {
|
|||||||
<h3 className="has-text-weight-medium">{t("admin.info.newRelease.title")}</h3>
|
<h3 className="has-text-weight-medium">{t("admin.info.newRelease.title")}</h3>
|
||||||
<p>
|
<p>
|
||||||
{t("admin.info.newRelease.description", {
|
{t("admin.info.newRelease.description", {
|
||||||
version: updateInfo?.latestVersion
|
version: updateInfo?.latestVersion,
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
<a className="button is-warning is-pulled-right" target="_blank" href={updateInfo?.link}>
|
<a className="button is-warning is-pulled-right" target="_blank" href={updateInfo?.link}>
|
||||||
@@ -85,8 +77,8 @@ const AdminDetails: FC = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={t("admin.info.title")} />
|
<Title title={t("admin.info.title")} />
|
||||||
<NoBottomMarginSubtitle subtitle={t("admin.info.currentAppVersion")} />
|
<Subtitle className="mb-1" subtitle={t("admin.info.currentAppVersion")} />
|
||||||
<BottomMarginDiv>{version}</BottomMarginDiv>
|
<div className="mb-5">{version}</div>
|
||||||
{updateInfo ? renderUpdateInfo() : null}
|
{updateInfo ? renderUpdateInfo() : null}
|
||||||
<BoxShadowBox className="box">
|
<BoxShadowBox className="box">
|
||||||
<article className="media">
|
<article className="media">
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -29,15 +30,16 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ActionWrapper = styled.div`
|
const ActionWrapper = styled.div`
|
||||||
justify-content: center;
|
border: 2px solid #e9f7fd;
|
||||||
margin-top: 2em;
|
|
||||||
padding: 1em 1em;
|
|
||||||
border: 2px solid #e9f7df;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default class PluginBottomActions extends React.Component<Props> {
|
export default class PluginBottomActions extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
return <ActionWrapper className="is-flex">{children}</ActionWrapper>;
|
return (
|
||||||
|
<ActionWrapper className={classNames("is-flex", "is-justify-content-center", "mt-5", "p-4")}>
|
||||||
|
{children}
|
||||||
|
</ActionWrapper>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,13 +40,11 @@ const ActionbarWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const IconWrapper = styled.span`
|
const IconWrapper = styled.span.attrs((props) => ({
|
||||||
margin-bottom: 0 !important;
|
className: "level-item mb-0 p-2 is-clickable",
|
||||||
padding: 0.5rem;
|
}))`
|
||||||
border: 1px solid #cdcdcd; // $dark-25
|
border: 1px solid #cdcdcd; // $dark-25
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
|
||||||
pointer-events: all;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: #9a9a9a; // $dark-50
|
border-color: #9a9a9a; // $dark-50
|
||||||
@@ -78,22 +76,22 @@ const PluginEntry: FC<Props> = ({ plugin, openModal }) => {
|
|||||||
const actionBar = () => (
|
const actionBar = () => (
|
||||||
<ActionbarWrapper className="is-flex">
|
<ActionbarWrapper className="is-flex">
|
||||||
{isCloudoguPlugin && (
|
{isCloudoguPlugin && (
|
||||||
<IconWrapper className="level-item" onClick={() => openModal({ plugin, action: PluginAction.CLOUDOGU })}>
|
<IconWrapper onClick={() => openModal({ plugin, action: PluginAction.CLOUDOGU })}>
|
||||||
<Icon title={t("plugins.modal.cloudoguInstall")} name="link" color="success-dark" />
|
<Icon title={t("plugins.modal.cloudoguInstall")} name="link" color="success-dark" />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)}
|
)}
|
||||||
{isInstallable && (
|
{isInstallable && (
|
||||||
<IconWrapper className="level-item" onClick={() => openModal({ plugin, action: PluginAction.INSTALL })}>
|
<IconWrapper onClick={() => openModal({ plugin, action: PluginAction.INSTALL })}>
|
||||||
<Icon title={t("plugins.modal.install")} name="download" color="info" />
|
<Icon title={t("plugins.modal.install")} name="download" color="info" />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)}
|
)}
|
||||||
{isUninstallable && (
|
{isUninstallable && (
|
||||||
<IconWrapper className="level-item" onClick={() => openModal({ plugin, action: PluginAction.UNINSTALL })}>
|
<IconWrapper onClick={() => openModal({ plugin, action: PluginAction.UNINSTALL })}>
|
||||||
<Icon title={t("plugins.modal.uninstall")} name="trash" color="info" />
|
<Icon title={t("plugins.modal.uninstall")} name="trash" color="info" />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)}
|
)}
|
||||||
{isUpdatable && (
|
{isUpdatable && (
|
||||||
<IconWrapper className="level-item" onClick={() => openModal({ plugin, action: PluginAction.UPDATE })}>
|
<IconWrapper onClick={() => openModal({ plugin, action: PluginAction.UPDATE })}>
|
||||||
<Icon title={t("plugins.modal.update")} name="sync-alt" color="info" />
|
<Icon title={t("plugins.modal.update")} name="sync-alt" color="info" />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ type ParentWithPluginAction = {
|
|||||||
pluginAction?: PluginAction;
|
pluginAction?: PluginAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ListParent = styled.div.attrs((props) => ({}))<ParentWithPluginAction>`
|
const ListParent = styled.div.attrs((props) => ({
|
||||||
margin-right: 0;
|
className: "field-label is-inline-flex mr-0 has-text-left",
|
||||||
|
}))<ParentWithPluginAction>`
|
||||||
min-width: ${(props) => (props.pluginAction === PluginAction.INSTALL ? "5.5em" : "10em")};
|
min-width: ${(props) => (props.pluginAction === PluginAction.INSTALL ? "5.5em" : "10em")};
|
||||||
text-align: left;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ListChild = styled.div`
|
const ListChild = styled.div`
|
||||||
@@ -194,9 +194,7 @@ const PluginModal: FC<Props> = ({ onClose, pluginAction, plugin }) => {
|
|||||||
<div className="media">
|
<div className="media">
|
||||||
<div className="media-content">
|
<div className="media-content">
|
||||||
<div className="field is-horizontal">
|
<div className="field is-horizontal">
|
||||||
<ListParent className={classNames("field-label", "is-inline-flex")} pluginAction={pluginAction}>
|
<ListParent pluginAction={pluginAction}>{t("plugins.modal.author")}:</ListParent>
|
||||||
{t("plugins.modal.author")}:
|
|
||||||
</ListParent>
|
|
||||||
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.author}</ListChild>
|
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.author}</ListChild>
|
||||||
</div>
|
</div>
|
||||||
{pluginAction === PluginAction.CLOUDOGU && (
|
{pluginAction === PluginAction.CLOUDOGU && (
|
||||||
@@ -208,25 +206,19 @@ const PluginModal: FC<Props> = ({ onClose, pluginAction, plugin }) => {
|
|||||||
)}
|
)}
|
||||||
{pluginAction === PluginAction.INSTALL && (
|
{pluginAction === PluginAction.INSTALL && (
|
||||||
<div className="field is-horizontal">
|
<div className="field is-horizontal">
|
||||||
<ListParent className={classNames("field-label", "is-inline-flex")} pluginAction={pluginAction}>
|
<ListParent pluginAction={pluginAction}>{t("plugins.modal.version")}:</ListParent>
|
||||||
{t("plugins.modal.version")}:
|
|
||||||
</ListParent>
|
|
||||||
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.version}</ListChild>
|
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.version}</ListChild>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(pluginAction === PluginAction.UPDATE || pluginAction === PluginAction.UNINSTALL) && (
|
{(pluginAction === PluginAction.UPDATE || pluginAction === PluginAction.UNINSTALL) && (
|
||||||
<div className="field is-horizontal">
|
<div className="field is-horizontal">
|
||||||
<ListParent className={classNames("field-label", "is-inline-flex")}>
|
<ListParent>{t("plugins.modal.currentVersion")}:</ListParent>
|
||||||
{t("plugins.modal.currentVersion")}:
|
|
||||||
</ListParent>
|
|
||||||
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.version}</ListChild>
|
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.version}</ListChild>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{pluginAction === PluginAction.UPDATE && (
|
{pluginAction === PluginAction.UPDATE && (
|
||||||
<div className="field is-horizontal">
|
<div className="field is-horizontal">
|
||||||
<ListParent className={classNames("field-label", "is-inline-flex")}>
|
<ListParent>{t("plugins.modal.newVersion")}:</ListParent>
|
||||||
{t("plugins.modal.newVersion")}:
|
|
||||||
</ListParent>
|
|
||||||
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.newVersion}</ListChild>
|
<ListChild className={classNames("field-body", "is-inline-flex")}>{plugin.newVersion}</ListChild>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -23,24 +23,27 @@
|
|||||||
*/
|
*/
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children?: React.Node;
|
children?: React.Node;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChildWrapper = styled.div`
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class PluginTopActions extends React.Component<Props> {
|
export default class PluginTopActions extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
return (
|
return (
|
||||||
<ChildWrapper className={classNames("column", "is-flex", "is-one-fifths", "is-mobile-action-spacing")}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"column",
|
||||||
|
"is-one-fifths",
|
||||||
|
"is-mobile-action-spacing",
|
||||||
|
"is-flex",
|
||||||
|
"is-justify-content-flex-end",
|
||||||
|
"is-align-items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</ChildWrapper>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class AvailableVerbs extends React.Component<Props> {
|
|||||||
let verbs = null;
|
let verbs = null;
|
||||||
if (role.verbs.length > 0) {
|
if (role.verbs.length > 0) {
|
||||||
verbs = (
|
verbs = (
|
||||||
<td className="is-paddingless">
|
<td className="p-0">
|
||||||
<ul>
|
<ul>
|
||||||
{role.verbs.map((verb, key) => {
|
{role.verbs.map((verb, key) => {
|
||||||
return <li key={key}>{t("verbs.repository." + verb + ".displayName")}</li>;
|
return <li key={key}>{t("verbs.repository." + verb + ".displayName")}</li>;
|
||||||
|
|||||||
@@ -23,24 +23,18 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
|
||||||
import { Tag } from "@scm-manager/ui-components";
|
import { Tag } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
system?: boolean;
|
system?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LeftMarginTag = styled(Tag)`
|
|
||||||
margin-left: 0.75rem;
|
|
||||||
vertical-align: inherit;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class SystemRoleTag extends React.Component<Props> {
|
class SystemRoleTag extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { system, t } = this.props;
|
const { system, t } = this.props;
|
||||||
|
|
||||||
if (system) {
|
if (system) {
|
||||||
return <LeftMarginTag color="dark" label={t("repositoryRole.system")} />;
|
return <Tag className="ml-3" color="dark" label={t("repositoryRole.system")} />;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,28 +33,13 @@ type Props = WithTranslation & {
|
|||||||
item?: InfoItem;
|
item?: InfoItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
const BottomMarginA = styled.a`
|
|
||||||
display: blocK;
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FixedSizedIconWrapper = styled.div`
|
const FixedSizedIconWrapper = styled.div`
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 160px;
|
width: 160px;
|
||||||
height: 160px;
|
height: 160px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const LightBlueIcon = styled(Icon)`
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
color: #bff1e6;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ContentWrapper = styled.div`
|
const ContentWrapper = styled.div`
|
||||||
min-height: 10.5rem;
|
min-height: 10.5rem;
|
||||||
margin-left: 1.5em;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
class InfoBox extends React.Component<Props> {
|
class InfoBox extends React.Component<Props> {
|
||||||
@@ -64,7 +49,7 @@ class InfoBox extends React.Component<Props> {
|
|||||||
const summary = item ? item.summary : t("login.loading");
|
const summary = item ? item.summary : t("login.loading");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContentWrapper className={classNames("media-content", "content")}>
|
<ContentWrapper className={classNames("media-content", "content", "ml-5")}>
|
||||||
<h4 className="has-text-link">{title}</h4>
|
<h4 className="has-text-link">{title}</h4>
|
||||||
<p>{summary}</p>
|
<p>{summary}</p>
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
@@ -75,20 +60,30 @@ class InfoBox extends React.Component<Props> {
|
|||||||
const { item, type, t } = this.props;
|
const { item, type, t } = this.props;
|
||||||
const icon = type === "plugin" ? "puzzle-piece" : "star";
|
const icon = type === "plugin" ? "puzzle-piece" : "star";
|
||||||
return (
|
return (
|
||||||
<BottomMarginA href={item._links.self.href}>
|
<a className="is-block mb-5" href={item._links.self.href}>
|
||||||
<div className="box media">
|
<div className="box media">
|
||||||
<figure className="media-left">
|
<figure className="media-left">
|
||||||
<FixedSizedIconWrapper
|
<FixedSizedIconWrapper
|
||||||
className={classNames("image", "box", "has-text-weight-bold", "has-text-white", "has-background-info")}
|
className={classNames(
|
||||||
|
"image",
|
||||||
|
"box",
|
||||||
|
"has-text-weight-bold",
|
||||||
|
"has-text-white",
|
||||||
|
"has-background-info",
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-direction-column",
|
||||||
|
"is-justify-content-center",
|
||||||
|
"is-align-items-center"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<LightBlueIcon className="fa-2x" name={icon} color="inherit" />
|
<Icon className="has-text-blue-light mb-2 fa-2x" name={icon} color="inherit" />
|
||||||
<div className="is-size-4">{t("login." + type)}</div>
|
<div className="is-size-4">{t("login." + type)}</div>
|
||||||
<div className="is-size-4">{t("login.tip")}</div>
|
<div className="is-size-4">{t("login.tip")}</div>
|
||||||
</FixedSizedIconWrapper>
|
</FixedSizedIconWrapper>
|
||||||
</figure>
|
</figure>
|
||||||
{this.renderBody()}
|
{this.renderBody()}
|
||||||
</div>
|
</div>
|
||||||
</BottomMarginA>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, {FormEvent} from "react";
|
import React, { FormEvent } from "react";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { ErrorNotification, Image, InputField, SubmitButton, UnauthorizedError } from "@scm-manager/ui-components";
|
import { ErrorNotification, Image, InputField, SubmitButton, UnauthorizedError } from "@scm-manager/ui-components";
|
||||||
@@ -50,7 +50,7 @@ const AvatarImage = styled(Image)`
|
|||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
background: #fff;
|
background: white;
|
||||||
border: 1px solid lightgray;
|
border: 1px solid lightgray;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
`;
|
`;
|
||||||
@@ -60,7 +60,7 @@ class LoginForm extends React.Component<Props, State> {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
username: "",
|
username: "",
|
||||||
password: ""
|
password: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,13 +73,13 @@ class LoginForm extends React.Component<Props, State> {
|
|||||||
|
|
||||||
handleUsernameChange = (value: string) => {
|
handleUsernameChange = (value: string) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
username: value
|
username: value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
handlePasswordChange = (value: string) => {
|
handlePasswordChange = (value: string) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
password: value
|
password: value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class LoginInfo extends React.Component<Props, State> {
|
|||||||
|
|
||||||
createInfoPanel = (info: LoginInfoResponse) => (
|
createInfoPanel = (info: LoginInfoResponse) => (
|
||||||
<NoOpErrorBoundary>
|
<NoOpErrorBoundary>
|
||||||
<div className="column is-7 is-offset-1 is-paddingless">
|
<div className="column is-7 is-offset-1 p-0">
|
||||||
<InfoBox item={info.feature} type="feature" />
|
<InfoBox item={info.feature} type="feature" />
|
||||||
<InfoBox item={info.plugin} type="plugin" />
|
<InfoBox item={info.plugin} type="plugin" />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -131,12 +131,12 @@ const InitializationAdminAccountStep: FC<Props> = ({ data }) => {
|
|||||||
<h3 className="title">{t("title")}</h3>
|
<h3 className="title">{t("title")}</h3>
|
||||||
<h4 className="subtitle">{t("adminStep.title")}</h4>
|
<h4 className="subtitle">{t("adminStep.title")}</h4>
|
||||||
<p>{t("adminStep.description")}</p>
|
<p>{t("adminStep.description")}</p>
|
||||||
<div className={"columns"}>
|
<div className="columns">
|
||||||
<div className="column is-full-width">
|
<div className="column is-full-width">
|
||||||
<InputField placeholder={t("adminStep.startupToken")} autofocus={true} {...register("startupToken")} />
|
<InputField placeholder={t("adminStep.startupToken")} autofocus={true} {...register("startupToken")} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={"columns"}>
|
<div className="columns">
|
||||||
<div className="column is-half">
|
<div className="column is-half">
|
||||||
<InputField
|
<InputField
|
||||||
testId="username-input"
|
testId="username-input"
|
||||||
@@ -154,7 +154,7 @@ const InitializationAdminAccountStep: FC<Props> = ({ data }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={"columns"}>
|
<div className="columns">
|
||||||
<div className="column is-full-width">
|
<div className="column is-full-width">
|
||||||
<InputField
|
<InputField
|
||||||
label={t("adminStep.email")}
|
label={t("adminStep.email")}
|
||||||
@@ -163,7 +163,7 @@ const InitializationAdminAccountStep: FC<Props> = ({ data }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={"columns"}>
|
<div className="columns">
|
||||||
<div className="column is-half">
|
<div className="column is-half">
|
||||||
<InputField
|
<InputField
|
||||||
testId="password-input"
|
testId="password-input"
|
||||||
@@ -184,7 +184,7 @@ const InitializationAdminAccountStep: FC<Props> = ({ data }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{errorComponent}
|
{errorComponent}
|
||||||
<div className={"columns"}>
|
<div className="columns">
|
||||||
<div className="column is-full-width">
|
<div className="column is-full-width">
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
label={t("adminStep.submit")}
|
label={t("adminStep.submit")}
|
||||||
|
|||||||
@@ -23,15 +23,10 @@
|
|||||||
*/
|
*/
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Redirect, useLocation } from "react-router-dom";
|
import { Redirect, useLocation } from "react-router-dom";
|
||||||
import styled from "styled-components";
|
|
||||||
import LoginInfo from "../components/LoginInfo";
|
import LoginInfo from "../components/LoginInfo";
|
||||||
import { parse } from "query-string";
|
import { parse } from "query-string";
|
||||||
import { useIndexLink, useLogin } from "@scm-manager/ui-api";
|
import { useIndexLink, useLogin } from "@scm-manager/ui-api";
|
||||||
|
|
||||||
const HeroSection = styled.section`
|
|
||||||
padding-top: 2em;
|
|
||||||
`;
|
|
||||||
|
|
||||||
interface FromObject {
|
interface FromObject {
|
||||||
from?: string;
|
from?: string;
|
||||||
}
|
}
|
||||||
@@ -62,7 +57,7 @@ const Login: FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeroSection className="hero">
|
<section className="hero pt-6">
|
||||||
<div className="hero-body">
|
<div className="hero-body">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="columns is-centered">
|
<div className="columns is-centered">
|
||||||
@@ -70,7 +65,7 @@ const Login: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</HeroSection>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,18 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, useEffect, useState } from "react";
|
import React, { FC, useEffect, useState } from "react";
|
||||||
|
import { useHistory, Link } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import {
|
||||||
|
useClearNotifications,
|
||||||
|
useDismissNotification,
|
||||||
|
useNotifications,
|
||||||
|
useNotificationSubscription,
|
||||||
|
} from "@scm-manager/ui-api";
|
||||||
|
import { Notification, NotificationCollection } from "@scm-manager/ui-types";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Notification as InfoNotification,
|
Notification as InfoNotification,
|
||||||
@@ -35,26 +45,6 @@ import {
|
|||||||
DateFromNow,
|
DateFromNow,
|
||||||
devices,
|
devices,
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import styled from "styled-components";
|
|
||||||
import {
|
|
||||||
useClearNotifications,
|
|
||||||
useDismissNotification,
|
|
||||||
useNotifications,
|
|
||||||
useNotificationSubscription,
|
|
||||||
} from "@scm-manager/ui-api";
|
|
||||||
import { Notification, NotificationCollection } from "@scm-manager/ui-types";
|
|
||||||
import { useHistory, Link } from "react-router-dom";
|
|
||||||
import classNames from "classnames";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
const Bell = styled(Icon)`
|
|
||||||
font-size: 1.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Container = styled.div`
|
|
||||||
display: flex;
|
|
||||||
cursor: pointer;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const DropDownMenu = styled.div`
|
const DropDownMenu = styled.div`
|
||||||
min-width: 35rem;
|
min-width: 35rem;
|
||||||
@@ -130,7 +120,7 @@ const NotificationEntry: FC<EntryProps> = ({ notification, removeToast }) => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<tr className={`is-${color(notification)}`}>
|
<tr className={`is-${color(notification)}`}>
|
||||||
<VerticalCenteredTd onClick={() => history.push(notification.link)} className="has-cursor-pointer">
|
<VerticalCenteredTd onClick={() => history.push(notification.link)} className="is-clickable">
|
||||||
<NotificationMessage message={notification.message} />
|
<NotificationMessage message={notification.message} />
|
||||||
</VerticalCenteredTd>
|
</VerticalCenteredTd>
|
||||||
<DateColumn className="has-text-right">
|
<DateColumn className="has-text-right">
|
||||||
@@ -143,7 +133,7 @@ const NotificationEntry: FC<EntryProps> = ({ notification, removeToast }) => {
|
|||||||
<Icon
|
<Icon
|
||||||
name="trash"
|
name="trash"
|
||||||
color="black"
|
color="black"
|
||||||
className="has-cursor-pointer"
|
className="is-clickable"
|
||||||
title={t("notifications.dismiss")}
|
title={t("notifications.dismiss")}
|
||||||
onClick={remove}
|
onClick={remove}
|
||||||
/>
|
/>
|
||||||
@@ -172,7 +162,7 @@ const ClearEntry: FC<ClearEntryProps> = ({ notifications, clearToasts }) => {
|
|||||||
clearStore();
|
clearStore();
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="dropdown-item has-text-centered">
|
<div className={classNames("dropdown-item", "has-text-centered")}>
|
||||||
<ErrorNotification error={error} />
|
<ErrorNotification error={error} />
|
||||||
<DismissAllButton className="is-outlined" color="link" loading={isLoading} action={clear}>
|
<DismissAllButton className="is-outlined" color="link" loading={isLoading} action={clear}>
|
||||||
<Icon color="link" name="trash" className="mr-1" /> {t("notifications.dismissAll")}
|
<Icon color="link" name="trash" className="mr-1" /> {t("notifications.dismissAll")}
|
||||||
@@ -189,8 +179,8 @@ const NotificationList: FC<Props> = ({ data, clear, remove }) => {
|
|||||||
const top = all.slice(0, 6);
|
const top = all.slice(0, 6);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dropdown-content p-0">
|
<div className={classNames("dropdown-content", "p-0")}>
|
||||||
<table className="table mb-0 card-table">
|
<table className={classNames("table", "card-table", "mb-0")}>
|
||||||
<tbody>
|
<tbody>
|
||||||
{top.map((n, i) => (
|
{top.map((n, i) => (
|
||||||
<NotificationEntry key={i} notification={n} removeToast={remove} />
|
<NotificationEntry key={i} notification={n} removeToast={remove} />
|
||||||
@@ -198,14 +188,18 @@ const NotificationList: FC<Props> = ({ data, clear, remove }) => {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{all.length > 6 ? (
|
{all.length > 6 ? (
|
||||||
<p className="has-text-centered has-text-grey">{t("notifications.xMore", { count: all.length - 6 })}</p>
|
<p className={classNames("has-text-centered", "has-text-grey")}>
|
||||||
|
{t("notifications.xMore", { count: all.length - 6 })}
|
||||||
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
{clearLink ? <ClearEntry notifications={data} clearToasts={clear} /> : null}
|
{clearLink ? <ClearEntry notifications={data} clearToasts={clear} /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DropdownMenuContainer: FC = ({ children }) => <div className="dropdown-content p-4">{children}</div>;
|
const DropdownMenuContainer: FC = ({ children }) => (
|
||||||
|
<div className={classNames("dropdown-content", "p-4")}>{children}</div>
|
||||||
|
);
|
||||||
|
|
||||||
const NoNotifications: FC = () => {
|
const NoNotifications: FC = () => {
|
||||||
const [t] = useTranslation("commons");
|
const [t] = useTranslation("commons");
|
||||||
@@ -278,12 +272,8 @@ const NotificationSubscription: FC<SubscriptionProps> = ({ notifications, remove
|
|||||||
};
|
};
|
||||||
|
|
||||||
const BellNotificationContainer = styled.div`
|
const BellNotificationContainer = styled.div`
|
||||||
position: relative;
|
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type NotificationCounterProps = {
|
type NotificationCounterProps = {
|
||||||
@@ -304,8 +294,11 @@ type BellNotificationIconProps = {
|
|||||||
const BellNotificationIcon: FC<BellNotificationIconProps> = ({ data, onClick }) => {
|
const BellNotificationIcon: FC<BellNotificationIconProps> = ({ data, onClick }) => {
|
||||||
const counter = data?._embedded.notifications.length || 0;
|
const counter = data?._embedded.notifications.length || 0;
|
||||||
return (
|
return (
|
||||||
<BellNotificationContainer onClick={onClick}>
|
<BellNotificationContainer
|
||||||
<Bell iconStyle={counter === 0 ? "far" : "fas"} name="bell" color="white" />
|
className={classNames("is-relative", "is-flex", "is-justify-content-center", "is-align-items-center")}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
<Icon className="is-size-4" iconStyle={counter === 0 ? "far" : "fas"} name="bell" color="white" />
|
||||||
{counter > 0 ? <NotificationCounter count={counter}>{counter < 100 ? counter : "∞"}</NotificationCounter> : null}
|
{counter > 0 ? <NotificationCounter count={counter}>{counter < 100 ? counter : "∞"}</NotificationCounter> : null}
|
||||||
</BellNotificationContainer>
|
</BellNotificationContainer>
|
||||||
);
|
);
|
||||||
@@ -357,9 +350,9 @@ const Notifications: FC<NotificationProps> = ({ className }) => {
|
|||||||
)}
|
)}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<Container className="dropdown-trigger">
|
<div className={classNames("is-flex", "dropdown-trigger", "is-clickable")}>
|
||||||
<BellNotificationIcon data={data} onClick={() => setOpen((o) => !o)} />
|
<BellNotificationIcon data={data} onClick={() => setOpen((o) => !o)} />
|
||||||
</Container>
|
</div>
|
||||||
<DropDownMenu className="dropdown-menu" id="dropdown-menu" role="menu">
|
<DropDownMenu className="dropdown-menu" id="dropdown-menu" role="menu">
|
||||||
<ErrorBox error={error} />
|
<ErrorBox error={error} />
|
||||||
{isLoading ? <LoadingBox /> : null}
|
{isLoading ? <LoadingBox /> : null}
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ import SyntaxModal from "../search/SyntaxModal";
|
|||||||
import SearchErrorNotification from "../search/SearchErrorNotification";
|
import SearchErrorNotification from "../search/SearchErrorNotification";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
|
|
||||||
const Field = styled.div`
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Input = styled.input`
|
const Input = styled.input`
|
||||||
border-radius: 4px !important;
|
border-radius: 4px !important;
|
||||||
`;
|
`;
|
||||||
@@ -77,12 +73,6 @@ const EmptyHits: FC = () => {
|
|||||||
|
|
||||||
const ResultHeading = styled.h3`
|
const ResultHeading = styled.h3`
|
||||||
border-bottom: 1px solid lightgray;
|
border-bottom: 1px solid lightgray;
|
||||||
margin: 0 0.5rem;
|
|
||||||
padding: 0.375rem 0.5rem;
|
|
||||||
font-weight: bold;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DropdownMenu = styled.div`
|
const DropdownMenu = styled.div`
|
||||||
@@ -91,8 +81,6 @@ const DropdownMenu = styled.div`
|
|||||||
|
|
||||||
const ResultFooter = styled.div`
|
const ResultFooter = styled.div`
|
||||||
border-top: 1px solid lightgray;
|
border-top: 1px solid lightgray;
|
||||||
margin: 0 0.5rem;
|
|
||||||
padding: 0.375rem 0.5rem;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AvatarSection: FC<HitProps> = ({ hit }) => {
|
const AvatarSection: FC<HitProps> = ({ hit }) => {
|
||||||
@@ -115,7 +103,7 @@ const AvatarSection: FC<HitProps> = ({ hit }) => {
|
|||||||
const MoreResults: FC<GotoProps> = ({ gotoDetailSearch }) => {
|
const MoreResults: FC<GotoProps> = ({ gotoDetailSearch }) => {
|
||||||
const [t] = useTranslation("commons");
|
const [t] = useTranslation("commons");
|
||||||
return (
|
return (
|
||||||
<ResultFooter className="dropdown-item has-text-centered">
|
<ResultFooter className={classNames("dropdown-item", "has-text-centered", "mx-2", "px-2", "py-1")}>
|
||||||
<Button action={gotoDetailSearch} color="primary" data-omnisearch="true">
|
<Button action={gotoDetailSearch} color="primary" data-omnisearch="true">
|
||||||
{t("search.quickSearch.moreResults")}
|
{t("search.quickSearch.moreResults")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -156,7 +144,18 @@ const Hits: FC<HitsProps> = ({ showHelp, gotoDetailSearch, ...rest }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div aria-expanded="true" role="listbox" className="dropdown-content">
|
<div aria-expanded="true" role="listbox" className="dropdown-content">
|
||||||
<ResultHeading className="dropdown-item">
|
<ResultHeading
|
||||||
|
className={classNames(
|
||||||
|
"dropdown-item",
|
||||||
|
"is-flex",
|
||||||
|
"is-justify-content-space-between",
|
||||||
|
"is-align-items-center",
|
||||||
|
"mx-2",
|
||||||
|
"px-2",
|
||||||
|
"py-1",
|
||||||
|
"has-text-weight-bold"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<span>{t("search.quickSearch.resultHeading")}</span>
|
<span>{t("search.quickSearch.resultHeading")}</span>
|
||||||
<SyntaxHelp onClick={showHelp} />
|
<SyntaxHelp onClick={showHelp} />
|
||||||
</ResultHeading>
|
</ResultHeading>
|
||||||
@@ -331,7 +330,7 @@ const OmniSearch: FC = () => {
|
|||||||
const { onKeyDown, index } = useKeyBoardNavigation(gotoDetailSearch, clearQuery, data?._embedded.hits);
|
const { onKeyDown, index } = useKeyBoardNavigation(gotoDetailSearch, clearQuery, data?._embedded.hits);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Field className="navbar-item field">
|
<div className={classNames("navbar-item", "field", "mb-0")}>
|
||||||
{showHelp ? <SyntaxModal close={closeHelp} /> : null}
|
{showHelp ? <SyntaxModal close={closeHelp} /> : null}
|
||||||
<div
|
<div
|
||||||
className={classNames("control", "has-icons-right", {
|
className={classNames("control", "has-icons-right", {
|
||||||
@@ -376,7 +375,7 @@ const OmniSearch: FC = () => {
|
|||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Field>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,10 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import styled from "styled-components";
|
||||||
import { apiClient, Loading, ErrorNotification, ErrorBoundary, Icon } from "@scm-manager/ui-components";
|
import { apiClient, Loading, ErrorNotification, ErrorBoundary, Icon } from "@scm-manager/ui-components";
|
||||||
import loadBundle from "./loadBundle";
|
import loadBundle from "./loadBundle";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
loaded: boolean;
|
loaded: boolean;
|
||||||
@@ -48,23 +49,11 @@ const BigIcon = styled(Icon)`
|
|||||||
font-size: 10rem;
|
font-size: 10rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Centered = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ErrorMessage = styled.span`
|
|
||||||
font-size: 20px;
|
|
||||||
margin: 1.5rem 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class PluginLoader extends React.Component<Props, State> {
|
class PluginLoader extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
message: "booting"
|
message: "booting",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +61,7 @@ class PluginLoader extends React.Component<Props, State> {
|
|||||||
const { loaded } = this.props;
|
const { loaded } = this.props;
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
this.setState({
|
this.setState({
|
||||||
message: "loading plugin information"
|
message: "loading plugin information",
|
||||||
});
|
});
|
||||||
|
|
||||||
this.getPlugins(this.props.link);
|
this.getPlugins(this.props.link);
|
||||||
@@ -82,16 +71,16 @@ class PluginLoader extends React.Component<Props, State> {
|
|||||||
getPlugins = (link: string): Promise<any> => {
|
getPlugins = (link: string): Promise<any> => {
|
||||||
return apiClient
|
return apiClient
|
||||||
.get(link)
|
.get(link)
|
||||||
.then(response => response.text())
|
.then((response) => response.text())
|
||||||
.then(JSON.parse)
|
.then(JSON.parse)
|
||||||
.then(pluginCollection => pluginCollection._embedded.plugins)
|
.then((pluginCollection) => pluginCollection._embedded.plugins)
|
||||||
.then(this.loadPlugins)
|
.then(this.loadPlugins)
|
||||||
.then(this.props.callback);
|
.then(this.props.callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
loadPlugins = (plugins: Plugin[]) => {
|
loadPlugins = (plugins: Plugin[]) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
message: "loading plugins"
|
message: "loading plugins",
|
||||||
});
|
});
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
@@ -100,21 +89,21 @@ class PluginLoader extends React.Component<Props, State> {
|
|||||||
promises.push(this.loadPlugin(plugin));
|
promises.push(this.loadPlugin(plugin));
|
||||||
}
|
}
|
||||||
return promises.reduce((chain, current) => {
|
return promises.reduce((chain, current) => {
|
||||||
return chain.then(chainResults => {
|
return chain.then((chainResults) => {
|
||||||
return current.then(currentResult => [...chainResults, currentResult]);
|
return current.then((currentResult) => [...chainResults, currentResult]);
|
||||||
});
|
});
|
||||||
}, Promise.resolve([]));
|
}, Promise.resolve([]));
|
||||||
};
|
};
|
||||||
|
|
||||||
loadPlugin = (plugin: Plugin) => {
|
loadPlugin = (plugin: Plugin) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
message: `loading ${plugin.name}`
|
message: `loading ${plugin.name}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (const bundle of plugin.bundles) {
|
for (const bundle of plugin.bundles) {
|
||||||
promises.push(
|
promises.push(
|
||||||
loadBundle(bundle).catch(error => this.setState({ error, errorMessage: `loading ${plugin.name} failed` }))
|
loadBundle(bundle).catch((error) => this.setState({ error, errorMessage: `loading ${plugin.name} failed` }))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
@@ -129,10 +118,17 @@ class PluginLoader extends React.Component<Props, State> {
|
|||||||
<section className="section">
|
<section className="section">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Centered>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
"is-flex",
|
||||||
|
"is-flex-direction-column",
|
||||||
|
"is-justify-content-space-between",
|
||||||
|
"is-align-items-center"
|
||||||
|
)}
|
||||||
|
>
|
||||||
<BigIcon name="exclamation-triangle" color="danger" />
|
<BigIcon name="exclamation-triangle" color="danger" />
|
||||||
<ErrorMessage>{errorMessage}</ErrorMessage>
|
<div className={classNames("my-5", "is-size-5")}>{errorMessage}</div>
|
||||||
</Centered>
|
</div>
|
||||||
<ErrorNotification error={error} />
|
<ErrorNotification error={error} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class ProfileInfo extends React.Component<Props> {
|
|||||||
groups = (
|
groups = (
|
||||||
<tr>
|
<tr>
|
||||||
<th>{t("profile.groups")}</th>
|
<th>{t("profile.groups")}</th>
|
||||||
<td className="is-paddingless">
|
<td className="p-0">
|
||||||
<ul>
|
<ul>
|
||||||
{me.groups.map(group => {
|
{me.groups.map(group => {
|
||||||
return <li>{group}</li>;
|
return <li>{group}</li>;
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
|
||||||
import { Group } from "@scm-manager/ui-types";
|
import { Group } from "@scm-manager/ui-types";
|
||||||
import { Checkbox, DateFromNow } from "@scm-manager/ui-components";
|
import { Checkbox, DateFromNow } from "@scm-manager/ui-components";
|
||||||
import GroupMember from "./GroupMember";
|
import GroupMember from "./GroupMember";
|
||||||
@@ -32,10 +31,6 @@ type Props = WithTranslation & {
|
|||||||
group: Group;
|
group: Group;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledMemberList = styled.ul`
|
|
||||||
margin-left: 1em !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class Details extends React.Component<Props> {
|
class Details extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { group, t } = this.props;
|
const { group, t } = this.props;
|
||||||
@@ -86,12 +81,12 @@ class Details extends React.Component<Props> {
|
|||||||
member = (
|
member = (
|
||||||
<tr>
|
<tr>
|
||||||
<th>{t("group.members")}</th>
|
<th>{t("group.members")}</th>
|
||||||
<td className="is-paddingless">
|
<td className="p-0">
|
||||||
<StyledMemberList>
|
<ul className="ml-4">
|
||||||
{group._embedded.members.map((member, index) => {
|
{group._embedded.members.map((member, index) => {
|
||||||
return <GroupMember key={index} member={member} />;
|
return <GroupMember key={index} member={member} />;
|
||||||
})}
|
})}
|
||||||
</StyledMemberList>
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Member } from "@scm-manager/ui-types";
|
import { Member } from "@scm-manager/ui-types";
|
||||||
import { Icon } from "@scm-manager/ui-components";
|
import { Icon } from "@scm-manager/ui-components";
|
||||||
@@ -32,9 +33,6 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const StyledMember = styled.li`
|
const StyledMember = styled.li`
|
||||||
display: inline-block;
|
|
||||||
margin-right: 0.25rem;
|
|
||||||
padding: 0.25rem 0.75rem;
|
|
||||||
border: 1px solid #eee;
|
border: 1px solid #eee;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
`;
|
`;
|
||||||
@@ -59,6 +57,10 @@ export default class GroupMember extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
const { member } = this.props;
|
const { member } = this.props;
|
||||||
const to = `/user/${member.name}`;
|
const to = `/user/${member.name}`;
|
||||||
return <StyledMember>{this.showName(to, member)}</StyledMember>;
|
return (
|
||||||
|
<StyledMember className={classNames("is-inline-block", "mr-1", "px-3", "py-1")}>
|
||||||
|
{this.showName(to, member)}
|
||||||
|
</StyledMember>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import PermissionCheckbox from "./PermissionCheckbox";
|
|
||||||
import { Loading } from "@scm-manager/ui-components";
|
import { Loading } from "@scm-manager/ui-components";
|
||||||
|
import PermissionCheckbox from "./PermissionCheckbox";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
permissions: {
|
permissions: {
|
||||||
@@ -37,8 +37,6 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const StyledWrapper = styled.div`
|
const StyledWrapper = styled.div`
|
||||||
padding-bottom: 0;
|
|
||||||
|
|
||||||
& .field .control {
|
& .field .control {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
@@ -56,7 +54,7 @@ export default class PermissionsWrapper extends React.Component<Props> {
|
|||||||
const permissionArray = Object.keys(permissions);
|
const permissionArray = Object.keys(permissions);
|
||||||
return (
|
return (
|
||||||
<div className="columns">
|
<div className="columns">
|
||||||
<StyledWrapper className={classNames("column", "is-half")}>
|
<StyledWrapper className={classNames("column", "is-half", "pb-0")}>
|
||||||
{permissionArray.slice(0, permissionArray.length / 2 + 1).map(p => (
|
{permissionArray.slice(0, permissionArray.length / 2 + 1).map(p => (
|
||||||
<PermissionCheckbox
|
<PermissionCheckbox
|
||||||
key={p}
|
key={p}
|
||||||
|
|||||||
@@ -22,49 +22,34 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||||
|
import { DateFromNow } from "@scm-manager/ui-components";
|
||||||
import BranchButtonGroup from "./BranchButtonGroup";
|
import BranchButtonGroup from "./BranchButtonGroup";
|
||||||
import DefaultBranchTag from "./DefaultBranchTag";
|
import DefaultBranchTag from "./DefaultBranchTag";
|
||||||
import { DateFromNow } from "@scm-manager/ui-components";
|
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
repository: Repository;
|
repository: Repository;
|
||||||
branch: Branch;
|
branch: Branch;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FlexRow = styled.div`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Created = styled.div`
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Label = styled.strong`
|
|
||||||
margin-right: 0.3rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Date = styled(DateFromNow)`
|
|
||||||
font-size: 0.8rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class BranchDetail extends React.Component<Props> {
|
class BranchDetail extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { repository, branch, t } = this.props;
|
const { repository, branch, t } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="media">
|
<div className="media">
|
||||||
<FlexRow className="media-content subtitle">
|
<div
|
||||||
<Label>{t("branch.name")}</Label> {branch.name} <DefaultBranchTag defaultBranch={branch.defaultBranch} />
|
className={classNames("media-content", "subtitle", "is-flex", "is-align-items-center", "is-flex-wrap-wrap")}
|
||||||
<Created className="is-ellipsis-overflow">
|
>
|
||||||
{t("branches.overview.lastCommit")} <Date date={branch.lastCommitDate} className="has-text-grey" />
|
<strong className="mr-1">{t("branch.name")}</strong> {branch.name}{" "}
|
||||||
</Created>
|
<DefaultBranchTag defaultBranch={branch.defaultBranch} />
|
||||||
</FlexRow>
|
<div className={classNames("is-ellipsis-overflow", "is-size-7", "ml-2")}>
|
||||||
|
{t("branches.overview.lastCommit")}{" "}
|
||||||
|
<DateFromNow className={classNames("is-size-7", "has-text-grey")} date={branch.lastCommitDate} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="media-right">
|
<div className="media-right">
|
||||||
<BranchButtonGroup repository={repository} branch={branch} />
|
<BranchButtonGroup repository={repository} branch={branch} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
*/
|
*/
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Link as ReactLink } from "react-router-dom";
|
import { Link as ReactLink } from "react-router-dom";
|
||||||
import { Branch, Link } from "@scm-manager/ui-types";
|
|
||||||
import DefaultBranchTag from "./DefaultBranchTag";
|
|
||||||
import { DateFromNow, Icon } from "@scm-manager/ui-components";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
import classNames from "classnames";
|
||||||
|
import { Branch, Link } from "@scm-manager/ui-types";
|
||||||
|
import { DateFromNow, Icon } from "@scm-manager/ui-components";
|
||||||
|
import DefaultBranchTag from "./DefaultBranchTag";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
@@ -35,11 +35,6 @@ type Props = {
|
|||||||
onDelete: (branch: Branch) => void;
|
onDelete: (branch: Branch) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Created = styled.span`
|
|
||||||
margin-left: 1rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BranchRow: FC<Props> = ({ baseUrl, branch, onDelete }) => {
|
const BranchRow: FC<Props> = ({ baseUrl, branch, onDelete }) => {
|
||||||
const to = `${baseUrl}/${encodeURIComponent(branch.name)}/info`;
|
const to = `${baseUrl}/${encodeURIComponent(branch.name)}/info`;
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
@@ -63,9 +58,9 @@ const BranchRow: FC<Props> = ({ baseUrl, branch, onDelete }) => {
|
|||||||
<DefaultBranchTag defaultBranch={branch.defaultBranch} />
|
<DefaultBranchTag defaultBranch={branch.defaultBranch} />
|
||||||
</ReactLink>
|
</ReactLink>
|
||||||
{branch.lastCommitDate && (
|
{branch.lastCommitDate && (
|
||||||
<Created className="has-text-grey is-ellipsis-overflow">
|
<span className={classNames("has-text-grey", "is-ellipsis-overflow", "is-size-7", "ml-4")}>
|
||||||
{t("branches.table.lastCommit")} <DateFromNow date={branch.lastCommitDate} />
|
{t("branches.table.lastCommit")} <DateFromNow date={branch.lastCommitDate} />
|
||||||
</Created>
|
</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="is-darker">{deleteButton}</td>
|
<td className="is-darker">{deleteButton}</td>
|
||||||
|
|||||||
@@ -23,24 +23,18 @@
|
|||||||
*/
|
*/
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { WithTranslation, withTranslation } from "react-i18next";
|
import { WithTranslation, withTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
|
||||||
import { Tag } from "@scm-manager/ui-components";
|
import { Tag } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = WithTranslation & {
|
type Props = WithTranslation & {
|
||||||
defaultBranch?: boolean;
|
defaultBranch?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LeftMarginTag = styled(Tag)`
|
|
||||||
vertical-align: inherit;
|
|
||||||
margin-left: 0.75rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
class DefaultBranchTag extends React.Component<Props> {
|
class DefaultBranchTag extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { defaultBranch, t } = this.props;
|
const { defaultBranch, t } = this.props;
|
||||||
|
|
||||||
if (defaultBranch) {
|
if (defaultBranch) {
|
||||||
return <LeftMarginTag color="dark" label={t("branch.defaultTag")} />;
|
return <Tag className="ml-3" color="dark" label={t("branch.defaultTag")} />;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,6 @@ const LeftOverflowTd = styled.td`
|
|||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ResultNotification = styled(Notification)`
|
|
||||||
margin: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type PathResultRowProps = {
|
type PathResultRowProps = {
|
||||||
contentBaseUrl: string;
|
contentBaseUrl: string;
|
||||||
path: string;
|
path: string;
|
||||||
@@ -81,7 +77,7 @@ type ResultTableProps = {
|
|||||||
const ResultTable: FC<ResultTableProps> = ({ contentBaseUrl, paths }) => (
|
const ResultTable: FC<ResultTableProps> = ({ contentBaseUrl, paths }) => (
|
||||||
<table className="table table-hover table-sm is-fullwidth">
|
<table className="table table-hover table-sm is-fullwidth">
|
||||||
<tbody>
|
<tbody>
|
||||||
{paths.map(path => (
|
{paths.map((path) => (
|
||||||
<PathResultRow contentBaseUrl={contentBaseUrl} path={path} />
|
<PathResultRow contentBaseUrl={contentBaseUrl} path={path} />
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -92,13 +88,17 @@ const FileSearchResults: FC<Props> = ({ query, contentBaseUrl, paths = [] }) =>
|
|||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
let body;
|
let body;
|
||||||
if (query.length <= 1) {
|
if (query.length <= 1) {
|
||||||
body = <ResultNotification type="info">{t("filesearch.notifications.queryToShort")}</ResultNotification>;
|
body = (
|
||||||
|
<Notification className="m-4" type="info">
|
||||||
|
{t("filesearch.notifications.queryToShort")}
|
||||||
|
</Notification>
|
||||||
|
);
|
||||||
} else if (paths.length === 0) {
|
} else if (paths.length === 0) {
|
||||||
const queryCmp = <strong>{query}</strong>;
|
const queryCmp = <strong>{query}</strong>;
|
||||||
body = (
|
body = (
|
||||||
<ResultNotification type="info">
|
<Notification className="m-4" type="info">
|
||||||
<Trans i18nKey="repos:filesearch.notifications.emptyResult" values={{ query }} components={[queryCmp]} />
|
<Trans i18nKey="repos:filesearch.notifications.emptyResult" values={{ query }} components={[queryCmp]} />
|
||||||
</ResultNotification>
|
</Notification>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
body = <ResultTable contentBaseUrl={contentBaseUrl} paths={paths} />;
|
body = <ResultTable contentBaseUrl={contentBaseUrl} paths={paths} />;
|
||||||
|
|||||||
@@ -22,14 +22,15 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC, useEffect, useState } from "react";
|
import React, { FC, useEffect, useState } from "react";
|
||||||
import { Branch, Repository } from "@scm-manager/ui-types";
|
|
||||||
import { Link, useHistory, useLocation, useParams } from "react-router-dom";
|
import { Link, useHistory, useLocation, useParams } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { Branch, Repository } from "@scm-manager/ui-types";
|
||||||
import { urls, usePaths } from "@scm-manager/ui-api";
|
import { urls, usePaths } from "@scm-manager/ui-api";
|
||||||
import { ErrorNotification, FilterInput, Help, Icon, Loading } from "@scm-manager/ui-components";
|
import { ErrorNotification, FilterInput, Help, Icon, Loading } from "@scm-manager/ui-components";
|
||||||
import CodeActionBar from "../components/CodeActionBar";
|
import CodeActionBar from "../components/CodeActionBar";
|
||||||
import styled from "styled-components";
|
|
||||||
import FileSearchResults from "../components/FileSearchResults";
|
import FileSearchResults from "../components/FileSearchResults";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { filepathSearch } from "../utils/filepathSearch";
|
import { filepathSearch } from "../utils/filepathSearch";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -43,27 +44,14 @@ type Params = {
|
|||||||
revision: string;
|
revision: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const InputContainer = styled.div`
|
|
||||||
padding: 1rem 1.75rem 0 1.75rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const HomeLink = styled(Link)`
|
const HomeLink = styled(Link)`
|
||||||
border-right: 1px solid lightgray;
|
border-right: 1px solid lightgray;
|
||||||
margin-right: 0.75rem;
|
|
||||||
padding-right: 0.75em;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const HomeIcon = styled(Icon)`
|
const HomeIcon = styled(Icon)`
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SearchHelp = styled(Help)`
|
|
||||||
margin-left: 0.75rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const useRevision = () => {
|
const useRevision = () => {
|
||||||
const { revision } = useParams<Params>();
|
const { revision } = useParams<Params>();
|
||||||
return revision;
|
return revision;
|
||||||
@@ -113,8 +101,18 @@ const FileSearch: FC<Props> = ({ repository, baseUrl, branches, selectedBranch }
|
|||||||
switchViewLink={evaluateSwitchViewLink}
|
switchViewLink={evaluateSwitchViewLink}
|
||||||
/>
|
/>
|
||||||
<div className="panel">
|
<div className="panel">
|
||||||
<InputContainer>
|
<div
|
||||||
<HomeLink to={contentBaseUrl}>
|
className={classNames(
|
||||||
|
"is-flex",
|
||||||
|
"is-justify-content-flex-start",
|
||||||
|
"is-align-items-center",
|
||||||
|
"pt-4",
|
||||||
|
"mx-3",
|
||||||
|
"px-4",
|
||||||
|
"pb-0"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<HomeLink className={classNames("mr-3", "pr-3")} to={contentBaseUrl}>
|
||||||
<HomeIcon title={t("filesearch.home")} name="home" color="inherit" />
|
<HomeIcon title={t("filesearch.home")} name="home" color="inherit" />
|
||||||
</HomeLink>
|
</HomeLink>
|
||||||
<FilterInput
|
<FilterInput
|
||||||
@@ -124,8 +122,8 @@ const FileSearch: FC<Props> = ({ repository, baseUrl, branches, selectedBranch }
|
|||||||
filter={search}
|
filter={search}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
/>
|
/>
|
||||||
<SearchHelp message={t("filesearch.input.help")} />
|
<Help className="ml-3" message={t("filesearch.input.help")} />
|
||||||
</InputContainer>
|
</div>
|
||||||
<ErrorNotification error={error} />
|
<ErrorNotification error={error} />
|
||||||
{isLoading ? <Loading /> : <FileSearchResults contentBaseUrl={contentBaseUrl} query={query} paths={result} />}
|
{isLoading ? <Loading /> : <FileSearchResults contentBaseUrl={contentBaseUrl} query={query} paths={result} />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,12 +21,10 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC, useState } from "react";
|
import React, { FC, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import { RepositoryUrlImport } from "@scm-manager/ui-types";
|
import { RepositoryUrlImport } from "@scm-manager/ui-types";
|
||||||
import { InputField, validation } from "@scm-manager/ui-components";
|
import { InputField, validation } from "@scm-manager/ui-components";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: RepositoryUrlImport;
|
repository: RepositoryUrlImport;
|
||||||
@@ -35,14 +33,6 @@ type Props = {
|
|||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Column = styled.div`
|
|
||||||
padding: 0 0.75rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Columns = styled.div`
|
|
||||||
padding: 0.75rem 0 0;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ImportFromUrlForm: FC<Props> = ({ repository, onChange, setValid, disabled }) => {
|
const ImportFromUrlForm: FC<Props> = ({ repository, onChange, setValid, disabled }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
const [urlValidationError, setUrlValidationError] = useState(false);
|
const [urlValidationError, setUrlValidationError] = useState(false);
|
||||||
@@ -65,8 +55,8 @@ const ImportFromUrlForm: FC<Props> = ({ repository, onChange, setValid, disabled
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Columns className="columns is-multiline">
|
<div className="columns is-multiline pt-3">
|
||||||
<Column className="column is-full">
|
<div className="column is-full px-3">
|
||||||
<InputField
|
<InputField
|
||||||
label={t("import.importUrl")}
|
label={t("import.importUrl")}
|
||||||
onChange={handleImportUrlChange}
|
onChange={handleImportUrlChange}
|
||||||
@@ -77,27 +67,27 @@ const ImportFromUrlForm: FC<Props> = ({ repository, onChange, setValid, disabled
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onBlur={handleImportUrlBlur}
|
onBlur={handleImportUrlBlur}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</div>
|
||||||
<Column className="column is-half">
|
<div className="column is-half px-3">
|
||||||
<InputField
|
<InputField
|
||||||
label={t("import.username")}
|
label={t("import.username")}
|
||||||
onChange={username => onChange({ ...repository, username })}
|
onChange={(username) => onChange({ ...repository, username })}
|
||||||
value={repository.username}
|
value={repository.username}
|
||||||
helpText={t("help.usernameHelpText")}
|
helpText={t("help.usernameHelpText")}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</div>
|
||||||
<Column className="column is-half">
|
<div className="column is-half px-3">
|
||||||
<InputField
|
<InputField
|
||||||
label={t("import.password")}
|
label={t("import.password")}
|
||||||
onChange={password => onChange({ ...repository, password })}
|
onChange={(password) => onChange({ ...repository, password })}
|
||||||
value={repository.password}
|
value={repository.password}
|
||||||
type="password"
|
type="password"
|
||||||
helpText={t("help.passwordHelpText")}
|
helpText={t("help.passwordHelpText")}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</div>
|
||||||
</Columns>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
Level,
|
Level,
|
||||||
SignatureIcon,
|
SignatureIcon,
|
||||||
Tooltip
|
Tooltip,
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import ContributorTable from "./ContributorTable";
|
import ContributorTable from "./ContributorTable";
|
||||||
import { Link as ReactLink } from "react-router-dom";
|
import { Link as ReactLink } from "react-router-dom";
|
||||||
@@ -54,14 +54,6 @@ type Props = {
|
|||||||
fileControlFactory?: FileControlFactory;
|
fileControlFactory?: FileControlFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
const RightMarginP = styled.p`
|
|
||||||
margin-right: 1em;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BottomMarginLevel = styled(Level)`
|
|
||||||
margin-bottom: 1rem !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const countContributors = (changeset: Changeset) => {
|
const countContributors = (changeset: Changeset) => {
|
||||||
if (changeset.contributors) {
|
if (changeset.contributors) {
|
||||||
return changeset.contributors.length + 1;
|
return changeset.contributors.length + 1;
|
||||||
@@ -69,16 +61,6 @@ const countContributors = (changeset: Changeset) => {
|
|||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FlexRow = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ContributorLine = styled.div`
|
|
||||||
display: flex;
|
|
||||||
cursor: pointer;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ContributorColumn = styled.p`
|
const ContributorColumn = styled.p`
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -92,25 +74,7 @@ const CountColumn = styled.p`
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ContributorDetails = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ContributorToggleLine = styled.p`
|
|
||||||
cursor: pointer;
|
|
||||||
/** margin-bottom is inherit from content p **/
|
|
||||||
margin-bottom: 0.5rem !important;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ChangesetSummary = styled.div`
|
|
||||||
display: flex;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SeparatedParents = styled.div`
|
const SeparatedParents = styled.div`
|
||||||
margin-left: 1em;
|
|
||||||
|
|
||||||
a + a:before {
|
a + a:before {
|
||||||
content: ",\\00A0";
|
content: ",\\00A0";
|
||||||
color: #4a4a4a;
|
color: #4a4a4a;
|
||||||
@@ -126,33 +90,33 @@ const Contributors: FC<{ changeset: Changeset }> = ({ changeset }) => {
|
|||||||
|
|
||||||
if (open) {
|
if (open) {
|
||||||
return (
|
return (
|
||||||
<ContributorDetails>
|
<div className="is-flex is-flex-direction-column mb-4">
|
||||||
<FlexRow>
|
<div className="is-flex">
|
||||||
<ContributorToggleLine onClick={e => setOpen(!open)} className="is-ellipsis-overflow">
|
<p className="is-ellipsis-overflow is-clickable mb-2" onClick={(e) => setOpen(!open)}>
|
||||||
<Icon name="angle-down" /> {t("changeset.contributors.list")}
|
<Icon name="angle-down" /> {t("changeset.contributors.list")}
|
||||||
</ContributorToggleLine>
|
</p>
|
||||||
{signatureIcon}
|
{signatureIcon}
|
||||||
</FlexRow>
|
</div>
|
||||||
<ContributorTable changeset={changeset} />
|
<ContributorTable changeset={changeset} />
|
||||||
</ContributorDetails>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ContributorLine onClick={e => setOpen(!open)}>
|
<div className="is-flex is-clickable" onClick={(e) => setOpen(!open)}>
|
||||||
<ContributorColumn className="is-ellipsis-overflow">
|
<ContributorColumn className="is-ellipsis-overflow">
|
||||||
<Icon name="angle-right" /> <ChangesetAuthor changeset={changeset} />
|
<Icon name="angle-right" /> <ChangesetAuthor changeset={changeset} />
|
||||||
</ContributorColumn>
|
</ContributorColumn>
|
||||||
{signatureIcon}
|
{signatureIcon}
|
||||||
<CountColumn className={"is-hidden-mobile is-hidden-tablet-only is-hidden-desktop-only"}>
|
<CountColumn className="is-hidden-mobile is-hidden-tablet-only is-hidden-desktop-only">
|
||||||
(
|
(
|
||||||
<span className="has-text-link">
|
<span className="has-text-link">
|
||||||
{t("changeset.contributors.count", { count: countContributors(changeset) })}
|
{t("changeset.contributors.count", { count: countContributors(changeset) })}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
</CountColumn>
|
</CountColumn>
|
||||||
</ContributorLine>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -178,13 +142,13 @@ const ChangesetDetails: FC<Props> = ({ changeset, repository, fileControlFactory
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={classNames("content", "is-marginless")}>
|
<div className={classNames("content", "m-0")}>
|
||||||
<h4>
|
<h4>
|
||||||
<ExtensionPoint
|
<ExtensionPoint
|
||||||
name="changeset.description"
|
name="changeset.description"
|
||||||
props={{
|
props={{
|
||||||
changeset,
|
changeset,
|
||||||
value: description.title
|
value: description.title,
|
||||||
}}
|
}}
|
||||||
renderAll={false}
|
renderAll={false}
|
||||||
>
|
>
|
||||||
@@ -193,23 +157,23 @@ const ChangesetDetails: FC<Props> = ({ changeset, repository, fileControlFactory
|
|||||||
</h4>
|
</h4>
|
||||||
<article className="media">
|
<article className="media">
|
||||||
<AvatarWrapper>
|
<AvatarWrapper>
|
||||||
<RightMarginP className={classNames("image", "is-64x64")}>
|
<p className={classNames("image", "is-64x64", "mr-4")}>
|
||||||
<AvatarImage person={changeset.author} />
|
<AvatarImage person={changeset.author} />
|
||||||
</RightMarginP>
|
</p>
|
||||||
</AvatarWrapper>
|
</AvatarWrapper>
|
||||||
<div className="media-content">
|
<div className="media-content">
|
||||||
<Contributors changeset={changeset} />
|
<Contributors changeset={changeset} />
|
||||||
<ChangesetSummary className="is-ellipsis-overflow">
|
<div className="is-flex is-ellipsis-overflow">
|
||||||
<p>
|
<p>
|
||||||
<Trans i18nKey="repos:changeset.summary" components={[id, date]} />
|
<Trans i18nKey="repos:changeset.summary" components={[id, date]} />
|
||||||
</p>
|
</p>
|
||||||
{parents && parents?.length > 0 ? (
|
{parents && parents?.length > 0 ? (
|
||||||
<SeparatedParents>
|
<SeparatedParents className="ml-4">
|
||||||
{t("changeset.parents.label", { count: parents?.length }) + ": "}
|
{t("changeset.parents.label", { count: parents?.length }) + ": "}
|
||||||
{parents}
|
{parents}
|
||||||
</SeparatedParents>
|
</SeparatedParents>
|
||||||
) : null}
|
) : null}
|
||||||
</ChangesetSummary>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="media-right">
|
<div className="media-right">
|
||||||
<ChangesetTags changeset={changeset} />
|
<ChangesetTags changeset={changeset} />
|
||||||
@@ -244,7 +208,7 @@ const ChangesetDetails: FC<Props> = ({ changeset, repository, fileControlFactory
|
|||||||
name="changeset.description"
|
name="changeset.description"
|
||||||
props={{
|
props={{
|
||||||
changeset,
|
changeset,
|
||||||
value: item
|
value: item,
|
||||||
}}
|
}}
|
||||||
renderAll={false}
|
renderAll={false}
|
||||||
>
|
>
|
||||||
@@ -257,7 +221,8 @@ const ChangesetDetails: FC<Props> = ({ changeset, repository, fileControlFactory
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<BottomMarginLevel
|
<Level
|
||||||
|
className="mb-4"
|
||||||
right={
|
right={
|
||||||
<Button
|
<Button
|
||||||
action={collapseDiffs}
|
action={collapseDiffs}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const ContributorTable: FC<Props> = ({ changeset }) => {
|
|||||||
{getContributorsByType().map(contributor => (
|
{getContributorsByType().map(contributor => (
|
||||||
<tr key={contributor.type}>
|
<tr key={contributor.type}>
|
||||||
<SizedTd>{t("changeset.contributor.type." + contributor.type)}:</SizedTd>
|
<SizedTd>{t("changeset.contributor.type." + contributor.type)}:</SizedTd>
|
||||||
<td className="is-ellipsis-overflow is-marginless">
|
<td className="is-ellipsis-overflow m-0">
|
||||||
<CommaSeparatedList>
|
<CommaSeparatedList>
|
||||||
{contributor.persons!.map(person => (
|
{contributor.persons!.map(person => (
|
||||||
<Contributor key={person.name} person={person} />
|
<Contributor key={person.name} person={person} />
|
||||||
|
|||||||
@@ -22,28 +22,14 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC, useCallback, useEffect, useState } from "react";
|
import React, { FC, useCallback, useEffect, useState } from "react";
|
||||||
import styled from "styled-components";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { IndexResources, Repository, RepositoryType, CUSTOM_NAMESPACE_STRATEGY } from "@scm-manager/ui-types";
|
import { IndexResources, Repository, RepositoryType, CUSTOM_NAMESPACE_STRATEGY } from "@scm-manager/ui-types";
|
||||||
import { Checkbox, Level, Select, SubmitButton } from "@scm-manager/ui-components";
|
import { Checkbox, Level, Select, SubmitButton } from "@scm-manager/ui-components";
|
||||||
import NamespaceAndNameFields from "../NamespaceAndNameFields";
|
import NamespaceAndNameFields from "../NamespaceAndNameFields";
|
||||||
import RepositoryInformationForm from "../RepositoryInformationForm";
|
import RepositoryInformationForm from "../RepositoryInformationForm";
|
||||||
|
|
||||||
const CheckboxWrapper = styled.div`
|
|
||||||
margin-top: 2em;
|
|
||||||
flex: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SelectWrapper = styled.div`
|
|
||||||
flex: 1;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const SpaceBetween = styled.div`
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
createRepository?: (repo: RepositoryCreation, shouldInit: boolean) => void;
|
createRepository?: (repo: RepositoryCreation, shouldInit: boolean) => void;
|
||||||
modifyRepository?: (repo: Repository) => void;
|
modifyRepository?: (repo: Repository) => void;
|
||||||
@@ -65,7 +51,7 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
repositoryTypes,
|
repositoryTypes,
|
||||||
namespaceStrategy,
|
namespaceStrategy,
|
||||||
loading,
|
loading,
|
||||||
indexResources
|
indexResources,
|
||||||
}) => {
|
}) => {
|
||||||
const [repo, setRepo] = useState<Repository>({
|
const [repo, setRepo] = useState<Repository>({
|
||||||
name: "",
|
name: "",
|
||||||
@@ -73,15 +59,15 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
type: "",
|
type: "",
|
||||||
contact: "",
|
contact: "",
|
||||||
description: "",
|
description: "",
|
||||||
_links: {}
|
_links: {},
|
||||||
});
|
});
|
||||||
const [initRepository, setInitRepository] = useState(false);
|
const [initRepository, setInitRepository] = useState(false);
|
||||||
const [contextEntries, setContextEntries] = useState({});
|
const [contextEntries, setContextEntries] = useState({});
|
||||||
const setCreationContextEntry = useCallback(
|
const setCreationContextEntry = useCallback(
|
||||||
(key: string, value: any) => {
|
(key: string, value: any) => {
|
||||||
setContextEntries(entries => ({
|
setContextEntries((entries) => ({
|
||||||
...entries,
|
...entries,
|
||||||
[key]: value
|
[key]: value,
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
[setContextEntries]
|
[setContextEntries]
|
||||||
@@ -102,7 +88,7 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
const isValid = () => {
|
const isValid = () => {
|
||||||
return (
|
return (
|
||||||
!(!repo.name || (namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY && !repo.namespace)) &&
|
!(!repo.name || (namespaceStrategy === CUSTOM_NAMESPACE_STRATEGY && !repo.namespace)) &&
|
||||||
Object.values(valid).every(v => v)
|
Object.values(valid).every((v) => v)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,10 +105,10 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
|
|
||||||
const createSelectOptions = (repositoryTypes?: RepositoryType[]) => {
|
const createSelectOptions = (repositoryTypes?: RepositoryType[]) => {
|
||||||
if (repositoryTypes) {
|
if (repositoryTypes) {
|
||||||
return repositoryTypes.map(repositoryType => {
|
return repositoryTypes.map((repositoryType) => {
|
||||||
return {
|
return {
|
||||||
label: repositoryType.displayName,
|
label: repositoryType.displayName,
|
||||||
value: repositoryType.name
|
value: repositoryType.name,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -137,28 +123,28 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
const extensionProps = {
|
const extensionProps = {
|
||||||
repository: repo,
|
repository: repo,
|
||||||
setCreationContextEntry: setCreationContextEntry,
|
setCreationContextEntry: setCreationContextEntry,
|
||||||
indexResources: indexResourcesWithLinks
|
indexResources: indexResourcesWithLinks,
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NamespaceAndNameFields
|
<NamespaceAndNameFields
|
||||||
repository={repo}
|
repository={repo}
|
||||||
onChange={setRepo}
|
onChange={setRepo}
|
||||||
setValid={namespaceAndName => setValid({ ...valid, namespaceAndName })}
|
setValid={(namespaceAndName) => setValid({ ...valid, namespaceAndName })}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
<SpaceBetween>
|
<div className="columns">
|
||||||
<SelectWrapper>
|
<div className={classNames("column", "is-half")}>
|
||||||
<Select
|
<Select
|
||||||
label={t("repository.type")}
|
label={t("repository.type")}
|
||||||
onChange={type => setRepo({ ...repo, type })}
|
onChange={(type) => setRepo({ ...repo, type })}
|
||||||
value={repo ? repo.type : ""}
|
value={repo ? repo.type : ""}
|
||||||
options={createSelectOptions(repositoryTypes)}
|
options={createSelectOptions(repositoryTypes)}
|
||||||
helpText={t("help.typeHelpText")}
|
helpText={t("help.typeHelpText")}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
/>
|
/>
|
||||||
</SelectWrapper>
|
</div>
|
||||||
<CheckboxWrapper>
|
<div className={classNames("column", "is-half", "is-align-self-flex-end")}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={t("repositoryForm.initializeRepository")}
|
label={t("repositoryForm.initializeRepository")}
|
||||||
checked={initRepository}
|
checked={initRepository}
|
||||||
@@ -169,8 +155,8 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
{initRepository && (
|
{initRepository && (
|
||||||
<ExtensionPoint name="repos.create.initialize" props={extensionProps} renderAll={true} />
|
<ExtensionPoint name="repos.create.initialize" props={extensionProps} renderAll={true} />
|
||||||
)}
|
)}
|
||||||
</CheckboxWrapper>
|
</div>
|
||||||
</SpaceBetween>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -199,7 +185,7 @@ const RepositoryForm: FC<Props> = ({
|
|||||||
repository={repo}
|
repository={repo}
|
||||||
onChange={setRepo}
|
onChange={setRepo}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
setValid={contact => setValid({ ...valid, contact })}
|
setValid={(contact) => setValid({ ...valid, contact })}
|
||||||
/>
|
/>
|
||||||
{submitButton()}
|
{submitButton()}
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -21,22 +21,12 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import styled from "styled-components";
|
|
||||||
import { Button, ButtonAddons, Icon, Level, urls } from "@scm-manager/ui-components";
|
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
const MarginIcon = styled(Icon)`
|
import styled from "styled-components";
|
||||||
padding-right: 0.5rem;
|
import { Button, ButtonAddons, Icon, Level, urls } from "@scm-manager/ui-components";
|
||||||
`;
|
|
||||||
|
|
||||||
const SmallButton = styled(Button)`
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 600;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TopLevel = styled(Level)`
|
const TopLevel = styled(Level)`
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
@@ -62,10 +52,14 @@ const RepositoryFormButton: FC<RepositoryForm> = ({ path, icon, label }) => {
|
|||||||
const [t] = useTranslation(["repos", "plugins"]);
|
const [t] = useTranslation(["repos", "plugins"]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SmallButton color={isSelected ? "link is-selected" : undefined} link={!isSelected ? href : undefined}>
|
<Button
|
||||||
<MarginIcon name={icon} color={isSelected ? "white" : "default"} />
|
className="is-size-6"
|
||||||
<p className="is-hidden-mobile is-hidden-tablet-only">{t(`plugins:${label}`, label)}</p>
|
color={isSelected ? "link is-selected" : undefined}
|
||||||
</SmallButton>
|
link={!isSelected ? href : undefined}
|
||||||
|
>
|
||||||
|
<Icon className="pr-2" name={icon} color={isSelected ? "white" : "default"} />
|
||||||
|
<p className={classNames("is-hidden-mobile", "is-hidden-tablet-only")}>{t(`plugins:${label}`, label)}</p>
|
||||||
|
</Button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ const RepositoryGroupEntry: FC<Props> = ({ group }) => {
|
|||||||
|
|
||||||
const settingsLink = group.namespace?._links?.permissions && (
|
const settingsLink = group.namespace?._links?.permissions && (
|
||||||
<Link to={`/namespace/${group.name}/settings`}>
|
<Link to={`/namespace/${group.name}/settings`}>
|
||||||
<Icon color="is-link" name="cog" title={t("repositoryOverview.settings.tooltip")} className={"is-size-6 ml-2"} />
|
<Icon color="is-link" name="cog" title={t("repositoryOverview.settings.tooltip")} className="is-size-6 ml-2" />
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
const namespaceHeader = (
|
const namespaceHeader = (
|
||||||
<>
|
<>
|
||||||
<Link to={`/repos/${group.name}/`} className={"has-text-dark"}>
|
<Link to={`/repos/${group.name}/`} className="has-text-dark">
|
||||||
{group.name}
|
{group.name}
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
{settingsLink}
|
{settingsLink}
|
||||||
|
|||||||
@@ -31,18 +31,17 @@ import {
|
|||||||
InputField,
|
InputField,
|
||||||
Level,
|
Level,
|
||||||
Notification,
|
Notification,
|
||||||
Subtitle
|
Subtitle,
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ExportInfo, Link, Repository } from "@scm-manager/ui-types";
|
import { ExportInfo, Link, Repository } from "@scm-manager/ui-types";
|
||||||
import { useExportInfo, useExportRepository } from "@scm-manager/ui-api";
|
import { useExportInfo, useExportRepository } from "@scm-manager/ui-api";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
const InfoBox = styled.div`
|
const InfoBox = styled.div`
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
background-color: #ccecf9;
|
background-color: #ccecf9;
|
||||||
margin: 1rem 0;
|
|
||||||
padding: 1rem;
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
border-left: 0.2rem solid;
|
border-left: 0.2rem solid;
|
||||||
border-color: #33b2e8;
|
border-color: #33b2e8;
|
||||||
@@ -60,7 +59,7 @@ const ExportInterruptedNotification = () => {
|
|||||||
const ExportInfoBox: FC<{ exportInfo: ExportInfo }> = ({ exportInfo }) => {
|
const ExportInfoBox: FC<{ exportInfo: ExportInfo }> = ({ exportInfo }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
return (
|
return (
|
||||||
<InfoBox>
|
<InfoBox className={classNames("my-4", "p-4")}>
|
||||||
<strong>{t("export.exportInfo.infoBoxTitle")}</strong>
|
<strong>{t("export.exportInfo.infoBoxTitle")}</strong>
|
||||||
<p>{t("export.exportInfo.exporter", { username: exportInfo.exporterName })}</p>
|
<p>{t("export.exportInfo.exporter", { username: exportInfo.exporterName })}</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -90,7 +89,7 @@ const ExportRepository: FC<Props> = ({ repository }) => {
|
|||||||
isLoading: isLoadingExport,
|
isLoading: isLoadingExport,
|
||||||
error: errorExport,
|
error: errorExport,
|
||||||
data: exportedInfo,
|
data: exportedInfo,
|
||||||
exportRepository
|
exportRepository,
|
||||||
} = useExportRepository();
|
} = useExportRepository();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -144,7 +143,7 @@ const ExportRepository: FC<Props> = ({ repository }) => {
|
|||||||
helpText={t("export.encrypt.helpText")}
|
helpText={t("export.encrypt.helpText")}
|
||||||
/>
|
/>
|
||||||
{encrypt && (
|
{encrypt && (
|
||||||
<div className="columns column is-half">
|
<div className={classNames("columns", "column", "is-half")}>
|
||||||
<InputField
|
<InputField
|
||||||
label={t("export.password.label")}
|
label={t("export.password.label")}
|
||||||
helpText={t("export.password.helpText")}
|
helpText={t("export.password.helpText")}
|
||||||
@@ -172,7 +171,7 @@ const ExportRepository: FC<Props> = ({ repository }) => {
|
|||||||
exportRepository(repository, {
|
exportRepository(repository, {
|
||||||
compressed,
|
compressed,
|
||||||
password: encrypt ? password : "",
|
password: encrypt ? password : "",
|
||||||
withMetadata: fullExport
|
withMetadata: fullExport,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
loading={isLoadingInfo || isLoadingExport}
|
loading={isLoadingInfo || isLoadingExport}
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ const HealthCheckWarning: FC<Props> = ({ repository }) => {
|
|||||||
return (
|
return (
|
||||||
<Notification type="danger">
|
<Notification type="danger">
|
||||||
{modal}
|
{modal}
|
||||||
<div className={"has-cursor-pointer"} onClick={() => setShowHealthCheck(true)}>
|
<div className="is-clickable" onClick={() => setShowHealthCheck(true)}>
|
||||||
<div>{t("repositoryForm.healthCheckWarning.title")}</div>
|
<div>{t("repositoryForm.healthCheckWarning.title")}</div>
|
||||||
<div className={"is-small"}>{t("repositoryForm.healthCheckWarning.subtitle")}</div>
|
<div className="is-small">{t("repositoryForm.healthCheckWarning.subtitle")}</div>
|
||||||
</div>
|
</div>
|
||||||
</Notification>
|
</Notification>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,14 +21,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import styled from "styled-components";
|
||||||
import { Repository } from "@scm-manager/ui-types";
|
import { Repository } from "@scm-manager/ui-types";
|
||||||
|
import { Subtitle } from "@scm-manager/ui-components";
|
||||||
import RenameRepository from "./RenameRepository";
|
import RenameRepository from "./RenameRepository";
|
||||||
import DeleteRepo from "./DeleteRepo";
|
import DeleteRepo from "./DeleteRepo";
|
||||||
import styled from "styled-components";
|
|
||||||
import { Subtitle } from "@scm-manager/ui-components";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import ArchiveRepo from "./ArchiveRepo";
|
import ArchiveRepo from "./ArchiveRepo";
|
||||||
import UnarchiveRepo from "./UnarchiveRepo";
|
import UnarchiveRepo from "./UnarchiveRepo";
|
||||||
|
|
||||||
@@ -37,7 +36,6 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const DangerZoneContainer = styled.div`
|
export const DangerZoneContainer = styled.div`
|
||||||
padding: 1.5rem 1rem;
|
|
||||||
border: 1px solid #ff6a88;
|
border: 1px solid #ff6a88;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|
||||||
@@ -83,7 +81,7 @@ const RepositoryDangerZone: FC<Props> = ({ repository }) => {
|
|||||||
<>
|
<>
|
||||||
<hr />
|
<hr />
|
||||||
<Subtitle subtitle={t("repositoryForm.dangerZone")} />
|
<Subtitle subtitle={t("repositoryForm.dangerZone")} />
|
||||||
<DangerZoneContainer>{dangerZone}</DangerZoneContainer>
|
<DangerZoneContainer className="px-4 py-5">{dangerZone}</DangerZoneContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Link as RouteLink, match, Redirect, Route, Switch, useRouteMatch } from "react-router-dom";
|
import { Link as RouteLink, Redirect, Route, Switch, useRouteMatch } from "react-router-dom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
|
import { binder, ExtensionPoint } from "@scm-manager/ui-extensions";
|
||||||
import { Changeset, Link } from "@scm-manager/ui-types";
|
import { Changeset, Link } from "@scm-manager/ui-types";
|
||||||
@@ -61,7 +61,6 @@ import { useIndexLinks, useRepository } from "@scm-manager/ui-api";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
const TagGroup = styled.span`
|
const TagGroup = styled.span`
|
||||||
font-weight: bold;
|
|
||||||
& > * {
|
& > * {
|
||||||
margin-right: 0.25rem;
|
margin-right: 0.25rem;
|
||||||
}
|
}
|
||||||
@@ -159,7 +158,7 @@ const RepositoryRoot = () => {
|
|||||||
|
|
||||||
const titleComponent = (
|
const titleComponent = (
|
||||||
<>
|
<>
|
||||||
<RouteLink to={`/repos/${repository.namespace}/`} className={"has-text-dark"}>
|
<RouteLink to={`/repos/${repository.namespace}/`} className="has-text-dark">
|
||||||
{repository.namespace}
|
{repository.namespace}
|
||||||
</RouteLink>
|
</RouteLink>
|
||||||
/{repository.name}
|
/{repository.name}
|
||||||
@@ -220,7 +219,7 @@ const RepositoryRoot = () => {
|
|||||||
afterTitle={
|
afterTitle={
|
||||||
<div className="is-flex">
|
<div className="is-flex">
|
||||||
<ExtensionPoint name={"repository.afterTitle"} props={{ repository }} />
|
<ExtensionPoint name={"repository.afterTitle"} props={{ repository }} />
|
||||||
<TagGroup>
|
<TagGroup className="has-text-weight-bold">
|
||||||
<RepositoryFlags repository={repository} tooltipLocation="bottom" />
|
<RepositoryFlags repository={repository} tooltipLocation="bottom" />
|
||||||
</TagGroup>
|
</TagGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -26,16 +26,11 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { Repository } from "@scm-manager/ui-types";
|
import { Repository } from "@scm-manager/ui-types";
|
||||||
import { Button, ErrorNotification, Level, Subtitle } from "@scm-manager/ui-components";
|
import { Button, ErrorNotification, Level, Subtitle } from "@scm-manager/ui-components";
|
||||||
import { useRunHealthCheck } from "@scm-manager/ui-api";
|
import { useRunHealthCheck } from "@scm-manager/ui-api";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
repository: Repository;
|
repository: Repository;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MarginTopButton = styled(Button)`
|
|
||||||
margin-top: 1rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const RunHealthCheck: FC<Props> = ({ repository }) => {
|
const RunHealthCheck: FC<Props> = ({ repository }) => {
|
||||||
const { isLoading, error, runHealthCheck } = useRunHealthCheck();
|
const { isLoading, error, runHealthCheck } = useRunHealthCheck();
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
@@ -56,7 +51,8 @@ const RunHealthCheck: FC<Props> = ({ repository }) => {
|
|||||||
</p>
|
</p>
|
||||||
<Level
|
<Level
|
||||||
right={
|
right={
|
||||||
<MarginTopButton
|
<Button
|
||||||
|
className="mt-4"
|
||||||
color="warning"
|
color="warning"
|
||||||
icon="heartbeat"
|
icon="heartbeat"
|
||||||
label={t("runHealthCheck.button")}
|
label={t("runHealthCheck.button")}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { File } from "@scm-manager/ui-types";
|
import { File } from "@scm-manager/ui-types";
|
||||||
import { ErrorNotification, Loading, MarkdownView } from "@scm-manager/ui-components";
|
import { ErrorNotification, Loading, MarkdownView } from "@scm-manager/ui-components";
|
||||||
import styled from "styled-components";
|
|
||||||
import replaceBranchWithRevision from "../../ReplaceBranchWithRevision";
|
import replaceBranchWithRevision from "../../ReplaceBranchWithRevision";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { useFileContent } from "@scm-manager/ui-api";
|
import { useFileContent } from "@scm-manager/ui-api";
|
||||||
@@ -34,10 +33,6 @@ type Props = {
|
|||||||
basePath: string;
|
basePath: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MarkdownContent = styled.div`
|
|
||||||
padding: 0.5rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const MarkdownViewer: FC<Props> = ({ file, basePath }) => {
|
const MarkdownViewer: FC<Props> = ({ file, basePath }) => {
|
||||||
const { isLoading, error, data: content } = useFileContent(file);
|
const { isLoading, error, data: content } = useFileContent(file);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -53,9 +48,9 @@ const MarkdownViewer: FC<Props> = ({ file, basePath }) => {
|
|||||||
const permalink = replaceBranchWithRevision(location.pathname, file.revision);
|
const permalink = replaceBranchWithRevision(location.pathname, file.revision);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MarkdownContent>
|
<div className="p-2">
|
||||||
<MarkdownView content={content} basePath={basePath} permalink={permalink} enableAnchorHeadings={true} />
|
<MarkdownView content={content} basePath={basePath} permalink={permalink} enableAnchorHeadings={true} />
|
||||||
</MarkdownContent>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,13 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, {FC, useState} from "react";
|
import React, { FC, useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import MarkdownViewer from "./MarkdownViewer";
|
import MarkdownViewer from "./MarkdownViewer";
|
||||||
import SourcecodeViewer from "./SourcecodeViewer";
|
import SourcecodeViewer from "./SourcecodeViewer";
|
||||||
import {File} from "@scm-manager/ui-types";
|
import { File } from "@scm-manager/ui-types";
|
||||||
import {Button} from "@scm-manager/ui-components";
|
import { Button } from "@scm-manager/ui-components";
|
||||||
import {useTranslation} from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const ToggleButton = styled(Button)`
|
const ToggleButton = styled(Button)`
|
||||||
max-width: 1rem;
|
max-width: 1rem;
|
||||||
@@ -37,17 +37,13 @@ const ToggleButton = styled(Button)`
|
|||||||
z-index: 30;
|
z-index: 30;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Container = styled.div`
|
|
||||||
position: relative;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
file: File;
|
file: File;
|
||||||
basePath: string;
|
basePath: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SwitchableMarkdownViewer: FC<Props> = ({file, basePath}) => {
|
const SwitchableMarkdownViewer: FC<Props> = ({ file, basePath }) => {
|
||||||
const {t} = useTranslation("repos");
|
const { t } = useTranslation("repos");
|
||||||
const [renderMarkdown, setRenderMarkdown] = useState(true);
|
const [renderMarkdown, setRenderMarkdown] = useState(true);
|
||||||
|
|
||||||
const toggleMarkdown = () => {
|
const toggleMarkdown = () => {
|
||||||
@@ -55,7 +51,7 @@ const SwitchableMarkdownViewer: FC<Props> = ({file, basePath}) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<div className="is-relative">
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
color={renderMarkdown ? "link" : ""}
|
color={renderMarkdown ? "link" : ""}
|
||||||
action={toggleMarkdown}
|
action={toggleMarkdown}
|
||||||
@@ -65,11 +61,14 @@ const SwitchableMarkdownViewer: FC<Props> = ({file, basePath}) => {
|
|||||||
: t("sources.content.toggleButton.showMarkdown")
|
: t("sources.content.toggleButton.showMarkdown")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i className="fab fa-markdown"/>
|
<i className="fab fa-markdown" />
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
{renderMarkdown ? <MarkdownViewer file={file} basePath={basePath}/> :
|
{renderMarkdown ? (
|
||||||
<SourcecodeViewer file={file} language={"MARKDOWN"}/>}
|
<MarkdownViewer file={file} basePath={basePath} />
|
||||||
</Container>
|
) : (
|
||||||
|
<SourcecodeViewer file={file} language={"MARKDOWN"} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,14 +49,6 @@ const HeaderWrapper = styled.div`
|
|||||||
padding: 0.5em 0.75em;
|
padding: 0.5em 0.75em;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const LighterGreyBackgroundPanelBlock = styled.div`
|
|
||||||
background-color: #fbfbfb;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LighterGreyBackgroundTable = styled.table`
|
|
||||||
background-color: #fbfbfb;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BorderBottom = styled.div`
|
const BorderBottom = styled.div`
|
||||||
border-bottom: solid 1px #dbdbdb;
|
border-bottom: solid 1px #dbdbdb;
|
||||||
`;
|
`;
|
||||||
@@ -65,10 +57,6 @@ const FullWidthTitleHeader = styled.div`
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AlignRight = styled.div`
|
|
||||||
margin-left: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BorderLessDiv = styled.div`
|
const BorderLessDiv = styled.div`
|
||||||
margin: -1.25rem;
|
margin: -1.25rem;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -116,13 +104,13 @@ const Content: FC<Props> = ({ file, repository, revision, breadcrumb, error }) =
|
|||||||
<HeaderWrapper>
|
<HeaderWrapper>
|
||||||
<div className={classNames("level", "is-flex-wrap-wrap")}>
|
<div className={classNames("level", "is-flex-wrap-wrap")}>
|
||||||
<FullWidthTitleHeader
|
<FullWidthTitleHeader
|
||||||
className={classNames("level-left", "is-flex", "has-cursor-pointer", "is-word-break", "mr-2")}
|
className={classNames("level-left", "is-flex", "is-clickable", "is-word-break", "mr-2")}
|
||||||
onClick={toggleCollapse}
|
onClick={toggleCollapse}
|
||||||
>
|
>
|
||||||
<Icon className={classNames("is-inline", "mr-2")} name={`${icon} fa-fw`} color="inherit" />
|
<Icon className={classNames("is-inline", "mr-2")} name={`${icon} fa-fw`} color="inherit" />
|
||||||
{file.name}
|
{file.name}
|
||||||
</FullWidthTitleHeader>
|
</FullWidthTitleHeader>
|
||||||
<AlignRight className={classNames("level-right", "buttons")}>
|
<div className={classNames("level-right", "buttons", "ml-auto")}>
|
||||||
{selector}
|
{selector}
|
||||||
<OpenInFullscreenButton
|
<OpenInFullscreenButton
|
||||||
modalTitle={file?.name}
|
modalTitle={file?.name}
|
||||||
@@ -139,7 +127,7 @@ const Content: FC<Props> = ({ file, repository, revision, breadcrumb, error }) =
|
|||||||
}}
|
}}
|
||||||
renderAll={true}
|
renderAll={true}
|
||||||
/>
|
/>
|
||||||
</AlignRight>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</HeaderWrapper>
|
</HeaderWrapper>
|
||||||
);
|
);
|
||||||
@@ -163,8 +151,8 @@ const Content: FC<Props> = ({ file, repository, revision, breadcrumb, error }) =
|
|||||||
if (!collapsed) {
|
if (!collapsed) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LighterGreyBackgroundPanelBlock className="panel-block">
|
<div className="panel-block has-background-white-bis">
|
||||||
<LighterGreyBackgroundTable className="table">
|
<table className="table has-background-white-bis">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{t("sources.content.path")}</td>
|
<td>{t("sources.content.path")}</td>
|
||||||
@@ -198,8 +186,8 @@ const Content: FC<Props> = ({ file, repository, revision, breadcrumb, error }) =
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</tbody>
|
</tbody>
|
||||||
</LighterGreyBackgroundTable>
|
</table>
|
||||||
</LighterGreyBackgroundPanelBlock>
|
</div>
|
||||||
<BorderBottom />
|
<BorderBottom />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,12 +21,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
import { Repository, Tag } from "@scm-manager/ui-types";
|
import { Repository, Tag } from "@scm-manager/ui-types";
|
||||||
import { DateFromNow, SignatureIcon } from "@scm-manager/ui-components";
|
import { DateFromNow, SignatureIcon } from "@scm-manager/ui-components";
|
||||||
import styled from "styled-components";
|
|
||||||
import TagButtonGroup from "./TagButtonGroup";
|
import TagButtonGroup from "./TagButtonGroup";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -34,37 +33,22 @@ type Props = {
|
|||||||
tag: Tag;
|
tag: Tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FlexRow = styled.div`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Created = styled.div`
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Label = styled.strong`
|
|
||||||
margin-right: 0.3rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Date = styled(DateFromNow)`
|
|
||||||
font-size: 0.8rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TagDetail: FC<Props> = ({ tag, repository }) => {
|
const TagDetail: FC<Props> = ({ tag, repository }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="media">
|
<div className="media">
|
||||||
<FlexRow className="media-content">
|
<div className={classNames("media-content", "is-flex", "is-flex-wrap-wrap", "is-align-items-center")}>
|
||||||
<Label className="subtitle has-text-weight-bold has-text-black">{t("tag.name") + ": "} </Label> <span className="subtitle">{tag.name}</span>
|
<strong className={classNames("subtitle", "has-text-weight-bold", "has-text-black", "mr-1")}>
|
||||||
|
{t("tag.name") + ": "}{" "}
|
||||||
|
</strong>{" "}
|
||||||
|
<span className="subtitle">{tag.name}</span>
|
||||||
<SignatureIcon signatures={tag.signatures} className="ml-2 mb-5" />
|
<SignatureIcon signatures={tag.signatures} className="ml-2 mb-5" />
|
||||||
<Created className="is-ellipsis-overflow mb-5">
|
<div className={classNames("is-ellipsis-overflow", "mb-5", "ml-2", "is-size-7")}>
|
||||||
{t("tags.overview.created")} <Date date={tag.date} className="has-text-grey" />
|
{t("tags.overview.created")}{" "}
|
||||||
</Created>
|
<DateFromNow className={classNames("has-text-grey", "is-size-7")} date={tag.date} />
|
||||||
</FlexRow>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="media-right">
|
<div className="media-right">
|
||||||
<TagButtonGroup repository={repository} tag={tag} />
|
<TagButtonGroup repository={repository} tag={tag} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,12 +21,11 @@
|
|||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
import { Tag, Link } from "@scm-manager/ui-types";
|
import { Tag, Link } from "@scm-manager/ui-types";
|
||||||
import styled from "styled-components";
|
|
||||||
import { DateFromNow, Icon } from "@scm-manager/ui-components";
|
import { DateFromNow, Icon } from "@scm-manager/ui-components";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -36,11 +35,6 @@ type Props = {
|
|||||||
// deleting: boolean;
|
// deleting: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Created = styled.span`
|
|
||||||
margin-left: 1rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const TagRow: FC<Props> = ({ tag, baseUrl, onDelete }) => {
|
const TagRow: FC<Props> = ({ tag, baseUrl, onDelete }) => {
|
||||||
const [t] = useTranslation("repos");
|
const [t] = useTranslation("repos");
|
||||||
|
|
||||||
@@ -61,9 +55,9 @@ const TagRow: FC<Props> = ({ tag, baseUrl, onDelete }) => {
|
|||||||
<td>
|
<td>
|
||||||
<RouterLink to={to} title={tag.name}>
|
<RouterLink to={to} title={tag.name}>
|
||||||
{tag.name}
|
{tag.name}
|
||||||
<Created className="has-text-grey is-ellipsis-overflow">
|
<span className={classNames("has-text-grey", "is-ellipsis-overflow", "ml-2", "is-size-7")}>
|
||||||
{t("tags.overview.created")} <DateFromNow date={tag.date} />
|
{t("tags.overview.created")} <DateFromNow date={tag.date} />
|
||||||
</Created>
|
</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
</td>
|
</td>
|
||||||
<td className="is-darker">{deleteButton}</td>
|
<td className="is-darker">{deleteButton}</td>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ type CountProps = {
|
|||||||
|
|
||||||
const Count: FC<CountProps> = ({ isLoading, isSelected, count }) => {
|
const Count: FC<CountProps> = ({ isLoading, isSelected, count }) => {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <span className={"small-loading-spinner"} />;
|
return <span className="small-loading-spinner" />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Tag rounded={true} color={isSelected ? "info" : "light"}>
|
<Tag rounded={true} color={isSelected ? "info" : "light"}>
|
||||||
|
|||||||
@@ -22,24 +22,18 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
import React, { FC, useEffect, useState } from "react";
|
import React, { FC, useEffect, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { User } from "@scm-manager/ui-types";
|
||||||
|
import { useConvertToExternal, useConvertToInternal } from "@scm-manager/ui-api";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ErrorNotification,
|
ErrorNotification,
|
||||||
Level,
|
Level,
|
||||||
Modal,
|
Modal,
|
||||||
PasswordConfirmation,
|
PasswordConfirmation,
|
||||||
SubmitButton
|
SubmitButton,
|
||||||
} from "@scm-manager/ui-components";
|
} from "@scm-manager/ui-components";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { User } from "@scm-manager/ui-types";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import { useConvertToExternal, useConvertToInternal } from "@scm-manager/ui-api";
|
|
||||||
|
|
||||||
const ExternalDescription = styled.div`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-weight: 400;
|
|
||||||
`;
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: User;
|
user: User;
|
||||||
@@ -53,12 +47,12 @@ const UserConverter: FC<Props> = ({ user }) => {
|
|||||||
const {
|
const {
|
||||||
isLoading: isConvertingToInternal,
|
isLoading: isConvertingToInternal,
|
||||||
error: convertingToInternalError,
|
error: convertingToInternalError,
|
||||||
convertToInternal
|
convertToInternal,
|
||||||
} = useConvertToInternal();
|
} = useConvertToInternal();
|
||||||
const {
|
const {
|
||||||
isLoading: isConvertingToExternal,
|
isLoading: isConvertingToExternal,
|
||||||
error: convertingToExternalError,
|
error: convertingToExternalError,
|
||||||
convertToExternal
|
convertToExternal,
|
||||||
} = useConvertToExternal();
|
} = useConvertToExternal();
|
||||||
const error = convertingToExternalError || convertingToInternalError || undefined;
|
const error = convertingToExternalError || convertingToInternalError || undefined;
|
||||||
const isLoading = isConvertingToExternal || isConvertingToInternal;
|
const isLoading = isConvertingToExternal || isConvertingToInternal;
|
||||||
@@ -135,7 +129,9 @@ const UserConverter: FC<Props> = ({ user }) => {
|
|||||||
{showPasswordModal && passwordModal}
|
{showPasswordModal && passwordModal}
|
||||||
{error && <ErrorNotification error={error} />}
|
{error && <ErrorNotification error={error} />}
|
||||||
<div className="columns is-multiline">
|
<div className="columns is-multiline">
|
||||||
<ExternalDescription className="column is-half">{getUserExternalDescription()}</ExternalDescription>
|
<div className={classNames("column", "is-half", "is-flex", "is-align-items-center")}>
|
||||||
|
{getUserExternalDescription()}
|
||||||
|
</div>
|
||||||
<div className="column is-half">
|
<div className="column is-half">
|
||||||
<Level right={getConvertButton()} />
|
<Level right={getConvertButton()} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -56,19 +56,19 @@ const ApiKeyCreatedModal: FC<Props> = ({ addedKey, close }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const newPassphraseModalContent = (
|
const newPassphraseModalContent = (
|
||||||
<div className={"media-content"}>
|
<div className="media-content">
|
||||||
<p>{t("apiKey.modal.text1")}</p>
|
<p>{t("apiKey.modal.text1")}</p>
|
||||||
<p>
|
<p>
|
||||||
<b>{t("apiKey.modal.text2")}</b>
|
<b>{t("apiKey.modal.text2")}</b>
|
||||||
</p>
|
</p>
|
||||||
<hr />
|
<hr />
|
||||||
<div className={"columns"}>
|
<div className="columns">
|
||||||
<div className={"column is-11"}>
|
<div className="column is-11">
|
||||||
<KeyArea wrap={"soft"} ref={keyRef} className={"input"} value={addedKey.token} />
|
<KeyArea wrap={"soft"} ref={keyRef} className="input" value={addedKey.token} />
|
||||||
</div>
|
</div>
|
||||||
<NoLeftMargin className={"column is-1"}>
|
<NoLeftMargin className="column is-1">
|
||||||
<Icon
|
<Icon
|
||||||
className={"is-hidden-mobile fa-2x"}
|
className="is-hidden-mobile fa-2x"
|
||||||
name={copied ? "clipboard-check" : "clipboard"}
|
name={copied ? "clipboard-check" : "clipboard"}
|
||||||
title={t("apiKey.modal.clipboard")}
|
title={t("apiKey.modal.clipboard")}
|
||||||
onClick={copy}
|
onClick={copy}
|
||||||
|
|||||||
Reference in New Issue
Block a user