Skip to content

Commit 8e5d57e

Browse files
authored
Merge pull request #568 from devtron-labs/feat/template-detail
feat: template detail
2 parents 578907f + c88566e commit 8e5d57e

File tree

11 files changed

+167
-7
lines changed

11 files changed

+167
-7
lines changed

src/Common/Constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ export const URLS = {
8383
CONFIG_DRIFT: 'config-drift',
8484
RESOURCE_BROWSER: '/resource-browser',
8585
COMPARE_CLUSTERS: '/compare-clusters',
86+
APP_CONFIG: 'edit',
87+
GLOBAL_CONFIG: '/global-config',
8688
GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP,
8789
GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP_CREATE: `${GLOBAL_CONFIG_TEMPLATES_DEVTRON_APP}/create`,
8890
// NOTE: using appId since we are re-using AppConfig component

src/Common/Tooltip/Tooltip.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import TippyJS from '@tippyjs/react'
1919
import { TooltipProps } from './types'
2020
import ShortcutKeyComboTooltipContent from './ShortcutKeyComboTooltipContent'
2121
import './styles.scss'
22+
import { SUB_PIXEL_ERROR } from './constants'
2223

2324
const Tooltip = ({
2425
shortcutKeyCombo,
@@ -33,7 +34,9 @@ const Tooltip = ({
3334

3435
const handleMouseEnterEvent: React.MouseEventHandler = (event) => {
3536
const { currentTarget: node } = event
36-
const isTextOverflowing = node.scrollWidth > node.clientWidth || node.scrollHeight > node.clientHeight
37+
const isTextOverflowing =
38+
node.scrollWidth > node.clientWidth + SUB_PIXEL_ERROR ||
39+
node.scrollHeight > node.clientHeight + SUB_PIXEL_ERROR
3740
if (isTextOverflowing && !isTextTruncated) {
3841
setIsTextTruncated(true)
3942
} else if (!isTextOverflowing && isTextTruncated) {

src/Common/Tooltip/constants.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@
1717
export const TOOLTIP_CONTENTS = {
1818
INVALID_INPUT: 'Valid input is required for all mandatory fields.',
1919
}
20+
21+
export const SUB_PIXEL_ERROR = 1

src/Pages/Applications/DevtronApps/Details/AppConfigurations/types.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { ResourceKindType } from '@Shared/types'
1718
import { ReactNode, SyntheticEvent } from 'react'
1819

1920
export enum ConfigHeaderTabType {
@@ -54,3 +55,35 @@ export interface OverrideStrategyTippyContentProps {
5455
*/
5556
children?: ReactNode
5657
}
58+
59+
export interface AppConfigProps {
60+
appName: string
61+
resourceKind: Extract<ResourceKindType, ResourceKindType.devtronApplication | ResourceKindType.job>
62+
filteredEnvIds?: string
63+
isTemplateView?: boolean
64+
}
65+
66+
export enum GetTemplateAPIRouteType {
67+
GIT_MATERIAL = 'git-material',
68+
CI_BUILD_CONFIG = 'ci-build-config',
69+
STAGE_STATUS = 'stage-status',
70+
CD_DEPLOY_CONFIG = 'cd-deploy-config',
71+
CD_ENV_LIST = 'cd-env-list',
72+
CONFIG_DEPLOYMENT_TEMPLATE = 'config/deployment-template',
73+
CONFIG_CM = 'config/config-map',
74+
CONFIG_CS = 'config/secret',
75+
WORKFLOW_LIST = 'workflow/list',
76+
OVERVIEW = 'overview',
77+
README = 'readme',
78+
CD_PIPELINE_LIST = 'cd-pipeline/list',
79+
EXTERNAL_CI_LIST = 'external-ci/list',
80+
EXTERNAL_CI = 'external-ci',
81+
CI_PIPELINE = 'ci-pipeline',
82+
CD_PIPELINE = 'cd-pipeline',
83+
CONFIG_STRATEGY = 'config/strategy',
84+
}
85+
86+
export interface GetTemplateAPIRouteProps {
87+
type: GetTemplateAPIRouteType
88+
queryParams: { id: string | number } & Record<string, any>
89+
}

src/Shared/Components/GenericInfoCard/GenericInfoCard.component.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ const GenericInfoCard = ({
6666
</Tooltip>
6767
</div>
6868

69-
<p className="fw-4 fs-12 lh-16 cn-7 m-0 dc__truncate--clamp-3">{description}</p>
69+
{description && (
70+
<p className="fw-4 fs-12 lh-16 cn-7 m-0 dc__truncate--clamp-3">{description}</p>
71+
)}
7072
</div>
7173
</>
7274
)}

src/Shared/Components/GraphVisualizer/styles.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
// REACT FLOW
22
.graph-visualizer {
33
.react-flow {
4+
--xy-attribution-background-color: var(--bg-tertiary);
45
--xy-edge-stroke-default: var(--N200);
56
--xy-background-color-default: var(--bg-secondary);
7+
8+
&__attribution {
9+
a {
10+
color: var(--N700);
11+
}
12+
}
613
}
714
}
815

src/Shared/Components/ReactSelect/constants.ts renamed to src/Shared/Components/ReactSelect/constants.tsx

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
* limitations under the License.
1515
*/
1616

17-
export const CommonGroupedDropdownStyles = {
17+
import { components, DropdownIndicatorProps, StylesConfig } from 'react-select'
18+
import { ReactComponent as DropDownIcon } from '@Icons/ic-chevron-down.svg'
19+
20+
export const CommonGroupedDropdownStyles: StylesConfig = {
1821
container: (base, state) => ({
1922
...base,
2023
...(state.isDisabled && {
@@ -109,3 +112,85 @@ export const CommonGroupedDropdownStyles = {
109112
backgroundColor: 'var(--bg-primary)',
110113
}),
111114
}
115+
116+
export const APP_SELECTOR_STYLES: StylesConfig = {
117+
control: (base, state) => ({
118+
...base,
119+
border: state.menuIsOpen ? '1px solid var(--B500)' : 'unset',
120+
boxShadow: 'none',
121+
color: 'var(--N900)',
122+
minHeight: '32px',
123+
minWidth: state.menuIsOpen ? '300px' : 'unset',
124+
justifyContent: state.menuIsOpen ? 'space-between' : 'flex-start',
125+
cursor: 'pointer',
126+
backgroundColor: 'var(--bg-primary)',
127+
}),
128+
valueContainer: (base, state) => ({
129+
...base,
130+
display: 'flex',
131+
flexDirection: 'row-reverse',
132+
flexBasis: '0px',
133+
justifyContent: 'flex-end',
134+
padding: state.selectProps.menuIsOpen ? '0 0 0 4px' : '0',
135+
color: state.selectProps.menuIsOpen ? 'var(--N500)' : 'var(--N900)',
136+
height: '30px',
137+
}),
138+
singleValue: (base, state) => ({
139+
...base,
140+
color: state.selectProps.menuIsOpen ? 'var(--N500)' : 'var(--N900)',
141+
}),
142+
menu: (base) => ({
143+
...base,
144+
backgroundColor: 'var(--bg-primary)',
145+
minWidth: '300px',
146+
fontSize: '14px',
147+
fontWeight: 'normal',
148+
}),
149+
menuList: (base) => ({
150+
...base,
151+
padding: '8px',
152+
}),
153+
option: (base, state) => ({
154+
...base,
155+
borderRadius: '4px',
156+
color: state.isSelected ? 'var(--B500)' : 'var(--N900)',
157+
// eslint-disable-next-line no-nested-ternary
158+
backgroundColor: state.isSelected ? 'var(--B100)' : state.isFocused ? 'var(--N100)' : 'var(--bg-primary)',
159+
fontWeight: state.isSelected ? 600 : 'normal',
160+
marginRight: '8px',
161+
}),
162+
input: (base) => ({
163+
...base,
164+
margin: '0',
165+
flex: 'unset',
166+
color: 'var(--N900)',
167+
}),
168+
dropdownIndicator: (base) => ({
169+
...base,
170+
padding: '0 4px 0 4px',
171+
}),
172+
}
173+
174+
export const AppSelectorDropdownIndicator = (props: DropdownIndicatorProps) => {
175+
const { selectProps } = props
176+
177+
return (
178+
<components.DropdownIndicator {...props}>
179+
<DropDownIcon
180+
className="rotate"
181+
style={{
182+
['--rotateBy' as any]: selectProps.menuIsOpen ? '180deg' : '0deg',
183+
height: '24px',
184+
width: '24px',
185+
}}
186+
/>
187+
</components.DropdownIndicator>
188+
)
189+
}
190+
191+
export const AppSelectorNoOptionsMessage = (inputObj: { inputValue: string }): string => {
192+
if (inputObj && (inputObj.inputValue === '' || inputObj.inputValue.length < 3)) {
193+
return 'Type 3 chars to see matching results'
194+
}
195+
return 'No matching results'
196+
}

src/Shared/Components/WorkflowOptionsModal/WorkflowOptionsModal.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ const WorkflowOptionsModal = ({
4646
resetChangeCIPayload,
4747
linkedCDSourceVariant,
4848
isAppGroup = false,
49+
getTemplateAPIRoute,
50+
isTemplateView,
4951
}: Readonly<WorkflowOptionsModalProps>) => {
5052
const [currentCIPipelineType, setCurrentCIPipelineType] = useState<CIPipelineNodeType | WorkflowNodeType.WEBHOOK>(
5153
null,
@@ -112,7 +114,10 @@ const WorkflowOptionsModal = ({
112114
if (containsCDPipeline) {
113115
// Only need to disable it in case of error
114116
setLoadingWebhook(true)
115-
saveCDPipeline(getSwitchToWebhookPayload(changeCIPayload))
117+
saveCDPipeline(getSwitchToWebhookPayload(changeCIPayload), {
118+
getTemplateAPIRoute,
119+
isTemplateView,
120+
})
116121
.then((response) => {
117122
if (response.result) {
118123
ToastManager.showToast({

src/Shared/Components/WorkflowOptionsModal/types.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { AppConfigProps, GetTemplateAPIRouteProps } from '@Pages/index'
1718
import { ChangeCIPayloadType, CIPipelineNodeType, WorkflowType } from '@Shared/types'
1819

1920
interface LinkedCDSourceVariant {
@@ -31,7 +32,7 @@ export interface SourceTypeCardProps extends LinkedCDSourceVariant {
3132
isDisabled?: boolean
3233
}
3334

34-
export interface WorkflowOptionsModalProps {
35+
export interface WorkflowOptionsModalProps extends Required<Pick<AppConfigProps, 'isTemplateView'>> {
3536
handleCloseWorkflowOptionsModal: () => void
3637
addCIPipeline: (type: CIPipelineNodeType, workflowId?: number | string) => void
3738
addWebhookCD: (workflowId?: number | string) => void
@@ -44,4 +45,5 @@ export interface WorkflowOptionsModalProps {
4445
getWorkflows?: () => void
4546
linkedCDSourceVariant?: LinkedCDSourceVariant
4647
isAppGroup?: boolean
48+
getTemplateAPIRoute: (props: GetTemplateAPIRouteProps) => string
4749
}

src/Shared/Services/common.service.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
import { AppConfigProps, GetTemplateAPIRouteType } from '@Pages/index'
18+
import { WorkflowOptionsModalProps } from '@Shared/Components/WorkflowOptionsModal/types'
1719
import { getUrlWithSearchParams, post, ROUTES } from '../../Common'
1820
import { GetPolicyApiUrlProps, GetResourceApiUrlProps } from './types'
1921

@@ -23,4 +25,21 @@ export const getResourceApiUrl = <T>({ baseUrl, kind, version, suffix, queryPara
2325
export const getPolicyApiUrl = <T>({ kind, version, queryParams, suffix }: GetPolicyApiUrlProps<T>) =>
2426
getUrlWithSearchParams(`global/policy/${kind}/${version}${suffix ? `/${suffix}` : ''}`, queryParams)
2527

26-
export const saveCDPipeline = (request) => post(ROUTES.CD_CONFIG, request)
28+
export const saveCDPipeline = (
29+
request,
30+
{
31+
getTemplateAPIRoute,
32+
isTemplateView,
33+
}: Pick<WorkflowOptionsModalProps, 'getTemplateAPIRoute'> & Required<Pick<AppConfigProps, 'isTemplateView'>>,
34+
) => {
35+
const url = isTemplateView
36+
? getTemplateAPIRoute({
37+
type: GetTemplateAPIRouteType.CD_PIPELINE,
38+
queryParams: {
39+
id: request.appId,
40+
},
41+
})
42+
: ROUTES.CD_CONFIG
43+
44+
return post(url, request)
45+
}

0 commit comments

Comments
 (0)