+ return res.filter((promiseResult): promiseResult is PromiseFulfilledResult<LogFragment[]> => (
+ // Filter out log files with rejected promises
+ // (Promise.all rejects on any failure)
+ promiseResult.status === 'fulfilled' &&
+ // Filter out files where any fragment is empty
+ // (prevent incorrect snipline generation or an un-resumable situation)
+ !!promiseResult.value.every(logFragment => logFragment.contents.length)
+ )).map(one => one.value)
+ })).map((logResponseSet)=> {
+ // For any multi fragment response set, modify the last line of non-final chunks to include a line break and snip line
+ // Don't add snip line as a separate line so that sorting won't reorder it
+ for (let i = 1; i < logResponseSet.length; i++) {
+ const fragment = logResponseSet[i-1];
+ const lastLineIndex = fragment.contents.length-1;
+ const lastLineContents = fragment.contents[lastLineIndex];
+ const newLastLine = `${lastLineContents}\n${SNIPLINE}`;
+
+ logResponseSet[i-1].contents[lastLineIndex] = newLastLine;
+ }
+
+ // Merge LogFragment Array (representing multiple log line arrays) into single LogLine[] / LogFragment
+ return logResponseSet.reduce((acc, curr: LogFragment) => ({
+ logType: curr.logType,
+ contents: [...(acc.contents || []), ...curr.contents]
+ }), {} as LogFragment);
+ })
+);
+
+const createInitialLogPanelState = (logFiles: CollectionFile[], logFragments: LogFragment[]): {filters: string[], logs: ProcessLogs} => {
+ const logs = groupLogs(logFiles, logFragments);
+ const filters = Object.keys(logs);
+ return { filters, logs };
+}
+
+/**
+ * Converts LogFragments into ProcessLogs, grouping and sorting All/Main logs
+ * @param logFiles
+ * @param logFragments
+ * @returns ProcessLogs for the store
+ */
+const groupLogs = (logFiles: CollectionFile[], logFragments: LogFragment[]): ProcessLogs => {
+ const sortableLogFragments = mergeMultilineLoglines(logFragments);
+
+ const allLogs = mergeSortLogFragments(sortableLogFragments);
+ const mainLogs = mergeSortLogFragments(sortableLogFragments.filter((fragment) => (MAIN_EVENT_TYPES.includes(fragment.logType))));
+
+ const groupedLogs = logFragments.reduce((grouped, fragment) => ({
+ ...grouped,
+ [fragment.logType as string]: {lastByte: fetchLastByteNumber(logFiles, fragment.logType), contents: fragment.contents}
+ }), {});
+
+ return {
+ [MAIN_FILTER_TYPE]: {lastByte: undefined, contents: mainLogs},
+ [ALL_FILTER_TYPE]: {lastByte: undefined, contents: allLogs},
+ ...groupedLogs,