Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions galasa-ui/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,10 @@
"filterTrace": "Trace",
"downloadButton": "Laufprotokoll herunterladen",
"copyPermalinkButton": "Permalink mit ausgewählten Zeilen kopieren",
"selectLinesToCreatePermalink": "Zeilen für Permalink wählen"
"selectLinesToCreatePermalink": "Zeilen für Permalink wählen",
"refreshRunLog": "Aktualisiere das Ausführungsprotokoll",
"scrollToTop": "Zum Anfang des Protokolls scrollen",
"scrollToBottom": "Zum Ende des Protokolls scrollen"
},
"MethodsTab": {
"title": "Methoden",
Expand Down Expand Up @@ -389,12 +392,10 @@
"isloading": "Diagramm wird geladen...",
"errorLoadingGraph": "Beim Laden des Diagramms ist ein Fehler aufgetreten.",
"noTestRunsFound": "Keine Testläufe gefunden.",

"limitExceeded": {
"title": "Grenzwert überschritten",
"subtitle": "Ihre Abfrage hat mehr als {maxRecords} Ergebnisse zurückgegeben. Es werden die ersten {maxRecords} Datensätze angezeigt. Um dies in Zukunft zu vermeiden, schränken Sie Ihren Zeitrahmen ein oder ändern Sie Ihre Suchkriterien, um weniger Ergebnisse zu erhalten."
},

"timeFrameText": {
"range": "Zeige Testläufe von {from} bis {to}"
}
Expand Down
5 changes: 4 additions & 1 deletion galasa-ui/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,10 @@
"filterTrace": "Trace",
"downloadButton": "Download Run Log",
"copyPermalinkButton": "Copy permalink with selected lines",
"selectLinesToCreatePermalink": "Select log lines for permalink"
"selectLinesToCreatePermalink": "Select log lines for permalink",
"refreshRunLog": "Refresh the Run Log",
"scrollToTop": "Scroll to top of log",
"scrollToBottom": "Scroll to bottom of log"
},
"MethodsTab": {
"title": "Methods",
Expand Down
11 changes: 11 additions & 0 deletions galasa-ui/src/actions/runsAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { ResultArchiveStoreAPIApi, TagsAPIApi } from '@/generated/galasaapi';
import { createAuthenticatedApiConfiguration } from '@/utils/api';
import { fetchRunDetailLogs } from '@/utils/testRuns';
import { CLIENT_API_VERSION } from '@/utils/constants/common';

export const downloadArtifactFromServer = async (runId: string, artifactUrl: string) => {
Expand Down Expand Up @@ -92,3 +93,13 @@ export const getExistingTagObjects = async () => {
};
}
};

export const fetchRunLog = async (runId: string) => {
let runLog;
try {
runLog = await fetchRunDetailLogs(runId);
} catch (error: any) {
runLog = 'Error fetching run log: ' + error;
}
return runLog;
};
75 changes: 73 additions & 2 deletions galasa-ui/src/components/test-runs/test-run-details/LogTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@ import {
Term,
LetterAa,
Copy,
Renew,
ArrowUp,
ArrowDown,
} from '@carbon/icons-react';
import { handleDownload } from '@/utils/artifacts';
import { useTranslations } from 'next-intl';
import { fetchRunLog } from '@/actions/runsAction';

interface LogLine {
content: string;
Expand All @@ -43,6 +47,7 @@ enum RegexFlags {
interface LogTabProps {
logs: string;
initialLine?: number;
runId: string;
}

interface selectedRange {
Expand All @@ -55,10 +60,11 @@ interface selectedRange {
const SELECTION_CHANGE_EVENT = 'selectionchange';
const HASH_CHANGE_EVENT = 'hashchange';

export default function LogTab({ logs, initialLine }: LogTabProps) {
export default function LogTab({ logs, initialLine, runId }: LogTabProps) {
const translations = useTranslations('LogTab');

const [logContent, setLogContent] = useState<string>('');
const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const [processedLines, setProcessedLines] = useState<LogLine[]>([]);
const [searchTerm, setSearchTerm] = useState<string>('');
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState<string>('');
Expand All @@ -84,6 +90,7 @@ export default function LogTab({ logs, initialLine }: LogTabProps) {
);

const logContainerRef = useRef<HTMLDivElement>(null);
const scrollContainerRef = useRef<HTMLDivElement>(null);
const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null);

const DEBOUNCE_DELAY_MILLISECONDS = 300;
Expand Down Expand Up @@ -162,6 +169,48 @@ export default function LogTab({ logs, initialLine }: LogTabProps) {
}
};

const handleRefreshLog = async () => {
setIsRefreshing(true);

try {
// Fetch fresh log from the server
const newRunLog = await fetchRunLog(runId);

setLogContent(newRunLog);

// Reset search and filters
setSearchTerm('');
setDebouncedSearchTerm('');
setCurrentMatchIndex(-1);
setTotalMatches(0);
setSearchCache(new Map());
} catch (error) {
console.error('Error refreshing logs:', error);
// Fallback to existing logs if fetch fails
setLogContent(logs);
} finally {
setIsRefreshing(false);
}
};

const scrollToTop = () => {
if (scrollContainerRef.current) {
scrollContainerRef.current.scrollTo({
top: 0,
behavior: 'smooth',
});
}
};

const scrollToBottom = () => {
if (scrollContainerRef.current) {
scrollContainerRef.current.scrollTo({
top: scrollContainerRef.current.scrollHeight,
behavior: 'smooth',
});
}
};

// Memoized regex creation to avoid recreating the same regex repeatedly
const searchRegex = useMemo(() => {
let regex: RegExp | null = null;
Expand Down Expand Up @@ -685,8 +734,30 @@ export default function LogTab({ logs, initialLine }: LogTabProps) {
className={!selectedRange?.startLine ? styles.buttonDisabled : ''}
data-testid="icon-button-copy-permalink"
/>
<Button
kind="ghost"
renderIcon={Renew}
hasIconOnly
iconDescription={translations('refreshRunLog')}
onClick={handleRefreshLog}
disabled={isRefreshing}
/>
<Button
kind="ghost"
renderIcon={ArrowUp}
hasIconOnly
iconDescription={translations('scrollToTop')}
onClick={scrollToTop}
/>
<Button
kind="ghost"
renderIcon={ArrowDown}
hasIconOnly
iconDescription={translations('scrollToBottom')}
onClick={scrollToBottom}
/>
</div>
<div className={styles.runLog}>
<div className={styles.runLog} ref={scrollContainerRef}>
<div className={styles.runLogContent} ref={logContainerRef}>
{renderLogContent()}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ const TestRunDetails = ({
<MethodsTab methods={methods} onMethodClick={handleNavigateToLog} />
</TabPanel>
<TabPanel>
<LogTab logs={logs} initialLine={initialLine} />
<LogTab logs={logs} initialLine={initialLine} runId={runId} />
</TabPanel>
<TabPanel>
<ArtifactsTab
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
border-radius: var(--border-radius);
padding: 1rem;
font-family: 'IBM Plex Mono', monospace;
height: 100vh;
height: 70vh;
overflow-y: auto;
}

Expand Down