diff --git a/Taskfile.yaml b/Taskfile.yaml index bdac9c97d..41360ec3b 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -8,7 +8,7 @@ tasks: interactive: true cmds: - | - BASE_URL=gcp-production.kloudlite.io + BASE_URL=dev.kloudlite.io COOKIE_DOMAIN=".kloudlite.io" GATEWAY_URL="http://gateway.kloudlite.svc.cluster.local" case {{.app}} in @@ -159,7 +159,7 @@ tasks: msg: "var tag must have a value" silent: true vars: - IMAGE: ghcr.io/kloudlite/platform/web/{{.app}}-web:{{.tag}} + IMAGE: ghcr.io/kloudlite/kloudlite/web/{{.app}}:{{.tag}} cmds: - docker build --build-arg APP={{.app}} . -t {{.IMAGE}} - docker push {{.IMAGE}} diff --git a/gql-queries-generator/doc/queries.graphql b/gql-queries-generator/doc/queries.graphql index 0413536dc..786184517 100644 --- a/gql-queries-generator/doc/queries.graphql +++ b/gql-queries-generator/doc/queries.graphql @@ -255,6 +255,7 @@ query consoleListClusters($search: SearchCluster, $pagination: CursorPaginationI edges { cursor node { + id displayName markedForDeletion metadata { @@ -2006,6 +2007,10 @@ mutation consoleDeleteBuild($crDeleteBuildId: ID!) { cr_deleteBuild(id: $crDeleteBuildId) } +mutation consoleTriggerBuild($crTriggerBuildId: ID!) { + cr_triggerBuild(id: $crTriggerBuildId) +} + query consoleListBuildCaches($pq: CursorPaginationIn, $search: SearchBuildCacheKeys) { cr_listBuildCacheKeys(pq: $pq, search: $search) { edges { diff --git a/lib/app-setup/root.tsx b/lib/app-setup/root.tsx index 29776665e..e007db562 100644 --- a/lib/app-setup/root.tsx +++ b/lib/app-setup/root.tsx @@ -1,4 +1,4 @@ -import { HeadersFunction } from '@remix-run/node'; +import { HeadersFunction, LinksFunction } from '@remix-run/node'; import { Link, Links, @@ -21,7 +21,6 @@ import Container from '~/components/atoms/container'; import ProgressContainer, { useProgress, } from '~/components/atoms/progress-bar'; -// import { SelectPortalContainer } from '~/components/atoms/select'; import Tooltip from '~/components/atoms/tooltip'; import { BrandLogo } from '~/components/branding/brand-logo'; import { ToastContainer } from '~/components/molecule/toast'; @@ -30,10 +29,12 @@ import styleZenerSelect from '@oshq/react-select/index.css'; import stylesUrl from '~/design-system/index.css'; import rcss from 'react-highlightjs-logs/dist/index.css'; import tailwindBase from '~/design-system/tailwind-base.js'; -import { isDev } from '../client/helpers/log'; +import { ReloadIndicator } from '~/lib/client/components/reload-indicator'; +import { isDev } from '~/lib/client/helpers/log'; import { getClientEnv, getServerEnv } from '../configs/base-url.cjs'; +import { useDataFromMatches } from '../client/hooks/use-custom-matches'; -export const links = () => [ +export const links: LinksFunction = () => [ { rel: 'stylesheet', href: stylesUrl }, { rel: 'stylesheet', href: reactToast }, { rel: 'stylesheet', href: skeletonCSS }, @@ -41,6 +42,11 @@ export const links = () => [ { rel: 'stylesheet', href: styleReactPulsable }, { rel: 'stylesheet', href: styleZenerSelect }, { rel: 'stylesheet', href: rcss }, + { + rel: 'stylesheet', + href: 'https://fonts.googleapis.com/css2?family=Familjen+Grotesk:ital,wght@0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap', + }, + { rel: 'stylesheet', href: 'https://rsms.me/inter/inter.css' }, ]; export const ErrorWrapper = ({ children, message }: any) => { @@ -160,6 +166,8 @@ const Root = ({ }) => { const env = useLoaderData(); + const error = useDataFromMatches('error', ''); + return ( @@ -197,11 +205,16 @@ const Root = ({ + - - - + {error ? ( +
{JSON.stringify(error)}
+ ) : ( + + + + )}
diff --git a/lib/client/components/logger/index.tsx b/lib/client/components/logger/index.tsx index f38e92fc9..f85dd9a34 100644 --- a/lib/client/components/logger/index.tsx +++ b/lib/client/components/logger/index.tsx @@ -15,7 +15,7 @@ import React, { useRef, useState, } from 'react'; -import { ViewportList } from 'react-viewport-list'; +import { ViewportList, ViewportListRef } from 'react-viewport-list'; import { dayjs } from '~/components/molecule/dayjs'; import { ISearchInfProps, @@ -28,6 +28,7 @@ import { generatePlainColor } from '~/root/lib/utils/color-generator'; import ReactPulsable from 'react-pulsable'; import { ChildrenProps } from '~/components/types'; import { logsMockData } from './dummy'; +import { LoadingIndicator } from '../reload-indicator'; const pulsableContext = createContext(false); @@ -94,7 +95,7 @@ interface IHighlightIt { const LoadingComp = memo(() => ( -
+
Logs
@@ -123,7 +124,7 @@ const LoadingComp = memo(() => ( const log = logsMockData[Math.floor(Math.random() * 10)]; return (
-
+
{log}
); @@ -499,22 +500,14 @@ const LogBlock = ({ const [showAll, setShowAll] = useState(true); - const ref = useRef(null); + const ref = useRef(null); useEffect(() => { - (async () => { - if ( - follow && - ref.current && - // @ts-ignore - typeof ref.current.scrollToIndex === 'function' - ) { - // @ts-ignore - ref.current.scrollToIndex({ - index: data.length - 1, - }); - } - })(); + if (follow && ref.current) { + ref.current.scrollToIndex({ + index: data.length - 1, + }); + } }, [data, maxLines]); return ( @@ -575,13 +568,8 @@ const LogBlock = ({
- + {(log, index) => { return ( (null); + + const getFullWidthInPx = () => { + if (wRef.current) { + return wRef.current.clientWidth; + } + return '100%'; + }; + return isClientSide ? (
@@ -736,11 +738,13 @@ const LogComp = ({
+ +
)} - {!subscribed && logs.length === 0 && } + {isLoading && } {errors.length ? (
{JSON.stringify(errors)}
diff --git a/lib/client/components/reload-indicator.tsx b/lib/client/components/reload-indicator.tsx new file mode 100644 index 000000000..c55a342d5 --- /dev/null +++ b/lib/client/components/reload-indicator.tsx @@ -0,0 +1,37 @@ +import { CircleFill, CircleNotch } from '@jengaicons/react'; +import { useRevalidator } from '@remix-run/react'; +import { cn } from '~/components/utils'; + +export const LoadingIndicator = ({ + className, + size = 1, +}: { + className?: string; + size?: number; +}) => { + return ( +
+ + +
+ ); +}; + +export const ReloadIndicator = () => { + const { state } = useRevalidator(); + + if (state === 'loading') { + return ( +
+ +
+ ); + } + + return null; +}; diff --git a/lib/client/helpers/log.ts b/lib/client/helpers/log.ts index e3cc635c7..ed4525f45 100644 --- a/lib/client/helpers/log.ts +++ b/lib/client/helpers/log.ts @@ -1,15 +1,12 @@ -// import axios from 'axios'; -// import { consoleBaseUrl } from '../../configs/base-url.cjs'; import { serverError } from '../../server/helpers/server-error'; -// import { parseError } from '../../utils/common'; const getNodeEnv = () => { const env = (() => { if (typeof window !== 'undefined') { // @ts-ignore - return window.ENV; + return window.NODE_ENV; } - return process.env.ENV; + return process.env.NODE_ENV; })(); if (env) { @@ -19,43 +16,6 @@ const getNodeEnv = () => { return 'development'; }; -/* eslint-disable no-unused-vars */ -/* eslint-disable @typescript-eslint/no-unused-vars */ -export const PostErr = async (message: string, source: string) => { - // try { - // await axios.post( - // 'https://hooks.slack.com/services/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', - // { - // body: { - // channel: source === 'server' ? '#bugs' : '#web-errors', - // username: - // typeof window === 'undefined' ? 'server-error' : 'web-error', - // text: message, - // icon_emoji: ':ghost:', - // }, - // } - // ); - // } catch (err) { - // console.log(parseError(err).message); - // } - return {}; -}; - -const PostToHook = (message: string) => { - // if (typeof window === 'undefined') { - // return PostErr(message, 'server'); - // } - // - // try { - // axios.post(`${consoleBaseUrl}/api/error`, { - // body: { error: message }, - // }); - // } catch (err) { - // console.log(err); - // } - return {}; -}; - export const isDev = getNodeEnv() === 'development'; const logger = { @@ -63,8 +23,6 @@ const logger = { timeEnd: isDev ? console.timeEnd : () => {}, log: isDev ? console.log : () => {}, - // log: console.log, - warn: console.warn, trace: (...args: any[]) => { let err; @@ -90,14 +48,16 @@ const logger = { } if (err) { - console.trace(err); if (!isDev) { - PostToHook(`\`\`\`${err}\`\`\``); + console.trace(`\n\n${args}\n\n`); + return; } - } else { - console.trace(args); + console.error(`\n\n${err}\n\n`); + return; } + console.trace(`\n\n${args}\n\n`); + if (isDev && typeof window === 'undefined') { serverError(args); } diff --git a/lib/client/helpers/reloader.ts b/lib/client/helpers/reloader.ts index d4ea4ea3e..5d6cac682 100644 --- a/lib/client/helpers/reloader.ts +++ b/lib/client/helpers/reloader.ts @@ -1,9 +1,9 @@ -import { useLocation, useNavigate } from '@remix-run/react'; +import { useRevalidator } from '@remix-run/react'; export const useReload = () => { - const location = useLocation(); - const navigate = useNavigate(); + const revalidator = useRevalidator(); + return () => { - navigate(location.pathname + location.search, { replace: true }); + revalidator.revalidate(); }; }; diff --git a/lib/client/helpers/socket/context.tsx b/lib/client/helpers/socket/context.tsx index 0fbbc6045..07c66fecb 100644 --- a/lib/client/helpers/socket/context.tsx +++ b/lib/client/helpers/socket/context.tsx @@ -62,8 +62,8 @@ export const useSubscribe = ( const { sendMsg, responses, - infos: i, - errors: e, + infos: mInfos, + errors: mErrors, clear, } = useContext(Context); @@ -85,9 +85,10 @@ export const useSubscribe = ( const m = msg[k]; tr.push(...(responses[m.for]?.[m.data.id || 'default'] || [])); - terr.push(...(e[m.for]?.[m.data.id || 'default'] || [])); - ti.push(...(i[m.for]?.[m.data.id || 'default'] || [])); + terr.push(...(mErrors[m.for]?.[m.data.id || 'default'] || [])); + ti.push(...(mInfos[m.for]?.[m.data.id || 'default'] || [])); } + setResp(tr); setErrors(terr); setInfos(ti); @@ -97,20 +98,23 @@ export const useSubscribe = ( } return; } + const tempResp = responses[msg.for]?.[msg.data.id || 'default'] || []; + setResp(tempResp); + + setErrors(mErrors[msg.for]?.[msg.data.id || 'default'] || []); - setResp(responses[msg.for]?.[msg.data.id || 'default'] || []); - setErrors(e[msg.for]?.[msg.data.id || 'default'] || []); - setInfos(i[msg.for]?.[msg.data.id || 'default'] || []); + const tempInfo = mInfos[msg.for]?.[msg.data.id || 'default'] || []; + setInfos(tempInfo); - if (resp.length || i[msg.for]?.[msg.data.id || 'default']?.length) { + if (tempResp.length || tempInfo.length) { setSubscribed(true); } })(); - }, [responses]); + }, [responses, mInfos, mErrors]); useDebounce( () => { - console.log('subscribing'); + logger.log('subscribing'); if (Array.isArray(msg)) { msg.forEach((m) => { sendMsg({ ...m, data: { ...m.data, event: 'subscribe' } }); @@ -120,7 +124,7 @@ export const useSubscribe = ( } return () => { - console.log('unsubscribing'); + logger.log('unsubscribing'); if (Array.isArray(msg)) { msg.forEach((m) => { clear(m); @@ -236,7 +240,7 @@ export const SockProvider = ({ children }: ChildrenProps) => { }; w.onerror = (e) => { - console.error(e); + console.error('socket closed:', e); if (!rejected) { rejected = true; rej(e); @@ -249,7 +253,7 @@ export const SockProvider = ({ children }: ChildrenProps) => { } }); } catch (e) { - console.log(e); + logger.error(e); } } }, diff --git a/lib/client/helpers/socket/useSockLogs.tsx b/lib/client/helpers/socket/useSockLogs.tsx index 81e28e5cc..b1831166f 100644 --- a/lib/client/helpers/socket/useSockLogs.tsx +++ b/lib/client/helpers/socket/useSockLogs.tsx @@ -11,7 +11,7 @@ interface IuseLog { export const useSocketLogs = ({ account, cluster, trackingId }: IuseLog) => { const [logs, setLogs] = useState[]>([]); - const { responses, subscribed, errors } = useSubscribe( + const { responses, infos, subscribed, errors } = useSubscribe( { for: 'logs', data: { @@ -26,16 +26,6 @@ export const useSocketLogs = ({ account, cluster, trackingId }: IuseLog) => { [] ); - const [isLoading, setIsLoading] = useState(true); - - useEffect(() => { - if (subscribed && isLoading) { - setIsLoading(false); - } else if (!subscribed && !isLoading) { - setIsLoading(true); - } - }, []); - useEffect(() => { const sorted = responses.sort((a, b) => { const resp = b.data.podName.localeCompare(a.data.podName); @@ -55,7 +45,7 @@ export const useSocketLogs = ({ account, cluster, trackingId }: IuseLog) => { return { logs, errors, - isLoading, + isLoading: !subscribed && (logs.length === 0 || infos.length === 0), subscribed, }; }; diff --git a/lib/client/helpers/socket/useWatch.tsx b/lib/client/helpers/socket/useWatch.tsx index 067c896dd..a47f2b5e5 100644 --- a/lib/client/helpers/socket/useWatch.tsx +++ b/lib/client/helpers/socket/useWatch.tsx @@ -34,7 +34,7 @@ export const useSocketWatch = ( onUpdate(responses); } }, - 1000, + 3000, [responses] ); }; diff --git a/lib/client/hooks/use-custom-loader-data.tsx b/lib/client/hooks/use-custom-loader-data.tsx new file mode 100644 index 000000000..40ca49199 --- /dev/null +++ b/lib/client/hooks/use-custom-loader-data.tsx @@ -0,0 +1,10 @@ +import { useLoaderData } from '@remix-run/react'; + +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( + k: infer I +) => void + ? I + : never; + +export const useExtLoaderData = Promise>() => + useLoaderData() as UnionToIntersection>>; diff --git a/lib/server/helpers/execute-query-with-context.ts b/lib/server/helpers/execute-query-with-context.ts index 91f24e7da..43eea48a6 100644 --- a/lib/server/helpers/execute-query-with-context.ts +++ b/lib/server/helpers/execute-query-with-context.ts @@ -112,12 +112,12 @@ export const ExecuteQueryWithContext = ( return { ...resp.data, data }; } catch (err) { if ((err as AxiosError).response) { - console.trace('ErrorIn:', apiName, (err as Error).name); + console.log('\nErrorIn:', apiName, (err as Error).name, '\n'); return (err as AxiosError).response?.data; } - console.trace('ErrorIn:', apiName, (err as Error).message); + console.log('\nErrorIn:', apiName, (err as Error).message, '\n'); return { data: null, diff --git a/lib/utils/common.tsx b/lib/utils/common.tsx index fb71ad287..38469880d 100644 --- a/lib/utils/common.tsx +++ b/lib/utils/common.tsx @@ -1,10 +1,27 @@ import { toast } from '~/components/molecule/toast'; import logger from '../client/helpers/log'; -export const handleError = (e: unknown): void => { +export const handleError = ( + e: unknown +): { + error?: { + message: string; + }; +} => { const err = e as Error; + + if (typeof window === 'undefined') { + return { + error: { + message: err.message, + }, + }; + } + toast.error(err.message); logger.error(e); + + return {}; }; export const parseError = (e: unknown): Error => { @@ -27,8 +44,9 @@ export const Truncate = ({ }; export function sleep(time: number) { - // eslint-disable-next-line no-promise-executor-return - return new Promise((resolve) => setTimeout(resolve, time)); + return new Promise((resolve) => { + setTimeout(resolve, time); + }); } export const anyUndefined: any = undefined; diff --git a/src/apps/auth/routes/_main+/logout.tsx b/src/apps/auth/routes/_main+/logout.tsx index 6d06933d7..ecea7e1a8 100644 --- a/src/apps/auth/routes/_main+/logout.tsx +++ b/src/apps/auth/routes/_main+/logout.tsx @@ -1,19 +1,34 @@ -import { getCookie } from '~/root/lib/app-setup/cookies'; -import withContext from '~/root/lib/app-setup/with-contxt'; -import { useNavigate, useLoaderData } from '@remix-run/react'; -import { useEffect } from 'react'; +import { useNavigate } from '@remix-run/react'; import { BrandLogo } from '~/components/branding/brand-logo'; -import { IExtRemixCtx } from '~/root/lib/types/common'; +import { handleError, sleep } from '~/root/lib/utils/common'; +import { useAuthApi } from '~/auth/server/gql/api-provider'; +import { toast } from 'react-toastify'; +import useDebounce from '~/root/lib/client/hooks/use-debounce'; const LogoutPage = () => { const navigate = useNavigate(); - const { done } = useLoaderData(); + const api = useAuthApi(); - useEffect(() => { - if (done) { - navigate('/'); - } - }, [done]); + useDebounce( + () => { + (async () => { + try { + const { errors } = await api.logout({}); + if (errors) { + throw errors[0]; + } + + toast.warn('Logged out successfully'); + await sleep(1000); + navigate('/login'); + } catch (error) { + handleError(error); + } + })(); + }, + 1000, + [] + ); return (
@@ -22,21 +37,4 @@ const LogoutPage = () => { ); }; -export const loader = async (ctx: IExtRemixCtx) => { - const cookie = getCookie(ctx); - - const keys = Object.keys(cookie.getAll()); - - for (let i = 0; i < keys.length; i += 1) { - const key = keys[i]; - if (key === 'hotspot-session') { - cookie.remove(key); - } - } - - return withContext(ctx, { - done: 'true', - }); -}; - export default LogoutPage; diff --git a/src/apps/auth/routes/_main+/verify-email.tsx b/src/apps/auth/routes/_main+/verify-email.tsx index c34b6e724..b85459f96 100644 --- a/src/apps/auth/routes/_main+/verify-email.tsx +++ b/src/apps/auth/routes/_main+/verify-email.tsx @@ -46,6 +46,7 @@ const VerifyEmail = () => { (async () => { try { if (!email) { + // TODO: handle this case, by taking email from user toast.error('Something went wrong! Please try again.'); return; } @@ -137,8 +138,9 @@ export const loader = async (ctx: IRemixCtx) => { const query = getQueries(ctx); const { data, errors } = await GQLServerHandler(ctx.request).whoAmI(); if (errors) { - console.error(errors[0].message); - return redirect('/'); + return { + query, + }; } const { email, verified } = data || {}; diff --git a/src/apps/console/components/commons.tsx b/src/apps/console/components/commons.tsx index 5dde3b8f5..30764ecd3 100644 --- a/src/apps/console/components/commons.tsx +++ b/src/apps/console/components/commons.tsx @@ -1,21 +1,21 @@ -import { CopySimple, Question } from "@jengaicons/react"; -import { ReactNode, useState } from "react"; -import { ProdLogo } from "~/components/branding/prod-logo"; -import { WorkspacesLogo } from "~/components/branding/workspace-logo"; -import useClipboard from "~/root/lib/client/hooks/use-clipboard"; -import { generateKey, titleCase } from "~/components/utils"; +import { CopySimple, Question } from '@jengaicons/react'; +import { ReactNode, useState } from 'react'; +import { ProdLogo } from '~/components/branding/prod-logo'; +import { WorkspacesLogo } from '~/components/branding/workspace-logo'; +import useClipboard from '~/root/lib/client/hooks/use-clipboard'; +import { generateKey, titleCase } from '~/components/utils'; import { Github__Com___Kloudlite___Api___Pkg___Types__SyncState as SyncState, Github__Com___Kloudlite___Api___Pkg___Types__SyncAction as SyncAction, -} from "~/root/src/generated/gql/server"; -import Tooltip from "~/components/atoms/tooltip"; -import { Link } from "@remix-run/react"; -import { Button, IButton } from "~/components/atoms/button"; -import { ListItem } from "./console-list-components"; +} from '~/root/src/generated/gql/server'; +import Tooltip from '~/components/atoms/tooltip'; +import { Link } from '@remix-run/react'; +import { Button, IButton } from '~/components/atoms/button'; +import { ListItem } from './console-list-components'; import { parseUpdateOrCreatedBy, parseUpdateOrCreatedOn, -} from "../server/r-utils/common"; +} from '../server/r-utils/common'; import { ArrowLeft, ArrowRight, @@ -23,8 +23,8 @@ import { GitBranchFill, GitlabLogoFill, GithubLogoFill, -} from "./icons"; -import { IGIT_PROVIDERS } from "../hooks/use-git"; +} from './icons'; +import { IGIT_PROVIDERS } from '../hooks/use-git'; export const BlackProdLogo = ({ size = 16 }) => { return ; @@ -129,7 +129,7 @@ interface IUpdateMeta { } // Component for Status parsing -export type IStatus = "deleting" | "notready" | "syncing" | "none"; +export type IStatus = 'deleting' | 'notready' | 'syncing' | 'none'; interface IStatusMeta { markedForDeletion?: boolean; @@ -145,17 +145,17 @@ interface IStatusMeta { }; } -type IResourceType = "nodepool"; +type IResourceType = 'nodepool' | 'cluster'; type ICommonMeta = IUpdateMeta & IStatusMeta; const parseStatusComponent = ({ status }: { status: IStatus }) => { switch (status) { - case "deleting": + case 'deleting': return
Deleting...
; - case "notready": + case 'notready': return
Not Ready
; - case "syncing": + case 'syncing': return
Syncing
; default: return null; @@ -169,17 +169,17 @@ export const parseStatus = ({ item: IStatusMeta; type?: IResourceType; }) => { - let status: IStatus = "none"; + let status: IStatus = 'none'; if (item.markedForDeletion) { - status = "deleting"; + status = 'deleting'; } else if (!item.status?.isReady) { switch (type) { - case "nodepool": - status = "syncing"; + case 'nodepool': + status = 'syncing'; break; default: - status = "notready"; + status = 'notready'; } } @@ -200,7 +200,7 @@ export const listRender = ({ time: parseUpdateOrCreatedOn(resource), }; return { - key: generateKey(keyPrefix, "author"), + key: generateKey(keyPrefix, 'author'), className, render: () => ( @@ -215,7 +215,7 @@ export const listRender = ({ type?: IResourceType; }) => { return { - key: generateKey(keyPrefix, "status"), + key: generateKey(keyPrefix, 'status'), className, render: () => parseStatus({ item: resource, type }).component, status: parseStatus({ item: resource, type }).status, @@ -249,8 +249,8 @@ export const BottomNavigation = ({ primaryButton, secondaryButton, }: { - primaryButton?: Optional; - secondaryButton?: Optional; + primaryButton?: Optional; + secondaryButton?: Optional; }) => { return (
@@ -283,7 +283,7 @@ interface IReviewComponent { canEdit?: boolean; } export const ReviewComponent = ({ - title = "", + title = '', children, onEdit, canEdit = true, @@ -327,13 +327,13 @@ export const GitDetail = ({
Source
- {provider === "github" ? ( + {provider === 'github' ? ( ) : ( )} - {repository.replace("https://", "").replace(".git", "")} + {repository.replace('https://', '').replace('.git', '')}
diff --git a/src/apps/console/components/git.tsx b/src/apps/console/components/git.tsx index 649e9332b..07591ddd2 100644 --- a/src/apps/console/components/git.tsx +++ b/src/apps/console/components/git.tsx @@ -63,7 +63,7 @@ const githubInstallUrl = `https://github.com/apps/${githubAppName}/installations const popupWindow = ({ url = '', - onClose = () => { }, + onClose = () => {}, width = 800, height = 500, title = 'kloudlite', @@ -71,7 +71,8 @@ const popupWindow = ({ const frame = window.open( url, title, - `toolbar=no,scrollbars=yes,resizable=no,top=${window.screen.height / 2 - height / 2 + `toolbar=no,scrollbars=yes,resizable=no,top=${ + window.screen.height / 2 - height / 2 },left=${window.screen.width / 2 - width / 2},width=800,height=600` ); const interval = setInterval(() => { @@ -90,8 +91,8 @@ interface IBranch { interface IListRenderer { data: - | { name: string; updatedAt: any; private: true; url: string }[] - | undefined; + | { name: string; updatedAt: any; private: true; url: string }[] + | undefined; onChange: (value: string) => void; value: string; isLoading?: boolean; diff --git a/src/apps/console/components/icons.tsx b/src/apps/console/components/icons.tsx index 6bd74f5c6..cfc21e06a 100644 --- a/src/apps/console/components/icons.tsx +++ b/src/apps/console/components/icons.tsx @@ -4,6 +4,7 @@ export { Plus, Trash, PencilLine as Pencil, + PencilSimple, GithubLogoFill, GitlabLogoFill, GitBranchFill, @@ -23,6 +24,7 @@ export { MinusCircle, Search, ArrowsCounterClockwise, + ArrowClockwise, Copy, GearSix, QrCode, diff --git a/src/apps/console/components/listV2.tsx b/src/apps/console/components/listV2.tsx index 28bb13995..29d256311 100644 --- a/src/apps/console/components/listV2.tsx +++ b/src/apps/console/components/listV2.tsx @@ -1,6 +1,7 @@ import * as RovingFocusGroup from '@radix-ui/react-roving-focus'; import { KeyboardEvent, ReactNode, useRef } from 'react'; import { cn } from '~/components/utils'; +import logger from '~/root/lib/client/helpers/log'; import { LoadingPlaceHolder } from './loading'; const focusableElement = 'a[href], button, input, select, textarea'; @@ -77,7 +78,7 @@ const handleKeyNavigation = ( } } } catch { - console.log('Error focusing'); + logger.error('Error focusing'); } }; @@ -224,7 +225,7 @@ const Root = ({ }: IRoot) => { const ref = useRef(null); - console.log(data); + // logger.log(data); return ( <> {!loading && ( @@ -250,7 +251,7 @@ const Root = ({ } } } catch { - console.log('Error Focusing'); + logger.error('Error Focusing'); } }} onKeyDown={(e) => { @@ -265,7 +266,7 @@ const Root = ({ )} > {data?.headers.map((h, index) => ( -
+
{h.render()}
))} @@ -274,7 +275,7 @@ const Root = ({ {data?.rows.map((r, index) => ( ); }; + +export const LoadingIndicator = ({ + className, + size = 1, +}: { + className?: string; + size?: 1 | 2 | 3; +}) => { + return ( +
+ + +
+ ); +}; diff --git a/src/apps/console/page-components/log-action.tsx b/src/apps/console/page-components/log-action.tsx new file mode 100644 index 000000000..57ae6e040 --- /dev/null +++ b/src/apps/console/page-components/log-action.tsx @@ -0,0 +1,48 @@ +import { cn } from '~/components/utils'; +import { Clock, ListNumbers } from '@jengaicons/react'; +import { useDataState } from './common-state'; + +const LogAction = () => { + const { state, setState } = useDataState<{ + linesVisible: boolean; + timestampVisible: boolean; + }>('logs'); + + return ( +
+
{ + setState((s) => ({ ...s, linesVisible: !s.linesVisible })); + }} + className="flex items-center justify-center font-bold text-xl cursor-pointer select-none active:translate-y-[1px] transition-all" + > + + + +
+
{ + setState((s) => ({ + ...s, + timestampVisible: !s.timestampVisible, + })); + }} + className="flex items-center justify-center font-bold text-xl cursor-pointer select-none active:translate-y-[1px] transition-all" + > + + + +
+
+ ); +}; + +export default LogAction; diff --git a/src/apps/console/page-components/new-cluster.tsx b/src/apps/console/page-components/new-cluster.tsx index 31a2fef63..bc59a4116 100644 --- a/src/apps/console/page-components/new-cluster.tsx +++ b/src/apps/console/page-components/new-cluster.tsx @@ -135,7 +135,7 @@ export const NewCluster = ({ providerSecrets, cloudProvider }: props) => { region: selectedRegion.Name, k3sMasters: { nvidiaGpuEnabled: true, - instanceType: 'c6a.xlarge', + instanceType: 'c6a.large', }, }, availabilityMode: validateAvailabilityMode( @@ -352,10 +352,10 @@ export const NewCluster = ({ providerSecrets, cloudProvider }: props) => { step={2} label="Add your cloud provider" /> - {/* */} + {getView()} diff --git a/src/apps/console/routes/_a+/new-team.tsx b/src/apps/console/routes/_a+/new-team.tsx index 31dfd877f..e849a3b34 100644 --- a/src/apps/console/routes/_a+/new-team.tsx +++ b/src/apps/console/routes/_a+/new-team.tsx @@ -89,7 +89,7 @@ const NewAccount = () => {
- {/* */} + diff --git a/src/apps/console/routes/_a+/onboarding+/$a+/$cloudprovider+/validate-cp.tsx b/src/apps/console/routes/_a+/onboarding+/$a+/$cloudprovider+/validate-cp.tsx index ba5f98eaa..195aa16d1 100644 --- a/src/apps/console/routes/_a+/onboarding+/$a+/$cloudprovider+/validate-cp.tsx +++ b/src/apps/console/routes/_a+/onboarding+/$a+/$cloudprovider+/validate-cp.tsx @@ -68,7 +68,7 @@ const Validator = ({ cloudProvider }: { cloudProvider: any }) => { const { data, isLoading: il } = useCustomSwr( () => parseName(cloudProvider) + isLoading, async () => { - if (!parseName(cloudProvider.metadata!.name)) { + if (!parseName(cloudProvider)) { throw new Error('Invalid cloud provider name'); } return api.checkAwsAccess({ diff --git a/src/apps/console/routes/_a+/onboarding+/$a+/new-cloud-provider.tsx b/src/apps/console/routes/_a+/onboarding+/$a+/new-cloud-provider.tsx index 454a25db2..526177957 100644 --- a/src/apps/console/routes/_a+/onboarding+/$a+/new-cloud-provider.tsx +++ b/src/apps/console/routes/_a+/onboarding+/$a+/new-cloud-provider.tsx @@ -143,7 +143,7 @@ const NewCloudProvider = () => { />
- {/* */} + diff --git a/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/logs-n-metrics/route.tsx b/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/logs-n-metrics/route.tsx index 8ea1645d2..32248e351 100644 --- a/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/logs-n-metrics/route.tsx +++ b/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/logs-n-metrics/route.tsx @@ -7,12 +7,11 @@ import { dayjs } from '~/components/molecule/dayjs'; import { parseValue } from '~/console/page-components/util'; import { ApexOptions } from 'apexcharts'; import { parseName } from '~/console/server/r-utils/common'; -import { Clock, ListNumbers } from '@jengaicons/react'; -import { cn } from '~/components/utils'; import { useDataState } from '~/console/page-components/common-state'; import { observeUrl } from '~/root/lib/configs/base-url.cjs'; -import { IAppContext } from '../_layout'; import LogComp from '~/root/lib/client/components/logger'; +import LogAction from '~/console/page-components/log-action'; +import { IAppContext } from '../_layout'; const LogsAndMetrics = () => { const { app, project, account } = useOutletContext(); @@ -87,7 +86,7 @@ const LogsAndMetrics = () => { }, }; - const { state, setState } = useDataState<{ + const { state } = useDataState<{ linesVisible: boolean; timestampVisible: boolean; }>('logs'); @@ -239,41 +238,7 @@ const LogsAndMetrics = () => { width: '100%', height: '70vh', title: 'Logs', - actionComponent: ( -
-
{ - setState((s) => ({ ...s, linesVisible: !s.linesVisible })); - }} - className="flex items-center justify-center font-bold text-xl cursor-pointer select-none active:translate-y-[1px] transition-all" - > - - - -
-
{ - setState((s) => ({ - ...s, - timestampVisible: !s.timestampVisible, - })); - }} - className="flex items-center justify-center font-bold text-xl cursor-pointer select-none active:translate-y-[1px] transition-all" - > - - - -
-
- ), + actionComponent: , websocket: { account: parseName(account), cluster: project.clusterName || '', diff --git a/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/settings+/compute/route.tsx b/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/settings+/compute/route.tsx index 5aa6e4605..b83dee86b 100644 --- a/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/settings+/compute/route.tsx +++ b/src/apps/console/routes/_main+/$account+/$project+/$environment+/app+/$app+/settings+/compute/route.tsx @@ -131,6 +131,7 @@ const SettingCompute = () => { ? `${values.repoName}:${values.repoImageTag}` : `${registryHost}/${values.repoAccountName}/${values.repoName}:${values.repoImageTag}`, name: 'container-0', + imagePullPolicy: 'Always', resourceCpu: val.selectionMode === 'quick' ? { diff --git a/src/apps/console/routes/_main+/$account+/$project+/$environment+/new-app/app-compute.tsx b/src/apps/console/routes/_main+/$account+/$project+/$environment+/new-app/app-compute.tsx index fe88d98d0..7b5617d05 100644 --- a/src/apps/console/routes/_main+/$account+/$project+/$environment+/new-app/app-compute.tsx +++ b/src/apps/console/routes/_main+/$account+/$project+/$environment+/new-app/app-compute.tsx @@ -159,6 +159,7 @@ const AppCompute = () => { ? `${values.repoName}:${values.repoImageTag}` : `${registryHost}/${values.repoAccountName}/${values.repoName}:${values.repoImageTag}`, name: 'container-0', + imagePullPolicy: 'Always', resourceCpu: val.selectionMode === 'quick' ? { diff --git a/src/apps/console/routes/_main+/$account+/infra+/$cluster+/nodepools/nodepool-resources.tsx b/src/apps/console/routes/_main+/$account+/infra+/$cluster+/nodepools/nodepool-resources.tsx index b63094c20..64727ac8a 100644 --- a/src/apps/console/routes/_main+/$account+/infra+/$cluster+/nodepools/nodepool-resources.tsx +++ b/src/apps/console/routes/_main+/$account+/infra+/$cluster+/nodepools/nodepool-resources.tsx @@ -35,6 +35,8 @@ import { dayjs } from '~/components/molecule/dayjs'; import LogComp from '~/root/lib/client/components/logger'; import { useWatchReload } from '~/lib/client/helpers/socket/useWatch'; import { IClusterContext } from '~/console/routes/_main+/$account+/infra+/$cluster+/_layout'; +import LogAction from '~/console/page-components/log-action'; +import { useDataState } from '~/console/page-components/common-state'; import HandleNodePool from './handle-nodepool'; import { findNodePlanWithCategory, @@ -87,6 +89,7 @@ const ExtraButton = ({ /> ); }; + interface IResource { items: BaseType[]; onDelete: (item: BaseType) => void; @@ -207,6 +210,11 @@ const ListDetail = ( const isLatest = dayjs(item.updateTime).isAfter(dayjs().subtract(3, 'hour')); + const { state } = useDataState<{ + linesVisible: boolean; + timestampVisible: boolean; + }>('logs'); + return (
@@ -277,12 +285,14 @@ const ListDetail = ( width: '100%', height: '40rem', title: 'Logs', - hideLineNumber: true, + hideLineNumber: !state.linesVisible, + hideTimestamp: !state.timestampVisible, websocket: { account: parseName(account), cluster: item.clusterName, trackingId: item.id, }, + actionComponent: , }} /> @@ -369,7 +379,6 @@ const ListView = ({ items, onDelete, onEdit }: IResource) => { {items.map((item, index) => { const { name, id } = parseItem(item); const keyPrefix = `${RESOURCE_NAME}-${id}-${index}`; - // const lR = listRender({ keyPrefix, resource: item }); return ( { const { cluster, account } = useOutletContext(); diff --git a/src/apps/console/routes/_main+/$account+/infra+/clusters/cluster-resources.tsx b/src/apps/console/routes/_main+/$account+/infra+/clusters/cluster-resources.tsx index cc89e03c4..abfd64b98 100644 --- a/src/apps/console/routes/_main+/$account+/infra+/clusters/cluster-resources.tsx +++ b/src/apps/console/routes/_main+/$account+/infra+/clusters/cluster-resources.tsx @@ -1,13 +1,12 @@ import { GearSix } from '@jengaicons/react'; import { Link, useOutletContext, useParams } from '@remix-run/react'; -import { cn, generateKey, titleCase } from '~/components/utils'; +import { generateKey, titleCase } from '~/components/utils'; import { IStatus, listRender } from '~/console/components/commons'; import ConsoleAvatar from '~/console/components/console-avatar'; import { ListBody, ListItem, ListTitle, - listFlex, } from '~/console/components/console-list-components'; import Grid from '~/console/components/grid'; import List from '~/console/components/list'; @@ -25,6 +24,14 @@ import { renderCloudProvider } from '~/console/utils/commons'; import logger from '~/root/lib/client/helpers/log'; import { IAccountContext } from '~/console/routes/_main+/$account+/_layout'; import { useWatchReload } from '~/lib/client/helpers/socket/useWatch'; +import { ISetState } from '~/console/page-components/app-states'; +import { useState } from 'react'; +import { dayjs } from '~/components/molecule/dayjs'; +import { Button } from '~/components/atoms/button'; +import AnimateHide from '~/components/atoms/animate-hide'; +import LogComp from '~/root/lib/client/components/logger'; +import LogAction from '~/console/page-components/log-action'; +import { useDataState } from '~/console/page-components/common-state'; const RESOURCE_NAME = 'cluster'; @@ -143,36 +150,128 @@ const GridView = ({ items }: { items: ExtractNodeType[] }) => { ); }; -const ListView = ({ items }: { items: ExtractNodeType[] }) => { +type BaseType = ExtractNodeType; + +interface IResource { + items: BaseType[]; + // onDelete: (item: BaseType) => void; + // onEdit: (item: BaseType) => void; +} + +const ListDetail = ( + props: Omit & { + open: string; + item: BaseType; + setOpen: ISetState; + } +) => { + const { item, open, setOpen } = props; + + const { name, id } = parseItem(item); + const keyPrefix = `${RESOURCE_NAME}-${id}`; + const lR = listRender({ keyPrefix, resource: item }); + + const { account } = useOutletContext(); + + const isLatest = dayjs(item.updateTime).isAfter(dayjs().subtract(3, 'hour')); + + const tempStatus = listStatus({ + key: keyPrefix, + item, + className: 'basis-full text-center', + }); + + const { state } = useDataState<{ + linesVisible: boolean; + timestampVisible: boolean; + }>('logs'); + + return ( +
+
+
+ {id}
+ } + avatar={} + /> +
+ + {isLatest && ( +
+ + e.preventDefault()} + show={open === item.id} + className="w-full flex pt-4xl justify-center items-center" + > + , + }} + /> + +
+ ); +}; + +const ListView = ({ items }: IResource) => { + const [open, setOpen] = useState(''); const { account } = useParams(); + return ( {items.map((item, index) => { - const { name, id, provider } = parseItem(item); + const { name, id } = parseItem(item); const keyPrefix = `${RESOURCE_NAME}-${id}-${index}`; - const lR = listRender({ keyPrefix, resource: item }); + const lR = listRender({ keyPrefix, resource: item }); const statusRender = lR.statusRender({ className: 'min-w-[80px] mx-[25px] basis-full text-center', }); - const tempStatus = listStatus({ - key: keyPrefix, - item, - className: 'text-center', - }); - return ( [] }) => { : {})} columns={[ { + className: 'w-full', key: generateKey(keyPrefix, name + id), - className: 'max-w-[180px] min-w-[180px] w-[180px]', - render: () => ( - } - /> - ), - }, - tempStatus, - listFlex({ key: 'flex-1' }), - { - key: generateKey(keyPrefix, `${provider}`), - className: 'min-w-[150px] text-start', - render: () => , - }, - lR.authorRender({ className: 'min-w-[180px] w-[180px]' }), - { - key: generateKey(keyPrefix, 'action'), render: () => ( - + ), }, ]} diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/_layout.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/_layout.tsx index 3d19bb7b3..caf263886 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/_layout.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/_layout.tsx @@ -15,19 +15,13 @@ import { import Breadcrum from '~/console/components/breadcrum'; import { CommonTabs } from '~/console/components/common-navbar-tabs'; -import { IRemixCtx } from '~/root/lib/types/common'; +import { IRemixCtx, LoaderResult } from '~/root/lib/types/common'; import { GQLServerHandler } from '~/console/server/gql/saved-queries'; import logger from '~/root/lib/client/helpers/log'; -import { ILoginUrls, ILogins } from '~/console/server/gql/queries/git-queries'; import { IPackageContext } from '~/console/routes/_main+/$account+/packages+/_layout'; -export interface IRepoContext extends IPackageContext { - logins: ILogins; - loginUrls: ILoginUrls; -} const LocalBreadcrum = () => { - const { repo, account } = useParams(); - const repoName = atob(repo || ''); + const { account, repo } = useParams(); return (
{ } /> {repoName}} + content={{atob(repo || '')}} />
); }; const Tabs = () => { - const { repo, account } = useParams(); + const { account } = useParams(); + + const { repo } = useParams(); const iconSize = 16; return ( { /> ); }; -export const handle = () => { - return { - navbar: , - breadcrum: () => , - }; -}; export const loader = async (ctx: IRemixCtx) => { + const { repo } = ctx.params; + + const repoName = atob(repo || ''); + try { const { data, errors } = await GQLServerHandler(ctx.request).getLogins({}); @@ -129,21 +123,38 @@ export const loader = async (ctx: IRemixCtx) => { return { loginUrls: e, logins: data, + repoName, }; } catch (err) { logger.error(err); } + const k: any = {}; + + return { + logins: k, + loginUrls: k, + repoName, + }; +}; + +export const handle = () => { return { - logins: {}, - loginUrls: {}, + navbar: , + breadcrum: () => , }; }; +export interface IRepoContext extends IPackageContext { + logins: LoaderResult['logins']; + loginUrls: LoaderResult['loginUrls']; + repoName: LoaderResult['repoName']; +} + const Repo = () => { const rootContext = useOutletContext(); - const { logins, loginUrls } = useLoaderData(); - return ; + const ctx = useLoaderData(); + return ; }; export default Repo; diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/buildruns-resources.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/buildruns-resources.tsx index ea949e042..392cfde55 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/buildruns-resources.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/buildruns-resources.tsx @@ -25,8 +25,8 @@ import { XCircleFill, } from '@jengaicons/react'; import dayjs from 'dayjs'; -import { IAccountContext } from '../../../_layout'; import LogComp from '~/root/lib/client/components/logger'; +import { IAccountContext } from '../../../_layout'; const RESOURCE_NAME = 'build run'; type BaseType = ExtractNodeType; diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/route.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/route.tsx index c66b84aa8..3f153897d 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/route.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/buildruns/route.tsx @@ -16,7 +16,7 @@ export const loader = async (ctx: IRemixCtx) => { const promise = pWrapper(async () => { const { data, errors } = await GQLServerHandler(ctx.request).listBuildRuns({ - repoName: repo, + repoName: atob(repo), pq: getPagination(ctx), search: getSearch(ctx), }); diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/_index.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/_index.tsx index c544f5407..579eb8370 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/_index.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/_index.tsx @@ -10,17 +10,17 @@ import logger from '~/root/lib/client/helpers/log'; import { IRemixCtx } from '~/root/lib/types/common'; import { Plus } from '@jengaicons/react'; import { Button } from '~/components/atoms/button'; +import fake from '~/root/fake-data-generator/fake'; import BuildResources from './build-resources'; import HandleBuild from './handle-builds'; import Tools from './tools'; -import fake from "~/root/fake-data-generator/fake"; export const loader = async (ctx: IRemixCtx) => { const { repo } = ctx.params; const promise = pWrapper(async () => { ensureAccountSet(ctx); const { data, errors } = await GQLServerHandler(ctx.request).listBuilds({ - repoName: repo, + repoName: atob(repo), pagination: getPagination(ctx), search: getSearch(ctx), }); @@ -44,10 +44,10 @@ const Builds = () => { return ( <> {({ buildData }) => { const builds = buildData.edges?.map(({ node }) => node); diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/build-resources.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/build-resources.tsx index f537ff3e2..b61ec068e 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/build-resources.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/build-resources.tsx @@ -1,4 +1,8 @@ -import { Trash, PencilSimple } from '@jengaicons/react'; +import { + Trash, + PencilSimple, + ArrowClockwise, +} from '~/console/components/icons'; import { useState } from 'react'; import { Badge } from '~/components/atoms/badge'; import { toast } from '~/components/molecule/toast'; @@ -47,9 +51,10 @@ const parseItem = (item: BaseType) => { interface IExtraButton { onDelete: () => void; onEdit: () => void; + onTrigger: () => void; } -const ExtraButton = ({ onDelete, onEdit }: IExtraButton) => { +const ExtraButton = ({ onDelete, onEdit, onTrigger }: IExtraButton) => { return ( { onClick: onEdit, key: 'edit', }, + { + label: 'Trigger', + icon: , + type: 'item', + onClick: onTrigger, + key: 'trigger', + }, + { + type: 'separator', + key: 'separator1', + }, { label: 'Delete', icon: , @@ -77,9 +93,10 @@ interface IResource { items: BaseType[]; onDelete: (item: BaseType) => void; onEdit: (item: BaseType) => void; + onTrigger: (item: BaseType) => void; } -const GridView = ({ items, onDelete, onEdit }: IResource) => { +const GridView = ({ items, onDelete, onEdit, onTrigger }: IResource) => { return ( {items.map((item, index) => { @@ -102,6 +119,9 @@ const GridView = ({ items, onDelete, onEdit }: IResource) => { onEdit={() => { onEdit(item); }} + onTrigger={() => { + onTrigger(item); + }} /> } /> @@ -124,7 +144,7 @@ const GridView = ({ items, onDelete, onEdit }: IResource) => { ); }; -const ListView = ({ items, onDelete, onEdit }: IResource) => { +const ListView = ({ items, onDelete, onEdit, onTrigger }: IResource) => { return ( {items.map((item, index) => { @@ -170,6 +190,9 @@ const ListView = ({ items, onDelete, onEdit }: IResource) => { onEdit={() => { onEdit(item); }} + onTrigger={() => { + onTrigger(item); + }} /> ), }, @@ -197,6 +220,22 @@ const BuildResources = ({ items = [] }: { items: BaseType[] }) => { }) ); + const triggerBuild = async (id: string) => { + try { + const { errors } = await api.triggerBuild({ + crTriggerBuildId: id, + }); + + if (errors) { + throw errors[0]; + } + reloadPage(); + toast.success(`${titleCase(RESOURCE_NAME)} triggered successfully`); + } catch (err) { + handleError(err); + } + }; + const props: IResource = { items, onDelete: (item) => { @@ -205,6 +244,9 @@ const BuildResources = ({ items = [] }: { items: BaseType[] }) => { onEdit: (item) => { setHandleBuild(item); }, + onTrigger: async (item) => { + await triggerBuild(item.id); + }, }; return ( diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/handle-builds.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/handle-builds.tsx index 53d6abf67..1fd57ab56 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/handle-builds.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/builds/handle-builds.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/destructuring-assignment */ import { IDialogBase } from '~/console/components/types.d'; -import { useOutletContext, useParams } from '@remix-run/react'; +import { useOutletContext } from '@remix-run/react'; import { Checkbox } from '~/components/atoms/checkbox'; import Select from '~/components/atoms/select'; import { toast } from '~/components/molecule/toast'; @@ -119,8 +119,6 @@ const Root = (props: IDialog) => { totalSteps: 2, }); - const { repo } = useParams(); - const isAdvanceOptions = (data: any) => { if (!data) { return false; @@ -306,6 +304,7 @@ const Root = (props: IDialog) => { }} error={!!errors.buildClusterName || !!errorCluster} message={ + // eslint-disable-next-line no-nested-ternary errors.buildClusterName ? errors.buildClusterName : errorCluster diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/route.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/route.tsx index 485930746..0ed934e27 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/route.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/route.tsx @@ -7,13 +7,13 @@ import { ensureAccountSet } from '~/console/server/utils/auth-utils'; import { getPagination, getSearch } from '~/console/server/utils/common'; import logger from '~/root/lib/client/helpers/log'; import { IRemixCtx } from '~/root/lib/types/common'; -import SecondarySubHeader from '~/console/components/secondary-sub-header'; +import fake from '~/root/fake-data-generator/fake'; import TagsResources from './tags-resources'; import Tools from './tools'; -import fake from "~/root/fake-data-generator/fake"; export const loader = async (ctx: IRemixCtx) => { const { repo } = ctx.params; + const promise = pWrapper(async () => { ensureAccountSet(ctx); const { data, errors } = await GQLServerHandler(ctx.request).listDigest({ @@ -21,6 +21,7 @@ export const loader = async (ctx: IRemixCtx) => { pagination: getPagination(ctx), search: getSearch(ctx), }); + if (errors) { logger.error(errors[0]); throw errors[0]; @@ -38,10 +39,10 @@ const Images = () => { const { promise } = useLoaderData(); return ( {({ tagsData }) => { const tags = tagsData.edges?.map(({ node }) => node); diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/sha-dialog.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/sha-dialog.tsx index 6e8af2dec..04e878537 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/sha-dialog.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/sha-dialog.tsx @@ -4,11 +4,18 @@ import Popup from '~/components/molecule/popup'; import CodeView from '~/console/components/code-view'; import { IDialog } from '~/console/components/types.d'; import { registryHost } from '~/root/lib/configs/base-url.cjs'; +import { useOutletContext } from 'react-router-dom'; import { ISHADialogData } from './tags-resources'; +import { IRepoContext } from '../_layout'; const SHADialog = ({ show, setShow }: IDialog) => { - const { account, repo } = useParams(); - const url = `${registryHost}/${account}/${repo}:${ + const { account } = useParams(); + + const { repoName } = useOutletContext(); + + return null; + + const url = `${registryHost}/${account}/${repoName}:${ show?.data?.tag ? show?.data?.tag : `@${show?.data?.sha}` }`; return ( diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/tags-resources.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/tags-resources.tsx index 48193e5c7..f6a3137a0 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/tags-resources.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/images/tags-resources.tsx @@ -244,7 +244,7 @@ const TagsResources = ({ items = [] }: { items: BaseType[] }) => { } }} /> - + {/* */} ); }; diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/configure-git-repo.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/configure-git-repo.tsx index b1c6e42ac..4e224ef29 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/configure-git-repo.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/configure-git-repo.tsx @@ -3,8 +3,6 @@ import ExtendedFilledTab from '~/console/components/extended-filled-tab'; import { AnimatePresence, motion } from 'framer-motion'; import { FadeIn } from '~/console/page-components/util'; - - const ConfigureRepo = () => { const [setting, setSetting] = useState('general'); return ( diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/route.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/route.tsx index 82b74fe0d..cd18a3b20 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/route.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/new-build/route.tsx @@ -10,12 +10,13 @@ import { useConsoleApi } from '~/console/server/gql/api-provider'; import Git from '~/console/components/git'; import { IGIT_PROVIDERS } from '~/console/hooks/use-git'; import { BottomNavigation } from '~/console/components/commons'; +import { toast } from '~/components/molecule/toast'; import ReviewBuild from './review-build'; import BuildDetails from './build-details'; import { IRepoContext } from '../_layout'; const NewBuild = () => { - const { loginUrls, logins } = useOutletContext(); + const { loginUrls, logins, repoName } = useOutletContext(); const navigate = useNavigate(); @@ -27,7 +28,6 @@ const NewBuild = () => { }); const api = useConsoleApi(); - const { repo } = useParams(); const { values, errors, handleSubmit, handleChange, isLoading } = useForm({ initialValues: { @@ -40,7 +40,7 @@ const NewBuild = () => { tags: [], buildClusterName: '', advanceOptions: false, - repository: repo || '', + repository: repoName || '', buildArgs: {}, buildContexts: {}, contextDir: '', @@ -69,8 +69,9 @@ const NewBuild = () => { }), }), onSubmit: async (val) => { - if (!repo) { - throw new Error('Repository is required!.'); + if (!repoName) { + toast.error('Repository is required!.'); + return; } const submit = async () => { try { @@ -115,21 +116,26 @@ const NewBuild = () => { if (e) { throw e[0]; } - navigate(`/${account}/repo/${repo}/builds`); + navigate(`/${account}/repo/${repoName}/builds`); } catch (err) { handleError(err); } }; - switch (currentStep) { - case 1: - nextStep(); - break; - case 2: - nextStep(); - break; - default: - await submit(); - break; + + try { + switch (currentStep) { + case 1: + nextStep(); + break; + case 2: + nextStep(); + break; + default: + await submit(); + break; + } + } catch (err) { + handleError(err); } }, }); diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/buildcaches/route.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/buildcaches/route.tsx index 08cda8462..678b11fd0 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/buildcaches/route.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/buildcaches/route.tsx @@ -2,9 +2,7 @@ import { defer } from '@remix-run/node'; import { Link, useLoaderData, useParams } from '@remix-run/react'; import { useState } from 'react'; import { Button } from '~/components/atoms/button'; -import { CommonTabs } from '~/console/components/common-navbar-tabs'; import { LoadingComp, pWrapper } from '~/console/components/loading-component'; -import SubNavAction from '~/console/components/sub-nav-action'; import Wrapper from '~/console/components/wrapper'; import { GQLServerHandler } from '~/console/server/gql/saved-queries'; import { ensureAccountSet } from '~/console/server/utils/auth-utils'; diff --git a/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/general/route.tsx b/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/general/route.tsx index 7cc4ed6a2..c2060a8cd 100644 --- a/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/general/route.tsx +++ b/src/apps/console/routes/_main+/$account+/repo+/$repo+/settings/general/route.tsx @@ -1,5 +1,5 @@ import { CopySimple } from '@jengaicons/react'; -import { useNavigate, useParams } from '@remix-run/react'; +import { useNavigate, useOutletContext, useParams } from '@remix-run/react'; import { useState } from 'react'; import { TextInput } from '~/components/atoms/input'; import { toast } from '~/components/molecule/toast'; @@ -12,9 +12,11 @@ import { useConsoleApi } from '~/console/server/gql/api-provider'; import useClipboard from '~/root/lib/client/hooks/use-clipboard'; import { consoleBaseUrl } from '~/root/lib/configs/base-url.cjs'; import { handleError } from '~/root/lib/utils/common'; +import { IRepoContext } from '../../_layout'; const ProjectSettingGeneral = () => { - const { repo = '', account } = useParams(); + const { account } = useParams(); + const { repoName } = useOutletContext(); const api = useConsoleApi(); const navigate = useNavigate(); const [deleteRepo, setDeleteRepo] = useState(false); @@ -30,14 +32,14 @@ const ProjectSettingGeneral = () => {
{