diff --git a/scm-ui/ui-components/src/Annotate.tsx b/scm-ui/ui-components/src/Annotate.tsx deleted file mode 100644 index 3cf25630dd..0000000000 --- a/scm-ui/ui-components/src/Annotate.tsx +++ /dev/null @@ -1,428 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2020-present Cloudogu GmbH and Contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import React, { FC, useRef, useState, MouseEvent, useLayoutEffect, useReducer, Dispatch } from "react"; -import { Person, Repository } from "@scm-manager/ui-types"; - -// @ts-ignore -import { LightAsync as ReactSyntaxHighlighter, createElement } from "react-syntax-highlighter"; -import { arduinoLight } from "react-syntax-highlighter/dist/cjs/styles/hljs"; -import styled from "styled-components"; -import DateShort from "./DateShort"; -import { SingleContributor } from "./repos/changesets"; -import DateFromNow from "./DateFromNow"; -import { Link } from "react-router-dom"; -import { DateInput } from "./dates"; -import { AvatarImage } from "./avatar"; - -// TODO move types to ui-types - -export type AnnotatedSource = { - lines: AnnotatedLine[]; - language: string; -}; - -export type AnnotatedLine = { - author: Person; - code: string; - description: string; - lineNumber: number; - revision: string; - when: Date; -}; - -type Props = { - source: AnnotatedSource; - repository: Repository; - baseDate?: DateInput; -}; - -const LineElement = styled.div` - display: inline-block; - margin: 0; - padding: 0; - height: 100%; - vertical-align: top; -`; - -const Author = styled(LineElement)` - width: 8em; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -`; - -const When = styled(LineElement)` - display: inline-block; - - width: 6.5em; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - margin: 0 0.5em; -`; - -const LineNumber = styled(LineElement)` - width: 3em; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - - border-left: 1px solid lightgrey; - border-right: 1px solid lightgrey; - - text-align: right; - - padding: 0 0.5em; -`; - -const PopoverContainer = styled.div` - position: absolute; - left: 2.25em; - z-index: 100; - width: 30em; - display: block; - - &:before { - position: absolute; - content: ""; - border-style: solid; - pointer-events: none; - height: 0; - width: 0; - top: 100%; - left: 5.5em; - border-color: transparent; - border-bottom-color: white; - border-left-color: white; - border-width: 0.4rem; - margin-left: -0.4rem; - margin-top: -0.4rem; - -webkit-transform-origin: center; - transform-origin: center; - box-shadow: -1px 1px 2px rgba(10, 10, 10, 0.2); - transform: rotate(-45deg); - } -`; - -const Line = styled.div` - margin: 0; - padding: 0; - height: 1.5em; - vertical-align: top; -`; - -const PreTag = styled.pre` - position: relative; -`; - -const SmallHr = styled.hr` - margin: 0.5em 0; -`; - -const PopoverHeading = styled.div` - height: 1.5em; -`; - -const PopoverDescription = styled.p` - margin-top: 0.5em; -`; - -const shortRevision = (revision: string) => { - if (revision.length > 7) { - return revision.substring(0, 7); - } - return revision; -}; - -type LineProps = { - annotation: AnnotatedLine; - showAnnotation: boolean; - nr: number; - dispatch: Dispatch; -}; - -type PopoverProps = { - annotation: AnnotatedLine; - offsetTop?: number; - repository: Repository; - baseDate?: DateInput; - dispatch: Dispatch; -}; - -const Popover: FC = ({ annotation, offsetTop, repository, baseDate, dispatch }) => { - const [height, setHeight] = useState(125); - const ref = useRef(null); - useLayoutEffect(() => { - if (ref.current) { - setHeight(ref.current.clientHeight); - } - }, [ref]); - - const onMouseEnter = (e: MouseEvent) => { - dispatch({ - type: "enter-popover" - }); - }; - - const OnMouseLeave = (e: MouseEvent) => { - dispatch({ - type: "leave-popover" - }); - }; - - const top = (offsetTop || 0) - height - 5; - return ( - - - - - - - - - -

- Changeset{" "} - - {shortRevision(annotation.revision)} - -

