mirror of
https://github.com/outbackdingo/openapi-ui.git
synced 2026-01-27 18:19:50 +00:00
wip
This commit is contained in:
@@ -5,9 +5,9 @@ import { AxiosError } from 'axios'
|
||||
import { usePermissions, useDirectUnknownResource, DeleteModal, Spacer } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { notification, Typography, Flex, Switch, Spin, Alert } from 'antd'
|
||||
import { BASE_API_GROUP, BASE_API_VERSION } from 'constants/customizationApiGroupAndVersion'
|
||||
import { TMarketPlacePanelResponse, TMarketPlacePanelResource, TMarketPlacePanel } from 'localTypes/marketplace'
|
||||
import { AddCard } from './atoms'
|
||||
import { AddEditFormModal, CardInProject, SearchTextInput } from './molecules'
|
||||
import { TMarketPlacePanelResponse, TMarketPlacePanelResource, TMarketPlacePanel } from './types'
|
||||
import { AddEditFormModal, MarketplaceCard, SearchTextInput } from './molecules'
|
||||
import { Styled } from './styled'
|
||||
|
||||
export const MarketPlace: FC = () => {
|
||||
@@ -187,7 +187,7 @@ export const MarketPlace: FC = () => {
|
||||
namespace &&
|
||||
filteredAndSortedData.map(
|
||||
({ name, description, icon, type, pathToNav, typeName, apiGroup, apiVersion, tags, disabled }) => (
|
||||
<CardInProject
|
||||
<MarketplaceCard
|
||||
key={name}
|
||||
description={description}
|
||||
disabled={disabled}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './MarketPlace'
|
||||
export * from './molecules/MarketplaceCard'
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createNewEntry, updateEntry } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { BASE_API_GROUP, BASE_API_VERSION } from 'constants/customizationApiGroupAndVersion'
|
||||
import { TMarketPlacePanel, TMarketPlacePanelResource } from '../../types'
|
||||
import { TMarketPlacePanel, TMarketPlacePanelResource } from 'localTypes/marketplace'
|
||||
|
||||
type TAddEditFormModalProps = {
|
||||
isOpen: boolean | TMarketPlacePanelResource
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './CardInProject'
|
||||
@@ -4,19 +4,20 @@ import { useNavigate } from 'react-router-dom'
|
||||
import { Typography, Flex, theme } from 'antd'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import { TMarketPlacePanel } from '../../types'
|
||||
import { TMarketPlacePanel } from 'localTypes/marketplace'
|
||||
import { getPathToNav } from './utils'
|
||||
import { Styled } from './styled'
|
||||
|
||||
type TCardInProjectProps = {
|
||||
type TMarketplaceCardProps = {
|
||||
clusterName: string
|
||||
namespace: string
|
||||
isEditMode?: boolean
|
||||
onDeleteClick: () => void
|
||||
onEditClick: () => void
|
||||
onDeleteClick?: () => void
|
||||
onEditClick?: () => void
|
||||
addedMode?: boolean
|
||||
} & Omit<TMarketPlacePanel, 'hidden'>
|
||||
|
||||
export const CardInProject: FC<TCardInProjectProps> = ({
|
||||
export const MarketplaceCard: FC<TMarketplaceCardProps> = ({
|
||||
description,
|
||||
name,
|
||||
icon,
|
||||
@@ -71,7 +72,9 @@ export const CardInProject: FC<TCardInProjectProps> = ({
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
onDeleteClick()
|
||||
if (onDeleteClick) {
|
||||
onDeleteClick()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -100,7 +103,9 @@ export const CardInProject: FC<TCardInProjectProps> = ({
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
onEditClick()
|
||||
if (onEditClick) {
|
||||
onEditClick()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<svg width="18" height="19" viewBox="0 0 18 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -0,0 +1 @@
|
||||
export * from './MarketplaceCard'
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './AddEditFormModal'
|
||||
export * from './CardInProject'
|
||||
export * from './MarketplaceCard'
|
||||
export * from './SearchTextInput'
|
||||
|
||||
@@ -1,207 +1,21 @@
|
||||
import React, { FC, useCallback, useState } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { Spacer, useDirectUnknownResource, DeleteModal, usePermissions } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { Typography, Flex, Row, Col, Spin, Button } from 'antd'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import { BASE_API_GROUP, BASE_RPROJECTS_VERSION } from 'constants/customizationApiGroupAndVersion'
|
||||
import React, { FC } from 'react'
|
||||
import { Row, Col } from 'antd'
|
||||
import { ContentCard, MarketPlace } from 'components'
|
||||
import { DropdownActions, DropdownAccessGroups } from './molecules'
|
||||
import { Styled } from './styled'
|
||||
import { ProjectInfoCard } from './organisms'
|
||||
|
||||
export const ProjectInfo: FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const { clusterName, namespace } = useParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const {
|
||||
data: project,
|
||||
isLoading,
|
||||
error,
|
||||
} = useDirectUnknownResource<{
|
||||
apiVersion: string
|
||||
kind: 'Project'
|
||||
metadata: {
|
||||
labels: {
|
||||
paas: string
|
||||
pj: string
|
||||
}
|
||||
name: string
|
||||
resourceVersion: string
|
||||
uid: string
|
||||
}
|
||||
spec: {
|
||||
businessName?: string
|
||||
description: string
|
||||
prefix: string
|
||||
}
|
||||
status: {
|
||||
conditions: {
|
||||
lastTransitionTime: string
|
||||
message: string
|
||||
reason: string
|
||||
status: string
|
||||
type: string
|
||||
}[]
|
||||
}
|
||||
}>({
|
||||
uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_RPROJECTS_VERSION}/projects/${namespace}`,
|
||||
refetchInterval: 5000,
|
||||
queryKey: ['projects', clusterName || 'no-cluster'],
|
||||
isEnabled: clusterName !== undefined,
|
||||
})
|
||||
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState<boolean>(false)
|
||||
|
||||
const updatePermission = usePermissions({
|
||||
apiGroup: BASE_API_GROUP,
|
||||
typeName: 'projects',
|
||||
namespace: '',
|
||||
clusterName: clusterName || '',
|
||||
verb: 'update',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const deletePermission = usePermissions({
|
||||
apiGroup: BASE_API_GROUP,
|
||||
typeName: 'projects',
|
||||
namespace: '',
|
||||
clusterName: clusterName || '',
|
||||
verb: 'delete',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const openUpdate = useCallback(() => {
|
||||
navigate(
|
||||
`${baseprefix}/${clusterName}/forms/apis/${BASE_API_GROUP}/${BASE_RPROJECTS_VERSION}/projects/${namespace}?backlink=${baseprefix}/clusters/${clusterName}`,
|
||||
)
|
||||
}, [baseprefix, clusterName, namespace, navigate])
|
||||
|
||||
if (isLoading) {
|
||||
return <Spin />
|
||||
}
|
||||
|
||||
if (!project || error) {
|
||||
return null
|
||||
}
|
||||
|
||||
// const readyCondition = project.status.conditions.find(({ type }) => type === 'Ready')
|
||||
const readyCondition = project.status.conditions.find(({ type }) => type !== 'Ready')
|
||||
|
||||
return (
|
||||
<>
|
||||
<Row gutter={[24, 24]} style={{ flexGrow: 1 }}>
|
||||
<Col span={13}>
|
||||
<ContentCard flexGrow={1}>
|
||||
<Flex justify="space-between">
|
||||
<div>
|
||||
<Flex gap={20} vertical>
|
||||
<div>
|
||||
<Typography.Text type="secondary">Project Business Name</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Flex gap="small">
|
||||
<Styled.BigValue>{project.spec.businessName || '-'}</Styled.BigValue>
|
||||
{readyCondition && (
|
||||
<Flex align="center" gap="small">
|
||||
<Typography.Text type={readyCondition.status === 'True' ? 'success' : 'warning'}>
|
||||
{readyCondition.reason}
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text>{project.spec.description}</Typography.Text>
|
||||
</div>
|
||||
</Flex>
|
||||
<Spacer $space={24} $samespace />
|
||||
<Flex gap={14} vertical>
|
||||
<div>
|
||||
<Typography.Text type="secondary">Developer Instruments</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Flex gap={14} wrap>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
</div>
|
||||
<div>
|
||||
<Flex gap={24} vertical>
|
||||
<Flex justify="flex-end">
|
||||
{readyCondition?.status === 'True' &&
|
||||
(updatePermission.data?.status.allowed || deletePermission.data?.status.allowed) ? (
|
||||
<DropdownActions
|
||||
onDelete={
|
||||
deletePermission.data?.status.allowed
|
||||
? () => {
|
||||
setIsDeleteModalOpen(true)
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onUpdate={updatePermission.data?.status.allowed ? openUpdate : undefined}
|
||||
/>
|
||||
) : (
|
||||
<Styled.ActionMenuPlaceholder />
|
||||
)}
|
||||
</Flex>
|
||||
<DropdownAccessGroups />
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
</ContentCard>
|
||||
</Col>
|
||||
<Col span={11}>
|
||||
<ContentCard flexGrow={1}>
|
||||
<MarketPlace />
|
||||
</ContentCard>
|
||||
</Col>
|
||||
</Row>
|
||||
{isDeleteModalOpen && (
|
||||
<DeleteModal
|
||||
name={project.metadata.name}
|
||||
onClose={() => {
|
||||
setIsDeleteModalOpen(false)
|
||||
navigate(`${baseprefix}/clusters/${clusterName}`)
|
||||
}}
|
||||
endpoint={`/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_RPROJECTS_VERSION}/projects/${project.metadata.name}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<Row gutter={[24, 24]} style={{ flexGrow: 1 }}>
|
||||
<Col span={13}>
|
||||
<ContentCard flexGrow={1}>
|
||||
<ProjectInfoCard />
|
||||
</ContentCard>
|
||||
</Col>
|
||||
<Col span={11}>
|
||||
<ContentCard flexGrow={1}>
|
||||
<MarketPlace />
|
||||
</ContentCard>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
import React, { FC, useCallback, useState } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { Spacer, useDirectUnknownResource, DeleteModal, usePermissions } from '@prorobotech/openapi-k8s-toolkit'
|
||||
import { Typography, Flex, Spin, Button } from 'antd'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { RootState } from 'store/store'
|
||||
import { BASE_API_GROUP, BASE_API_VERSION, BASE_RPROJECTS_VERSION } from 'constants/customizationApiGroupAndVersion'
|
||||
import { TMarketPlacePanelResponse } from 'localTypes/marketplace'
|
||||
import { MarketplaceCard } from 'components/molecules'
|
||||
import { DropdownActions, DropdownAccessGroups } from '../../molecules'
|
||||
import { Styled } from './styled'
|
||||
|
||||
export const ProjectInfoCard: FC = () => {
|
||||
const navigate = useNavigate()
|
||||
const { clusterName, namespace } = useParams()
|
||||
const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix)
|
||||
|
||||
const {
|
||||
data: marketplacePanels,
|
||||
isLoading: marketplaceIsLoading,
|
||||
// error: marketplaceError,
|
||||
} = useDirectUnknownResource<TMarketPlacePanelResponse>({
|
||||
uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_API_VERSION}/marketplacepanels/`,
|
||||
refetchInterval: 5000,
|
||||
queryKey: ['marketplacePanels', clusterName || 'no-cluster'],
|
||||
isEnabled: clusterName !== undefined,
|
||||
})
|
||||
|
||||
const {
|
||||
data: project,
|
||||
isLoading,
|
||||
error,
|
||||
} = useDirectUnknownResource<{
|
||||
apiVersion: string
|
||||
kind: 'Project'
|
||||
metadata: {
|
||||
labels: {
|
||||
paas: string
|
||||
pj: string
|
||||
}
|
||||
name: string
|
||||
resourceVersion: string
|
||||
uid: string
|
||||
}
|
||||
spec: {
|
||||
businessName?: string
|
||||
description: string
|
||||
prefix: string
|
||||
}
|
||||
status: {
|
||||
conditions: {
|
||||
lastTransitionTime: string
|
||||
message: string
|
||||
reason: string
|
||||
status: string
|
||||
type: string
|
||||
}[]
|
||||
}
|
||||
}>({
|
||||
uri: `/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_RPROJECTS_VERSION}/projects/${namespace}`,
|
||||
refetchInterval: 5000,
|
||||
queryKey: ['projects', clusterName || 'no-cluster'],
|
||||
isEnabled: clusterName !== undefined,
|
||||
})
|
||||
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState<boolean>(false)
|
||||
|
||||
const updatePermission = usePermissions({
|
||||
apiGroup: BASE_API_GROUP,
|
||||
typeName: 'projects',
|
||||
namespace: '',
|
||||
clusterName: clusterName || '',
|
||||
verb: 'update',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const deletePermission = usePermissions({
|
||||
apiGroup: BASE_API_GROUP,
|
||||
typeName: 'projects',
|
||||
namespace: '',
|
||||
clusterName: clusterName || '',
|
||||
verb: 'delete',
|
||||
refetchInterval: false,
|
||||
})
|
||||
|
||||
const openUpdate = useCallback(() => {
|
||||
navigate(
|
||||
`${baseprefix}/${clusterName}/forms/apis/${BASE_API_GROUP}/${BASE_RPROJECTS_VERSION}/projects/${namespace}?backlink=${baseprefix}/clusters/${clusterName}`,
|
||||
)
|
||||
}, [baseprefix, clusterName, namespace, navigate])
|
||||
|
||||
if (isLoading) {
|
||||
return <Spin />
|
||||
}
|
||||
|
||||
if (!project || error) {
|
||||
return null
|
||||
}
|
||||
|
||||
// const readyCondition = project.status.conditions.find(({ type }) => type === 'Ready')
|
||||
const readyCondition = project.status.conditions.find(({ type }) => type !== 'Ready')
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex justify="space-between">
|
||||
<div>
|
||||
<Flex gap={20} vertical>
|
||||
<div>
|
||||
<Typography.Text type="secondary">Project Business Name</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Flex gap="small">
|
||||
<Styled.BigValue>{project.spec.businessName || '-'}</Styled.BigValue>
|
||||
{readyCondition && (
|
||||
<Flex align="center" gap="small">
|
||||
<Typography.Text type={readyCondition.status === 'True' ? 'success' : 'warning'}>
|
||||
{readyCondition.reason}
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text>{project.spec.description}</Typography.Text>
|
||||
</div>
|
||||
</Flex>
|
||||
<Spacer $space={24} $samespace />
|
||||
<Flex gap={14} vertical>
|
||||
<div>
|
||||
<Typography.Text type="secondary">Developer Instruments</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Flex gap={14} wrap>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
<Button type="link">Test</Button>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
</div>
|
||||
<div>
|
||||
<Flex gap={24} vertical>
|
||||
<Flex justify="flex-end">
|
||||
{readyCondition?.status === 'True' &&
|
||||
(updatePermission.data?.status.allowed || deletePermission.data?.status.allowed) ? (
|
||||
<DropdownActions
|
||||
onDelete={
|
||||
deletePermission.data?.status.allowed
|
||||
? () => {
|
||||
setIsDeleteModalOpen(true)
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onUpdate={updatePermission.data?.status.allowed ? openUpdate : undefined}
|
||||
/>
|
||||
) : (
|
||||
<Styled.ActionMenuPlaceholder />
|
||||
)}
|
||||
</Flex>
|
||||
<DropdownAccessGroups />
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
<Spacer $space={24} $samespace />
|
||||
<Typography.Text type="secondary">Added Products</Typography.Text>
|
||||
<Spacer $space={12} $samespace />
|
||||
<Flex gap={22}>
|
||||
{marketplaceIsLoading && <Spin />}
|
||||
{clusterName &&
|
||||
namespace &&
|
||||
marketplacePanels?.items
|
||||
.map(({ spec }) => spec)
|
||||
.sort()
|
||||
.map(({ name, description, icon, type, pathToNav, typeName, apiGroup, apiVersion, tags, disabled }) => (
|
||||
<MarketplaceCard
|
||||
key={name}
|
||||
description={description}
|
||||
disabled={disabled}
|
||||
icon={icon}
|
||||
isEditMode={false}
|
||||
name={name}
|
||||
clusterName={clusterName}
|
||||
namespace={namespace}
|
||||
type={type}
|
||||
pathToNav={pathToNav}
|
||||
typeName={typeName}
|
||||
apiGroup={apiGroup}
|
||||
apiVersion={apiVersion}
|
||||
tags={tags}
|
||||
addedMode
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
{isDeleteModalOpen && (
|
||||
<DeleteModal
|
||||
name={project.metadata.name}
|
||||
onClose={() => {
|
||||
setIsDeleteModalOpen(false)
|
||||
navigate(`${baseprefix}/clusters/${clusterName}`)
|
||||
}}
|
||||
endpoint={`/api/clusters/${clusterName}/k8s/apis/${BASE_API_GROUP}/${BASE_RPROJECTS_VERSION}/projects/${project.metadata.name}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './ProjectInfoCard'
|
||||
@@ -0,0 +1,27 @@
|
||||
import styled from 'styled-components'
|
||||
import { Typography } from 'antd'
|
||||
|
||||
const ActionMenuPlaceholder = styled.div`
|
||||
width: 45.33px;
|
||||
height: 1px;
|
||||
`
|
||||
|
||||
const BigValue = styled(Typography.Text)`
|
||||
font-size: 36px;
|
||||
line-height: 36px;
|
||||
font-weight: 700;
|
||||
/* stylelint-disable-next-line value-no-vendor-prefix */
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
-ms-line-clamp: 1;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
line-clamp: 1;
|
||||
word-break: break-all;
|
||||
`
|
||||
|
||||
export const Styled = {
|
||||
ActionMenuPlaceholder,
|
||||
BigValue,
|
||||
}
|
||||
1
src/components/organisms/ProjectInfo/organisms/index.ts
Normal file
1
src/components/organisms/ProjectInfo/organisms/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './ProjectInfoCard'
|
||||
Reference in New Issue
Block a user