This is an automated email from the ASF dual-hosted git repository. marat pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 7eaf19230ee4f1c0bb233281e6caaf03ee4204bf Author: Marat Gubaidullin <[email protected]> AuthorDate: Fri Apr 3 14:04:56 2026 -0400 Karavan App Cleanup --- .../src/main/webui/src/ui/api/ValidationApi.tsx | 66 --------------- .../DashboardDevelopmentCardProjectRow.tsx | 15 +--- .../DashboardDevelopmentCardProjects.tsx | 1 - .../development/DashboardDevelopmentHook.tsx | 99 +--------------------- .../development/DashboardDevelopmentRefresher.tsx | 5 +- .../ui/features/project/ProjectPageNavigation.tsx | 4 - .../webui/src/ui/features/project/ProjectTitle.tsx | 6 +- .../project/developer/DeveloperManager.tsx | 5 +- .../project/developer/DeveloperToolbar.tsx | 75 ---------------- .../ui/features/project/developer/YamlEditor.tsx | 13 --- .../src/ui/features/project/files/FilesSubTab.tsx | 5 -- .../src/ui/features/project/files/FilesToolbar.tsx | 11 --- .../project/project-topology/CustomNode.tsx | 14 +-- .../project/project-topology/TopologyToolbar.tsx | 10 +-- .../src/ui/features/projects/ProjectsTableRow.tsx | 4 - .../main/webui/src/ui/models/ValidationModels.ts | 12 --- .../main/webui/src/ui/stores/ValidationStore.ts | 40 --------- 17 files changed, 8 insertions(+), 377 deletions(-) diff --git a/karavan-app/src/main/webui/src/ui/api/ValidationApi.tsx b/karavan-app/src/main/webui/src/ui/api/ValidationApi.tsx deleted file mode 100644 index 3fe91d4d..00000000 --- a/karavan-app/src/main/webui/src/ui/api/ValidationApi.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import axios from "axios"; -import {AuthApi} from "@api/auth/AuthApi"; -import {ErrorEventBus} from "@bus/ErrorEventBus"; -import {ProjectValidation} from "@models/ValidationModels"; - -axios.defaults.headers.common['Accept'] = 'application/json'; -axios.defaults.headers.common['Content-Type'] = 'application/json'; -const instance = AuthApi.getInstance(); - -export class ValidationApi { - - static async getAllProjectValidations(after: (result: ProjectValidation[]) => void) { - instance.get('/ui/validation/') - .then(res => { - if (res.status === 200) { - after(res.data); - } else { - after([]); - } - }).catch(err => { - ErrorEventBus.sendApiError(err); - after([]); - }); - } - - static async validateProjects(after: () => void) { - instance.post('/ui/validation/', {}) - .then(res => { - if (res.status === 200) { - after(); - } else { - after(); - } - }).catch(err => { - ErrorEventBus.sendApiError(err); - after(); - }); - } - - static async validateProject(projectId: string, after: () => void) { - instance.post(`/ui/validation/project/${projectId}`, {}) - .then(res => { - if (res.status === 200) { - after(); - } else { - after(); - } - }).catch(err => { - ErrorEventBus.sendApiError(err); - after(); - }); - } - static async validateProjectFile(projectId: string, filename: string, after: () => void) { - instance.post(`/ui/validation/project/${projectId}/${filename}`, {}) - .then(res => { - if (res.status === 200) { - after(); - } else { - after(); - } - }).catch(err => { - ErrorEventBus.sendApiError(err); - after(); - }); - } -} diff --git a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjectRow.tsx b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjectRow.tsx index 45c88ac1..fbb59bd3 100644 --- a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjectRow.tsx +++ b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjectRow.tsx @@ -1,12 +1,10 @@ import React from 'react'; -import {Button, Content, Label} from '@patternfly/react-core'; +import {Button, Content} from '@patternfly/react-core'; import {BUILD_IN_PROJECTS, Project, ProjectCommited} from "@models/ProjectModels"; import {ComplexityProject} from "@features/projects/ComplexityModels"; import {ProjectInfo} from "@models/CatalogModels"; import {useNavigate} from "react-router-dom"; -import {useValidationStore} from "@stores/ValidationStore"; import {Td, Tr} from "@patternfly/react-table"; -import CheckCircleIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon"; import {ROUTES} from "@app/navigation/Routes"; import {ProjectsTableRowTimeLine} from "@features/projects/ProjectsTableRowTimeLine"; import {ProjectStatusLabel} from "@features/projects/ProjectStatusLabel"; @@ -24,13 +22,8 @@ interface Props { export function DashboardDevelopmentCardProjectRow(props: Props): React.ReactElement { - const {validations} = useValidationStore(); const {project, complexity, activeUsers, labels, projectInfo, projectCommited} = props; const navigate = useNavigate(); - const validation = validations?.find(v => v.projectId === project.projectId); - const hasErrors = validation?.hasErrors; - const errorCount = validation?.files?.filter(f => f.hasErrors)?.length || 0; - const color = hasErrors ? "var(--pf-t--global--icon--color--status--danger--default)" : "var(--pf-t--global--icon--color--status--success--default)" const isBuildIn = BUILD_IN_PROJECTS.includes(project.projectId); return ( <Tr key={project.projectId} style={{verticalAlign: "middle"}} className={"project-card"}> @@ -40,12 +33,6 @@ export function DashboardDevelopmentCardProjectRow(props: Props): React.ReactEle <div>{project.projectId}</div> </Button> </Td> - <Td textCenter> - {hasErrors - ? <Label status={'danger'} variant={'outline'}>{errorCount}</Label> - : <CheckCircleIcon color={color}/> - } - </Td> <Td modifier={"nowrap"} textCenter> <ProjectsTableRowTimeLine project={project} projectCommited={projectCommited} /> </Td> diff --git a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjects.tsx b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjects.tsx index 826a2fda..89c450dd 100644 --- a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjects.tsx +++ b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentCardProjects.tsx @@ -121,7 +121,6 @@ export function DashboardDevelopmentCardProjects() { <Th key='project'> <Content component={'h6'}>Recent Projects</Content> </Th> - <Th key='validation' modifier='fitContent' textCenter>Validation</Th> <Th key='timeline'> <ProgressStepper isCenterAligned className={"projects-table-header-progress-stepper"}> <ProgressStep id="commited" titleId="commited"> diff --git a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentHook.tsx b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentHook.tsx index 25eaf94a..ac3f1223 100644 --- a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentHook.tsx +++ b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentHook.tsx @@ -2,112 +2,16 @@ import {useStatusesStore} from "@stores/ProjectStore"; import {ROUTES} from "@app/navigation/Routes"; import {useNavigate} from "react-router-dom"; import {ProjectMetrics} from "@models/DashboardModels"; -import {useValidationStore} from "@stores/ValidationStore"; -import {Button, Content, Popover, Tooltip} from "@patternfly/react-core"; -import * as React from "react"; -import ExclamationCircleIcon from "@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon"; export function DashboardDevelopmentHook() { const [camelStatuses] = useStatusesStore((s) => [s.camelContexts]) - const [validations] = useValidationStore((s) => [s.validations]) const navigate = useNavigate(); function selectFile(integration: string, fileName: string) { navigate(`${ROUTES.PROJECTS}/${integration}/${fileName}`); } - function getValidationInfo(projectId: string) { - return validations.find(v => v.projectId === projectId); - } - - function getValidationInfoForFile(projectId: string, fileName: string) { - const validation = getValidationInfo(projectId); - return validation?.files?.find(f => f.name === fileName) - } - - function getProjectValidationIcon(projectId: string) { - const validation = getValidationInfo(projectId); - const invalidFiles = validation?.files?.filter(f => f?.hasErrors)?.length ?? 0; - let labelIcon = undefined; - if (validation?.hasErrors) { - labelIcon = ( - <Tooltip content={`Errors in ${invalidFiles} file(s)!`} className={'tooltip-danger'}> - <ExclamationCircleIcon className='validation-icon validation-icon-danger'/> - </Tooltip> - ); - } - return labelIcon; - } - - function getProjectValidationStatus(projectId: string) { - const validation = getValidationInfo(projectId); - const invalidFiles = validation?.files?.filter(f => f?.hasErrors)?.length ?? 0; - if (validation === undefined || validation === null || validation.files?.length === 0) { - return undefined; - } else if (invalidFiles > 0) { - return false; - } - return true; - } - - function getProjectFileValidationIcon(projectId: string, fileName: string) { - const invalidFile = getValidationInfoForFile(projectId, fileName); - let labelIcon = undefined; - if (invalidFile?.hasErrors) { - labelIcon = ( - <Tooltip content={`Errors in file ${invalidFile?.name}!`} className={'tooltip-danger'}> - <ExclamationCircleIcon className='validation-icon validation-icon-danger'/> - </Tooltip> - ); - } - return labelIcon; - } - - function getProjectFileValidationAlerts(projectId: string, fileName: string) { - try { - const invalidFile = getValidationInfoForFile(projectId, fileName); - if (invalidFile?.hasErrors) { - const errors = invalidFile?.errors; - if (errors && Array.isArray(errors)) { - return ( - <Popover - className='popover-file-validation' - aria-label="Alert popover" - hasAutoWidth - alertSeverityVariant={'danger'} - headerContent="Validation Errors" - headerIcon={<ExclamationCircleIcon/>} - headerComponent="h1" - bodyContent={ - <div style={{display: "flex", flexDirection: "column", justifyContent: "flex-start", alignItems: "stretch", gap: "8px"}}> - {errors.map((error, index) => { - const line = error?.details?.line; - const type = error?.property ? error?.property : error?.type; - const title = `Error at line ${line}: ${type}` - return ( - <div key={index} style={{display: "flex", flexDirection: "column", justifyContent: "flex-start", gap: "3px"}}> - <Content style={{fontWeight: 'bold', margin: 0}} component="p">{title}</Content> - <Content style={{margin: 0}} component="p">{error?.message}</Content> - </div> - ) - })} - </div> - } - appendTo={() => document.body} - > - <Button isInline variant={'link'} isDanger icon={<ExclamationCircleIcon/>}>Validation Error</Button> - </Popover> - ) - } - } - } catch (err) { - console.error(err); - } - return undefined; - } - - function getIntegrationMetrics(projectId: string): ProjectMetrics { let remoteExchangesTotal: number = 0; let remoteExchangesFailed: number = 0; @@ -142,7 +46,6 @@ export function DashboardDevelopmentHook() { } return { - selectFile, getValidationInfoForFile, getProjectValidationIcon, getProjectFileValidationIcon, - getProjectFileValidationAlerts, getProjectValidationStatus + selectFile } } \ No newline at end of file diff --git a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentRefresher.tsx b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentRefresher.tsx index 75a96334..87b04495 100644 --- a/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentRefresher.tsx +++ b/karavan-app/src/main/webui/src/ui/features/dashboard/development/DashboardDevelopmentRefresher.tsx @@ -7,16 +7,14 @@ import {useDataPolling} from "@shared/polling/useDataPolling"; import {DashboardService} from "@services/DashboardService"; import {INTERNAL_COMPONENTS} from "@core/api/ComponentApi"; import {useContainerStatusesStore} from "@stores/ContainerStatusesStore"; -import {useValidationStore} from "@stores/ValidationStore"; import {useCommitsStore} from "@stores/CommitsStore"; -import {useProjectInfoStore} from "../../../stores/ProjectInfoStore"; +import {useProjectInfoStore} from "@stores/ProjectInfoStore"; export function DashboardDevelopmentRefresher() { const {containers} = useContainerStatusesStore(); const [consumers, processors] = useStatusesStore((s) => [s.consumers, s.processors]); const {fetchProjectsCommited} = useProjectsStore(); - const {fetchValidations} = useValidationStore(); const {fetchSystemCommits} = useCommitsStore(); const [projectInfos, fetchProjectInfos] = useProjectInfoStore(s => [s.projectInfos, s.fetchProjectInfos]); const [count, setCount] = useState<number>(0); @@ -27,7 +25,6 @@ export function DashboardDevelopmentRefresher() { function refreshDesign() { ProjectService.refreshProjects(); - fetchValidations(); fetchSystemCommits(); fetchProjectsCommited(); fetchProjectInfos(); diff --git a/karavan-app/src/main/webui/src/ui/features/project/ProjectPageNavigation.tsx b/karavan-app/src/main/webui/src/ui/features/project/ProjectPageNavigation.tsx index 8c95fab4..413c9a68 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/ProjectPageNavigation.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/ProjectPageNavigation.tsx @@ -36,7 +36,6 @@ import {TryOutIcon} from "@shared/icons/TryOutIcon"; import {shallow} from "zustand/shallow"; import {useIntegrationStore} from "@features/project/designer/DesignerStore"; import {KubernetesIcon} from "@features/project/designer/icons/ComponentIcons"; -import {DashboardDevelopmentHook} from "@features/dashboard/development/DashboardDevelopmentHook"; export function ProjectPageNavigation(): JSX.Element { @@ -62,9 +61,6 @@ export function ProjectPageNavigation(): JSX.Element { const [buildContainerId, setBuildContainerId] = useState<string>(''); const [hasDevMode, setHasDevMode] = useState<boolean>(false); - const {getProjectValidationIcon} = DashboardDevelopmentHook(); - const validationIcon = getProjectValidationIcon(project?.projectId) - useEffect(() => { selectName(); }, [tabIndex, hasDevmodeContainers, hasBuildContainers, buildContainer?.containerId, buildContainerId]) diff --git a/karavan-app/src/main/webui/src/ui/features/project/ProjectTitle.tsx b/karavan-app/src/main/webui/src/ui/features/project/ProjectTitle.tsx index 7fa2905a..88616015 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/ProjectTitle.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/ProjectTitle.tsx @@ -19,7 +19,6 @@ import React from 'react'; import {Alert, ClipboardCopy, Content, Flex, FlexItem,} from '@patternfly/react-core'; import {useFileStore, useProjectStore} from "@stores/ProjectStore"; import {shallow} from "zustand/shallow"; -import {GENERATED_FILENAME_PREFIX} from "@models/CatalogModels"; import {LockedIcon} from "@patternfly/react-icons"; export function ProjectTitle() { @@ -28,7 +27,6 @@ export function ProjectTitle() { const [file, setFile, operation] = useFileStore((s) => [s.file, s.setFile, s.operation], shallow); const isFile = file !== undefined && operation !== 'delete'; - const isGenerated = isFile && file?.name?.startsWith(GENERATED_FILENAME_PREFIX); const isLog = file !== undefined && file.name.endsWith("log"); const filename = file ? file.name.substring(0, file.name.lastIndexOf('.')) : ""; @@ -87,8 +85,8 @@ export function ProjectTitle() { return ( <div className="dsl-title project-title"> - {isFile && !isGenerated && getFileTitle()} - {isFile && isGenerated && getGeneratedFileTitle()} + {isFile && getFileTitle()} + {isFile && getGeneratedFileTitle()} {!isFile && getProjectTitle()} </div> ) diff --git a/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperManager.tsx b/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperManager.tsx index 302d68f7..ad5f7b5c 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperManager.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperManager.tsx @@ -11,14 +11,11 @@ import {EditorType} from "@features/project/developer/EditorConfig"; import {APPLICATION_PROPERTIES, DOCKER_COMPOSE, DOCKER_STACK, KUBERNETES_YAML} from "@models/ProjectModels"; import DeveloperToolbar from "@features/project/developer/DeveloperToolbar"; import {DesignerEditor} from "@features/project/developer/DesignerEditor"; -import {DashboardDevelopmentHook} from "@features/dashboard/development/DashboardDevelopmentHook"; export function DeveloperManager() { const [file] = useFileStore((s) => [s.file], shallow) const [designerSwitch, setDesignerSwitch] = useDesignerStore((s) => [s.designerSwitch, s.setDesignerSwitch], shallow) - const {getValidationInfoForFile} = DashboardDevelopmentHook(); - const validation = getValidationInfoForFile(file.projectId, file?.name); useEffect(() => { if (isCamelYaml || isKameletYaml) { @@ -43,7 +40,7 @@ export function DeveloperManager() { const isCamelYaml = yamlIsCamel(); const isKameletYaml = file?.name.endsWith(".kamelet.yaml"); const isIntegration = isCamelYaml && (file?.code && CamelDefinitionYaml.yamlIsIntegration(file.code) || file?.code?.length === 0); - const showDesigner = !validation?.hasErrors && designerSwitch && ((isCamelYaml && isIntegration) || isKameletYaml); + const showDesigner = designerSwitch && ((isCamelYaml && isIntegration) || isKameletYaml); const showPropertiesEditor = file?.name === APPLICATION_PROPERTIES; const isMarkdown = file?.name.endsWith(".md"); const isGroovy = file?.name.endsWith(".groovy"); diff --git a/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperToolbar.tsx b/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperToolbar.tsx index a568f60b..054aa3c4 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperToolbar.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/developer/DeveloperToolbar.tsx @@ -1,15 +1,6 @@ import React from 'react'; -import {useFileStore, useProjectStore} from "@stores/ProjectStore"; -import {shallow} from "zustand/shallow"; import {ProjectTitle} from "@features/project/ProjectTitle"; import {DesignerToggle} from "@features/project/DesignerToggle"; -import {Button, Content, Popover} from "@patternfly/react-core"; -import {DashboardDevelopmentHook} from "@features/dashboard/development/DashboardDevelopmentHook"; -import {CheckIcon} from "@patternfly/react-icons"; -import {useValidationStore} from "@stores/ValidationStore"; -import {KARAVAN_DOT_EXTENSION} from "@core/contants"; -import {DOCKER_COMPOSE} from "@models/ProjectModels"; -import ExclamationCircleIcon from "@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon"; interface DeveloperToolbarProps { showDesignerToggle?: boolean @@ -18,75 +9,9 @@ interface DeveloperToolbarProps { function DeveloperToolbar({showDesignerToggle, showRunButton}: DeveloperToolbarProps) { - const [project] = useProjectStore((s) => [s.project], shallow) - const [file] = useFileStore((s) => [s.file], shallow) - const {getValidationInfoForFile} = DashboardDevelopmentHook(); - const validation = file ? getValidationInfoForFile(project.projectId, file?.name) : undefined; - const {validateProjectFile, validations} = useValidationStore(); - const showValidateButton = file?.name?.endsWith(KARAVAN_DOT_EXTENSION.CAMEL_YAML) - || file?.name?.endsWith(KARAVAN_DOT_EXTENSION.KAMELET_YAML) - || file?.name?.endsWith(DOCKER_COMPOSE) - - const errors = validation?.errors; - const hasErrors = errors?.length > 0; - - const popoverBody = ( - <div style={{display: "flex", flexDirection: "column", justifyContent: "flex-start", alignItems: "stretch", gap: "8px"}}> - {errors?.map((error, index) => { - const line = error?.details?.line; - const type = error?.property ? error?.property : error?.type; - const title = `Error at line ${line}: ${type}` - return ( - <div key={index} style={{display: "flex", flexDirection: "column", justifyContent: "flex-start", gap: "3px"}}> - <Content isVisitedLink style={{fontWeight: 'bold', margin: 0}} component="p">{title}</Content> - <Content style={{margin: 0}} component="p">{error?.message}</Content> - </div> - ) - })} - </div> - ) - - const popover = ( - <Popover - aria-label="Alert popover" - alertSeverityVariant={'danger'} - headerComponent="h1" - bodyContent={popoverBody} - appendTo={() => document.body} - > - <Button icon={<ExclamationCircleIcon/>} - isDanger={hasErrors} - variant={'secondary'} - onClick={_ => { - validateProjectFile(file.projectId, file.name); - }} - > - Show Errors - </Button> - </Popover> - ) - - function getValidationButton() { - return ( - <div style={{paddingRight: 16, display: "flex", flexDirection: "row", gap: "16px", alignItems: "center"}}> - <Button icon={<CheckIcon/>} - isDanger={hasErrors} - variant={'secondary'} - onClick={_ => { - validateProjectFile(file.projectId, file.name); - }} - > - Validate - </Button> - {hasErrors && popover} - </div> - ) - } - return ( <div className="project-files-toolbar"> <ProjectTitle/> - {showValidateButton && getValidationButton()} {showDesignerToggle && <DesignerToggle/>} </div> ) diff --git a/karavan-app/src/main/webui/src/ui/features/project/developer/YamlEditor.tsx b/karavan-app/src/main/webui/src/ui/features/project/developer/YamlEditor.tsx index f2f13aa4..e1ece20e 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/developer/YamlEditor.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/developer/YamlEditor.tsx @@ -4,13 +4,11 @@ import {MonacoEditorWrapper} from "@features/project/developer/MonacoEditorWrapp import {Group, Panel} from "react-resizable-panels"; import type * as monaco from "monaco-editor"; import {configureMonacoYaml} from 'monaco-yaml'; -import {useValidationStore} from "@stores/ValidationStore"; import {useDeveloperStore} from "@stores/DeveloperStore"; import camelYaml from "./schemas/camelYamlDslSimplified.json"; import dockerYaml from "./schemas/compose-spec.json"; import {DOCKER_COMPOSE} from "@models/ProjectModels"; import {KARAVAN_DOT_EXTENSION} from "@core/contants"; -import {useDebounceCallback} from "usehooks-ts"; export interface CodeEditorProps { projectId?: string; @@ -23,16 +21,13 @@ export interface CodeEditorProps { export function YamlEditor(props: CodeEditorProps) { const {projectId, filename, initialCode, onChange, onLinkOpen} = props; - const {validateProjectFile} = useValidationStore(); const {setValidation} = useDeveloperStore(); const markerListenerRef = useRef<monaco.IDisposable | null>(null); - const debouncedValidateProjectFile = useDebounceCallback(validateProjectFile, 3000); // Cleanup the marker listener on unmount useEffect(() => { return () => { markerListenerRef.current?.dispose(); - debouncedValidateProjectFile.cancel(); }; }, []); @@ -71,14 +66,6 @@ export function YamlEditor(props: CodeEditorProps) { // Get all markers currently applied to this file const currentMarkers = monacoInstance.editor.getModelMarkers({ resource: model.uri }); setValidation(currentMarkers?.length === 0, currentMarkers); - if (currentMarkers.length === 0) { - // Frontend is valid: Queue the heavy backend validation - debouncedValidateProjectFile(projectId, filename); - } else { - // Frontend is INVALID: Cancel any pending backend validation immediately - // This prevents useless server load if they just broke the schema! - debouncedValidateProjectFile.cancel(); - } } }); } diff --git a/karavan-app/src/main/webui/src/ui/features/project/files/FilesSubTab.tsx b/karavan-app/src/main/webui/src/ui/features/project/files/FilesSubTab.tsx index d07d0583..9cb796b0 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/files/FilesSubTab.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/files/FilesSubTab.tsx @@ -26,7 +26,6 @@ import {ModalConfirmation} from "@shared/ui/ModalConfirmation"; import {EventBus} from "@features/project/designer/utils/EventBus"; import {useSearchStore} from "@stores/SearchStore"; import {RenameFileModal} from "@features/project/RenameFileModal"; -import {DashboardDevelopmentHook} from "@features/dashboard/development/DashboardDevelopmentHook"; import {FileCopyForEnvModal} from "@features/project/files/FileCopyForEnvModal"; import {CamelUtil} from "@core/api/CamelUtil"; import {download, getIcon, sortFiles} from "@features/project/files/FilesTabUtils"; @@ -55,8 +54,6 @@ export function FilesSubTab(props: FilesSubTabProps) { const [showRename, setShowRename] = useState<boolean>(false); const [missingEnvs, setMissingEnvs] = useState<string[]>([]); - const {getProjectFileValidationIcon} = DashboardDevelopmentHook(); - const filenames = files.map(f => f.name); const deletedFilenames: string[] = Object.getOwnPropertyNames(diff) .map(name => diff[name] === 'DELETED' ? name : '') @@ -201,7 +198,6 @@ export function FilesSubTab(props: FilesSubTabProps) { const hasRouteTemplate = CamelUtil.hasRouteTemplateDefinitions(file); const missEnvs = getMissingEnvs(file.name); const canBeRenamed = !isInfra && !BUILD_IN_FILES.includes(file.name); - const validationIcon = getProjectFileValidationIcon(file.projectId, file.name); const commitTime = commitedFiles?.find(f => f.name === file.name)?.commitTime; const timeAgo = new TimeAgo('en-US') return ( @@ -234,7 +230,6 @@ export function FilesSubTab(props: FilesSubTabProps) { }}> {prefix[2]} </Button> - {validationIcon} </div> </Td> <Td modifier={"fitContent"} style={{textAlign: "right"}}> diff --git a/karavan-app/src/main/webui/src/ui/features/project/files/FilesToolbar.tsx b/karavan-app/src/main/webui/src/ui/features/project/files/FilesToolbar.tsx index 9ee409fe..0bc769f6 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/files/FilesToolbar.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/files/FilesToolbar.tsx @@ -31,13 +31,10 @@ import {FileSearchToolbarItem} from "@features/project/FileSearchToolbarItem"; import TimeAgo from "javascript-time-ago"; import {useCommitsStore} from "@stores/CommitsStore"; import {BUILD_IN_PROJECTS} from "@models/ProjectModels"; -import {CheckIcon} from "@patternfly/react-icons"; -import {useValidationStore} from "@stores/ValidationStore"; export function FilesToolbar() { const {fetchProjectCommits} = useCommitsStore(); - const {validateProject} = useValidationStore(); const [config] = useAppConfigStore((s) => [s.config], shallow); const [project, isPushing, isPulling] = useProjectStore((s) => [s.project, s.isPushing, s.isPulling], shallow) const [projectsCommited] = useProjectsStore((s) => [s.projectsCommited], shallow) @@ -178,10 +175,6 @@ export function FilesToolbar() { })} </ToggleGroup> - function validate() { - validateProject(project.projectId); - } - function onRefresh() { if (isCommitsTab) { fetchProjectCommits(project.projectId); @@ -197,10 +190,6 @@ export function FilesToolbar() { <div className="project-files-toolbar"> <ProjectTitle/> {toggle} - <Button icon={<CheckIcon/>} - variant={"link"} - onClick={() => validate()} - /> <Button icon={<RefreshIcon/>} variant={"link"} onClick={() => onRefresh()} diff --git a/karavan-app/src/main/webui/src/ui/features/project/project-topology/CustomNode.tsx b/karavan-app/src/main/webui/src/ui/features/project/project-topology/CustomNode.tsx index 873e1494..4e0286b1 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/project-topology/CustomNode.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/project-topology/CustomNode.tsx @@ -7,12 +7,10 @@ import '@features/project/project-topology/topology.css'; import {RouteDefinition} from "@core/model/CamelDefinition"; import {AutoStartupFalseIcon, ErrorHandlerIcon} from "@features/project/designer/icons/OtherIcons"; import {CustomNodeMetricAttachment} from "@features/project/project-topology/CustomNodeMetricAttachment"; -import {DashboardDevelopmentHook} from "@features/dashboard/development/DashboardDevelopmentHook"; import {runInAction} from "mobx"; import {SvgIcon} from "@shared/icons/SvgIcon"; import {useTopologyHook} from "@features/project/project-topology/useTopologyHook"; import {Category, IntentRequestScaleIn, IntentRequestScaleOut} from "@carbon/icons-react"; -import {GENERATED_FILENAME_PREFIX} from "@models/CatalogModels"; function getIcon(data: any) { if (['route'].includes(data.icon)) { @@ -130,7 +128,6 @@ function getAttachments(data: any) { const CustomNode: React.FC<any & WithContextMenuProps> = observer(({element, onContextMenu, contextMenuOpen, selected, ...rest}) => { const {selectFile, project} = useTopologyHook(undefined); - const {getProjectFileValidationIcon} = DashboardDevelopmentHook(); const data = element.getData(); const badge: string = ['API', 'RT', 'TR'].includes(data.badge) ? data.badge : data.badge?.substring(0, 1).toUpperCase(); let colorClass = 'route'; @@ -148,8 +145,6 @@ const CustomNode: React.FC<any & WithContextMenuProps> = observer(({element, onC } const disableClass = isDisable(data) ? 'disable-node' : ''; - const labelIcon = data.type === 'route' ? getProjectFileValidationIcon(project.projectId, data.fileName) : undefined; - const { x, y } = getDefaultShapeDecoratorCenter("lowerRight" as TopologyQuadrant, element); const decorator = ( @@ -164,11 +159,6 @@ const CustomNode: React.FC<any & WithContextMenuProps> = observer(({element, onC ); - const showDecorator = data.type === 'route' && data.fileName?.startsWith(GENERATED_FILENAME_PREFIX); - const isMasGenerated = data.isMasGenerated; - const gemsClass = isMasGenerated ? " gems-generated" : ""; - colorClass = showDecorator ? 'gen-route' : colorClass; - return ( <g onDoubleClick={event => { event.stopPropagation(); @@ -176,20 +166,18 @@ const CustomNode: React.FC<any & WithContextMenuProps> = observer(({element, onC }}> <DefaultNode showStatusDecorator - className={"common-node common-node-" + badge + " topology-color-" + colorClass + " " + disableClass + gemsClass} + className={"common-node common-node-" + badge + " topology-color-" + colorClass + " " + disableClass} scaleLabel={true} element={element} onContextMenu={onContextMenu} contextMenuOpen={contextMenuOpen} attachments={getAttachments(data)} hideContextMenuKebab={false} - labelIcon={labelIcon} labelIconPadding={1} label={label} {...rest} > {getIcon(data)} - {showDecorator && decorator} </DefaultNode> </g> ) diff --git a/karavan-app/src/main/webui/src/ui/features/project/project-topology/TopologyToolbar.tsx b/karavan-app/src/main/webui/src/ui/features/project/project-topology/TopologyToolbar.tsx index 3c97b1aa..63dc87dc 100644 --- a/karavan-app/src/main/webui/src/ui/features/project/project-topology/TopologyToolbar.tsx +++ b/karavan-app/src/main/webui/src/ui/features/project/project-topology/TopologyToolbar.tsx @@ -8,16 +8,13 @@ import {useRouteDesignerHook} from "@features/project/designer/route/useRouteDes import {APPLICATION_PROPERTIES, DOCKER_COMPOSE, DOCKER_STACK} from "@models/ProjectModels"; import {ProjectTitle} from "@features/project/ProjectTitle"; import {useProjectFunctions} from "@features/project/ProjectContext"; -import {CheckIcon, CogIcon, DockerIcon, EllipsisVIcon} from "@patternfly/react-icons"; +import {CogIcon, DockerIcon, EllipsisVIcon} from "@patternfly/react-icons"; import {AddLarge} from "@carbon/icons-react"; -import {DashboardDevelopmentHook} from "@features/dashboard/development/DashboardDevelopmentHook"; -import {useValidationStore} from "@stores/ValidationStore"; import {KubernetesIcon} from "@features/project/designer/icons/ComponentIcons"; export function TopologyToolbar() { const [config] = useAppConfigStore((s) => [s.config], shallow); - const {validateProject} = useValidationStore(); const isDev = config.environment === 'dev'; const { @@ -30,10 +27,6 @@ export function TopologyToolbar() { } = useProjectFunctions(); const {openSelector} = useRouteDesignerHook(); - const {getProjectValidationIcon, getProjectValidationStatus} = DashboardDevelopmentHook(); - const validationStatus = getProjectValidationStatus(project.projectId) - const validationIcon = getProjectValidationIcon(project.projectId) - const [isOpen, setIsOpen] = useState(false); const onToggleClick = () => { @@ -156,7 +149,6 @@ export function TopologyToolbar() { <ProjectTitle/> </div> {primaryButtons} - {getButton("Validate", 'secondary', <CheckIcon/>, event => validateProject(project.projectId), validationStatus === false)} {dropDown} </div> ) diff --git a/karavan-app/src/main/webui/src/ui/features/projects/ProjectsTableRow.tsx b/karavan-app/src/main/webui/src/ui/features/projects/ProjectsTableRow.tsx index 87daae5e..ddeed992 100644 --- a/karavan-app/src/main/webui/src/ui/features/projects/ProjectsTableRow.tsx +++ b/karavan-app/src/main/webui/src/ui/features/projects/ProjectsTableRow.tsx @@ -14,7 +14,6 @@ import TimeAgo from 'javascript-time-ago' import en from 'javascript-time-ago/locale/en' import {ROUTES} from "@app/navigation/Routes"; import {ProjectStatusLabel} from "@features/projects/ProjectStatusLabel"; -import {DashboardDevelopmentHook} from "@features/dashboard/development/DashboardDevelopmentHook"; import {ComplexityProject} from "@features/projects/ComplexityModels"; import {ProjectZipApi} from "@features/projects/ProjectZipApi"; import {ProjectsTableRowComplexity} from "@features/projects/ProjectsTableRowComplexity"; @@ -37,7 +36,6 @@ interface Props { function ProjectsTableRow(props: Props) { const {project, complexity, activeUsers, labels, selectedLabels, onLabelClick, projectCommited} = props; - const {getProjectValidationIcon} = DashboardDevelopmentHook(); const [deployments] = useStatusesStore((state) => [state.deployments], shallow) const {containers} = useContainerStatusesStore(); const {config} = useAppConfigStore(); @@ -46,7 +44,6 @@ function ProjectsTableRow(props: Props) { const timeAgo = new TimeAgo('en-US') const isBuildIn = BUILD_IN_PROJECTS.includes(project.projectId); - const validationIcon = getProjectValidationIcon(project.projectId); function getEnvironments(): string [] { return config.environments && Array.isArray(config.environments) ? Array.from(config.environments) : []; @@ -69,7 +66,6 @@ function ProjectsTableRow(props: Props) { }}> {project.projectId} </Button> - {validationIcon} </Td> <Td> <div style={{display: 'flex', flexDirection: 'column', alignItems: 'start', justifyContent: 'start', gap: '3px'}}> diff --git a/karavan-app/src/main/webui/src/ui/models/ValidationModels.ts b/karavan-app/src/main/webui/src/ui/models/ValidationModels.ts deleted file mode 100644 index 81ea9913..00000000 --- a/karavan-app/src/main/webui/src/ui/models/ValidationModels.ts +++ /dev/null @@ -1,12 +0,0 @@ -export class ProjectValidation { - projectId: string = ''; - lastValidate: number = 0; - files: ProjectFileValidation[] = []; - hasErrors: boolean = false; -} - -export class ProjectFileValidation { - name: string = ''; - errors: any[] = []; - hasErrors: boolean = false; -} diff --git a/karavan-app/src/main/webui/src/ui/stores/ValidationStore.ts b/karavan-app/src/main/webui/src/ui/stores/ValidationStore.ts deleted file mode 100644 index 393fbbf0..00000000 --- a/karavan-app/src/main/webui/src/ui/stores/ValidationStore.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {createWithEqualityFn} from "zustand/traditional"; -import {shallow} from "zustand/shallow"; -import {ProjectValidation} from "@models/ValidationModels"; -import isEqual from "lodash/isEqual"; -import {ValidationApi} from "@api/ValidationApi"; - -interface ValidationState { - validations: ProjectValidation[]; - fetchValidations: () => Promise<void>; - validateProject: (projectId: string) => Promise<void>; - validateProjectFile: (projectId: string, filename: string) => Promise<void> -} - -export const useValidationStore = createWithEqualityFn<ValidationState>((set, get) => ({ - validations: [], - fetchValidations: async (): Promise<void> => { - const currentValidations = get().validations; - await new Promise<ProjectValidation[]>((resolve) => { - ValidationApi.getAllProjectValidations(resolve); - }).then(validations=> { - if (!isEqual(currentValidations, validations)) { - set({validations: validations}); - } - }) - }, - validateProject: async (projectId: string): Promise<void> => { - ValidationApi.validateProject(projectId, () => { - setTimeout(() => { - get().fetchValidations(); - }, 3000); - }); - }, - validateProjectFile: async (projectId: string, filename: string): Promise<void> => { - ValidationApi.validateProjectFile(projectId, filename, () => { - setTimeout(() => { - get().fetchValidations(); - }, 1000); - }); - }, -}), shallow)