- {annotation.description} -
- ); -}; - -const Metadata = styled(LineElement)` - cursor: help; -`; - -const EmptyMetadata = styled(LineElement)` - width: 16.7em; -`; - -const dispatchDeferred = (dispatch: Dispatch, action: Action) => { - setTimeout(() => dispatch(action), 250); -}; - -const AuthorImage = styled(AvatarImage)` - width: 1em; - height: 1em; - margin-right: 0.2em; -`; - -const AnnotateLine: FC = ({ annotation, showAnnotation, dispatch, nr, children }) => { - const link = useRef(null); - - const onMouseEnter = (e: MouseEvent) => { - if (showAnnotation) { - dispatchDeferred(dispatch, { - annotation, - line: nr, - offset: link.current!.offsetTop, - type: "enter-line" - }); - } - }; - - const OnMouseLeave = (e: MouseEvent) => { - if (showAnnotation) { - dispatchDeferred(dispatch, { - line: nr, - type: "leave-line" - }); - } - }; - - if (!showAnnotation) { - return ( - - - {nr} {children} - - ); - } - - return ( - - - - - {annotation.author.name} - {" "} - - - {" "} - - {nr} {children} - - ); -}; - -type State = { - annotation?: AnnotatedLine; - offset?: number; - line?: number; - onPopover: boolean; - onLine: boolean; -}; - -type EnterLine = { - annotation: AnnotatedLine; - offset: number; - line: number; - type: "enter-line"; -}; - -type LeaveLine = { - line: number; - type: "leave-line"; -}; - -type EnterPopover = { - type: "enter-popover"; -}; - -type LeavePopover = { - type: "leave-popover"; -}; - -const initialState = { - onPopover: false, - onLine: false -}; - -type Action = EnterLine | LeaveLine | EnterPopover | LeavePopover; - -const reducer = (state: State, action: Action): State => { - switch (action.type) { - case "enter-line": { - if (state.onPopover) { - return state; - } - return { - annotation: action.annotation, - offset: action.offset, - line: action.line, - onLine: true, - onPopover: false - }; - } - case "leave-line": { - if (state.onPopover) { - return { - ...state, - onLine: false - }; - } - return initialState; - } - case "enter-popover": { - return { - ...state, - onPopover: true - }; - } - case "leave-popover": { - if (state.onLine) { - return { - ...state, - onPopover: false - }; - } - return initialState; - } - } -}; - -const Annotate: FC = ({ source, repository, baseDate }) => { - const [state, dispatch] = useReducer(reducer, initialState); - - const defaultRenderer = ({ rows, stylesheet, useInlineStyles }: any) => { - let lastRevision = ""; - return rows.map((node: any, i: number) => { - const line = createElement({ - node, - stylesheet, - useInlineStyles, - key: `code-segement${i}` - }); - - if (i + 1 < rows.length) { - const annotation = source.lines[i]; - const newAnnotation = annotation.revision !== lastRevision; - lastRevision = annotation.revision; - return ( - - {line} - - ); - } - - return line; - }); - }; - - let popover = null; - if ((state.onPopover || state.onLine) && state.annotation) { - popover = ( - - ); - } - - const code = source.lines.reduce((content, line) => { - content += line.code + "\n"; - return content; - }, ""); - - return ( -
- {popover} - - {code} - -
- ); -}; - -export default Annotate; diff --git a/scm-ui/ui-components/src/index.ts b/scm-ui/ui-components/src/index.ts index 07f4bdf5f3..19ba35a1f4 100644 --- a/scm-ui/ui-components/src/index.ts +++ b/scm-ui/ui-components/src/index.ts @@ -43,7 +43,6 @@ import { export { validation, urls, repositories }; -export { default as Annotate } from "./Annotate"; export { default as DateFromNow } from "./DateFromNow"; export { default as DateShort } from "./DateShort"; export { default as ErrorNotification } from "./ErrorNotification"; diff --git a/scm-ui/ui-components/src/Annotate.stories.tsx b/scm-ui/ui-components/src/repos/annotate/Annotate.stories.tsx similarity index 95% rename from scm-ui/ui-components/src/Annotate.stories.tsx rename to scm-ui/ui-components/src/repos/annotate/Annotate.stories.tsx index 64afc0cca9..41345b2744 100644 --- a/scm-ui/ui-components/src/Annotate.stories.tsx +++ b/scm-ui/ui-components/src/repos/annotate/Annotate.stories.tsx @@ -25,11 +25,12 @@ import { storiesOf } from "@storybook/react"; import React, { FC } from "react"; import styled from "styled-components"; -import Annotate, { AnnotatedSource } from "./Annotate"; +import Annotate from "./Annotate"; import { MemoryRouter } from "react-router-dom"; -import repository from "./__resources__/repository"; +import repository from "../../__resources__/repository"; import { Binder, BinderContext } from "@scm-manager/ui-extensions"; -import { Person } from "./avatar/Avatar"; +import { Person } from "../../avatar/Avatar"; +import { AnnotatedSource } from "@scm-manager/ui-types"; const Wrapper = styled.div` margin: 2rem; diff --git a/scm-ui/ui-components/src/repos/annotate/Annotate.tsx b/scm-ui/ui-components/src/repos/annotate/Annotate.tsx new file mode 100644 index 0000000000..b7a67a6d8d --- /dev/null +++ b/scm-ui/ui-components/src/repos/annotate/Annotate.tsx @@ -0,0 +1,157 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import React, { FC, useReducer } from "react"; +import { Repository, AnnotatedSource, AnnotatedLine } from "@scm-manager/ui-types"; + +// @ts-ignore +import { LightAsync as ReactSyntaxHighlighter, createElement } from "react-syntax-highlighter"; +import { arduinoLight } from "react-syntax-highlighter/dist/cjs/styles/hljs"; +import { DateInput } from "../../dates"; +import Popover from "./Popover"; +import AnnotateLine from "./AnnotateLine"; +import { Action } from "./actions"; + +type Props = { + source: AnnotatedSource; + repository: Repository; + baseDate?: DateInput; +}; + +type State = { + annotation?: AnnotatedLine; + offset?: number; + line?: number; + onPopover: boolean; + onLine: boolean; +}; + +const initialState = { + onPopover: false, + onLine: false +}; + +const reducer = (state: State, action: Action): State => { + switch (action.type) { + case "enter-line": { + if (state.onPopover) { + return state; + } + return { + annotation: action.annotation, + offset: action.offset, + line: action.line, + onLine: true, + onPopover: false + }; + } + case "leave-line": { + if (state.onPopover) { + return { + ...state, + onLine: false + }; + } + return initialState; + } + case "enter-popover": { + return { + ...state, + onPopover: true + }; + } + case "leave-popover": { + if (state.onLine) { + return { + ...state, + onPopover: false + }; + } + return initialState; + } + } +}; + +const Annotate: FC = ({ source, repository, baseDate }) => { + const [state, dispatch] = useReducer(reducer, initialState); + + const defaultRenderer = ({ rows, stylesheet, useInlineStyles }: any) => { + let lastRevision = ""; + return rows.map((node: React.ReactNode, i: number) => { + const line = createElement({ + node, + stylesheet, + useInlineStyles, + key: `code-segement${i}` + }); + + if (i + 1 < rows.length) { + const annotation = source.lines[i]; + const newAnnotation = annotation.revision !== lastRevision; + lastRevision = annotation.revision; + return ( + + {line} + + ); + } + + return line; + }); + }; + + let popover = null; + if ((state.onPopover || state.onLine) && state.annotation) { + popover = ( + + ); + } + + const code = source.lines.reduce((content, line) => { + content += line.code + "\n"; + return content; + }, ""); + + return ( +
+ {popover} + + {code} + +
+ ); +}; + +export default Annotate; diff --git a/scm-ui/ui-components/src/repos/annotate/AnnotateLine.tsx b/scm-ui/ui-components/src/repos/annotate/AnnotateLine.tsx new file mode 100644 index 0000000000..cb6b2ffb86 --- /dev/null +++ b/scm-ui/ui-components/src/repos/annotate/AnnotateLine.tsx @@ -0,0 +1,145 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +import React, { FC, Dispatch, useRef } from "react"; +import styled from "styled-components"; +import AuthorImage from "./AuthorImage"; +import DateShort from "../../DateShort"; +import { Action } from "./actions"; +import { AnnotatedLine } from "@scm-manager/ui-types"; + +const LineElement = styled.div` + display: inline-block; + margin: 0; + padding: 0; + height: 100%; + vertical-align: top; +`; + +const Author = styled(LineElement)` + width: 8em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +`; + +const When = styled(LineElement)` + display: inline-block; + + width: 6.5em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + margin: 0 0.5em; +`; + +const LineNumber = styled(LineElement)` + width: 3em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + border-left: 1px solid lightgrey; + border-right: 1px solid lightgrey; + + text-align: right; + + padding: 0 0.5em; +`; + +const Line = styled.div` + margin: 0; + padding: 0; + height: 1.5em; + vertical-align: top; +`; + +const Metadata = styled(LineElement)` + cursor: help; +`; + +const EmptyMetadata = styled(LineElement)` + width: 16.7em; +`; + +const dispatchDeferred = (dispatch: Dispatch, action: Action) => { + setTimeout(() => dispatch(action), 250); +}; + +type Props = { + annotation: AnnotatedLine; + showAnnotation: boolean; + nr: number; + dispatch: Dispatch; +}; + +const AnnotateLine: FC = ({ annotation, showAnnotation, dispatch, nr, children }) => { + const link = useRef(null); + + const onMouseEnter = () => { + if (showAnnotation) { + dispatchDeferred(dispatch, { + annotation, + line: nr, + offset: link.current!.offsetTop, + type: "enter-line" + }); + } + }; + + const OnMouseLeave = () => { + if (showAnnotation) { + dispatchDeferred(dispatch, { + line: nr, + type: "leave-line" + }); + } + }; + + if (!showAnnotation) { + return ( + + + {nr} {children} + + ); + } + + return ( + + + + + {annotation.author.name} + {" "} + + + {" "} + + {nr} {children} + + ); +}; + +export default AnnotateLine; diff --git a/scm-ui/ui-components/src/repos/annotate/AuthorImage.tsx b/scm-ui/ui-components/src/repos/annotate/AuthorImage.tsx new file mode 100644 index 0000000000..3963ed51a5 --- /dev/null +++ b/scm-ui/ui-components/src/repos/annotate/AuthorImage.tsx @@ -0,0 +1,34 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { AvatarImage } from "../../avatar"; +import styled from "styled-components"; + +const AuthorImage = styled(AvatarImage)` + width: 1em; + height: 1em; + margin-right: 0.2em; +`; + +export default AuthorImage; diff --git a/scm-ui/ui-components/src/repos/annotate/Popover.tsx b/scm-ui/ui-components/src/repos/annotate/Popover.tsx new file mode 100644 index 0000000000..b4edb785cb --- /dev/null +++ b/scm-ui/ui-components/src/repos/annotate/Popover.tsx @@ -0,0 +1,140 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import React, { FC, useState, useRef, useLayoutEffect, Dispatch } from "react"; +import styled from "styled-components"; +import { Link } from "react-router-dom"; +import DateFromNow from "../../DateFromNow"; +import { SingleContributor } from "../changesets"; +import { DateInput } from "../../dates"; +import { Repository, AnnotatedLine } from "@scm-manager/ui-types"; +import AuthorImage from "./AuthorImage"; +import { Action } from "./actions"; + +const PopoverContainer = styled.div` + position: absolute; + left: 2.25em; + z-index: 100; + width: 30em; + display: block; + + &:before { + position: absolute; + content: ""; + border-style: solid; + pointer-events: none; + height: 0; + width: 0; + top: 100%; + left: 5.5em; + border-color: transparent; + border-bottom-color: white; + border-left-color: white; + border-width: 0.4rem; + margin-left: -0.4rem; + margin-top: -0.4rem; + -webkit-transform-origin: center; + transform-origin: center; + box-shadow: -1px 1px 2px rgba(10, 10, 10, 0.2); + transform: rotate(-45deg); + } +`; + +const SmallHr = styled.hr` + margin: 0.5em 0; +`; + +const PopoverHeading = styled.div` + height: 1.5em; +`; + +const PopoverDescription = styled.p` + margin-top: 0.5em; +`; + +const shortRevision = (revision: string) => { + if (revision.length > 7) { + return revision.substring(0, 7); + } + return revision; +}; + +type PopoverProps = { + annotation: AnnotatedLine; + offsetTop?: number; + repository: Repository; + baseDate?: DateInput; + dispatch: Dispatch; +}; + +const Popover: FC = ({ annotation, offsetTop, repository, baseDate, dispatch }) => { + const [height, setHeight] = useState(125); + const ref = useRef(null); + useLayoutEffect(() => { + if (ref.current) { + setHeight(ref.current.clientHeight); + } + }, [ref]); + + const onMouseEnter = () => { + dispatch({ + type: "enter-popover" + }); + }; + + const OnMouseLeave = () => { + dispatch({ + type: "leave-popover" + }); + }; + + const top = (offsetTop || 0) - height - 5; + return ( + + + + + + + + + +

+ Changeset{" "} + + {shortRevision(annotation.revision)} + +

+ {annotation.description} +
+ ); +}; + +export default Popover; diff --git a/scm-ui/ui-components/src/repos/annotate/actions.ts b/scm-ui/ui-components/src/repos/annotate/actions.ts new file mode 100644 index 0000000000..8ac1158b4f --- /dev/null +++ b/scm-ui/ui-components/src/repos/annotate/actions.ts @@ -0,0 +1,47 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { AnnotatedLine } from "@scm-manager/ui-types"; + +type EnterLine = { + annotation: AnnotatedLine; + offset: number; + line: number; + type: "enter-line"; +}; + +type LeaveLine = { + line: number; + type: "leave-line"; +}; + +type EnterPopover = { + type: "enter-popover"; +}; + +type LeavePopover = { + type: "leave-popover"; +}; + +export type Action = EnterLine | LeaveLine | EnterPopover | LeavePopover; diff --git a/scm-ui/ui-components/src/repos/annotate/index.ts b/scm-ui/ui-components/src/repos/annotate/index.ts new file mode 100644 index 0000000000..84534a9c60 --- /dev/null +++ b/scm-ui/ui-components/src/repos/annotate/index.ts @@ -0,0 +1,25 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +export { default as Annotate } from "./Annotate"; diff --git a/scm-ui/ui-components/src/repos/index.ts b/scm-ui/ui-components/src/repos/index.ts index 01f6c97daa..a3551ed6b5 100644 --- a/scm-ui/ui-components/src/repos/index.ts +++ b/scm-ui/ui-components/src/repos/index.ts @@ -39,6 +39,7 @@ import { export { diffs }; +export * from "./annotate"; export * from "./changesets"; export { default as Diff } from "./Diff"; diff --git a/scm-ui/ui-types/src/Annotate.ts b/scm-ui/ui-types/src/Annotate.ts new file mode 100644 index 0000000000..b1c09ba49b --- /dev/null +++ b/scm-ui/ui-types/src/Annotate.ts @@ -0,0 +1,39 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { Person } from "./Person"; + +export type AnnotatedSource = { + lines: AnnotatedLine[]; + language: string; +}; + +export type AnnotatedLine = { + author: Person; + code: string; + description: string; + lineNumber: number; + revision: string; + when: Date; +}; diff --git a/scm-ui/ui-types/src/Changesets.ts b/scm-ui/ui-types/src/Changesets.ts index 74adfd8a78..f182da296c 100644 --- a/scm-ui/ui-types/src/Changesets.ts +++ b/scm-ui/ui-types/src/Changesets.ts @@ -25,11 +25,7 @@ import { Collection, Links } from "./hal"; import { Tag } from "./Tags"; import { Branch } from "./Branches"; - -export type Person = { - name: string; - mail?: string; -}; +import { Person } from "./Person"; export type Changeset = Collection & { id: string; diff --git a/scm-ui/ui-types/src/Person.ts b/scm-ui/ui-types/src/Person.ts new file mode 100644 index 0000000000..6560407a68 --- /dev/null +++ b/scm-ui/ui-types/src/Person.ts @@ -0,0 +1,28 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +export type Person = { + name: string; + mail?: string; +}; diff --git a/scm-ui/ui-types/src/index.ts b/scm-ui/ui-types/src/index.ts index 4b7fdc694d..a0ce96dac9 100644 --- a/scm-ui/ui-types/src/index.ts +++ b/scm-ui/ui-types/src/index.ts @@ -34,7 +34,11 @@ export { RepositoryType, RepositoryTypeCollection } from "./RepositoryTypes"; export { Branch, BranchRequest } from "./Branches"; -export { Changeset, Person, Contributor, ParentChangeset } from "./Changesets"; +export { Person } from "./Person"; + +export { Changeset, Contributor, ParentChangeset } from "./Changesets"; + +export { AnnotatedSource, AnnotatedLine } from "./Annotate"; export { Tag } from "./Tags";