mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
streamable ftbuild logs
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
"@monaco-editor/react": "^4.1.0",
|
||||
"@tinymce/tinymce-react": "^3.4.0",
|
||||
"algoliasearch": "^4.8.6",
|
||||
"ansi-to-react": "^6.1.5",
|
||||
"chroma-js": "^2.1.0",
|
||||
"csv-parse": "^4.15.3",
|
||||
"date-fns": "^2.19.0",
|
||||
@@ -30,6 +31,7 @@
|
||||
"json2csv": "^5.0.6",
|
||||
"jszip": "^3.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.1",
|
||||
"query-string": "^6.8.3",
|
||||
"react": "^16.9.0",
|
||||
"react-beautiful-dnd": "^13.0.0",
|
||||
|
||||
@@ -142,15 +142,17 @@ export default function SparksEditor() {
|
||||
</>
|
||||
}
|
||||
actions={{
|
||||
primary:showForceSave ? {
|
||||
children: "Force Save",
|
||||
onClick: handleSave,
|
||||
|
||||
}:{
|
||||
children: "Save Changes",
|
||||
onClick: handleSave,
|
||||
disabled:!isSparksValid || localSparks === tableState?.config.sparks ,
|
||||
},
|
||||
primary: showForceSave
|
||||
? {
|
||||
children: "Force Save",
|
||||
onClick: handleSave,
|
||||
}
|
||||
: {
|
||||
children: "Save Changes",
|
||||
onClick: handleSave,
|
||||
disabled:
|
||||
!isSparksValid || localSparks === tableState?.config.sparks,
|
||||
},
|
||||
secondary: {
|
||||
children: "Cancel",
|
||||
onClick: handleClose,
|
||||
|
||||
192
www/src/components/Table/TableHeader/TableLogs.tsx
Normal file
192
www/src/components/Table/TableHeader/TableLogs.tsx
Normal file
@@ -0,0 +1,192 @@
|
||||
import React, { useState } from "react";
|
||||
import useRouter from "hooks/useRouter";
|
||||
import useTable from "hooks/useFiretable/useTable";
|
||||
import { useFiretableContext } from "contexts/FiretableContext";
|
||||
|
||||
import _camelCase from "lodash/camelCase";
|
||||
import _get from "lodash/get";
|
||||
import _find from "lodash/find";
|
||||
import _sortBy from "lodash/sortBy";
|
||||
import moment from "moment";
|
||||
|
||||
import Tabs from "@material-ui/core/Tabs";
|
||||
import Tab from "@material-ui/core/Tab";
|
||||
import { Chip } from "@material-ui/core";
|
||||
import Modal from "components/Modal";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Box from "@material-ui/core/Box";
|
||||
import LogsIcon from "@material-ui/icons/QueryBuilder";
|
||||
import TableHeaderButton from "./TableHeaderButton";
|
||||
import Ansi from "ansi-to-react";
|
||||
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
function a11yProps(index) {
|
||||
return {
|
||||
id: `vertical-tab-${index}`,
|
||||
"aria-controls": `vertical-tabpanel-${index}`,
|
||||
};
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
flexGrow: 1,
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
display: "flex",
|
||||
height: "80vh",
|
||||
},
|
||||
tabs: {
|
||||
borderRight: `1px solid ${theme.palette.divider}`,
|
||||
},
|
||||
|
||||
logPanel: {
|
||||
width: "100%",
|
||||
},
|
||||
logEntryWrapper: {
|
||||
overflowY: "scroll",
|
||||
maxHeight: "100%",
|
||||
},
|
||||
logNumber: {
|
||||
float: "left",
|
||||
width: "3em",
|
||||
textAlign: "right",
|
||||
paddingRight: "1em",
|
||||
},
|
||||
logEntry: {
|
||||
lineBreak: "anywhere",
|
||||
paddingLeft: "3em",
|
||||
whiteSpace: "break-spaces",
|
||||
userSelect: "text",
|
||||
},
|
||||
}));
|
||||
|
||||
LogPanel.propTypes = {
|
||||
logs: PropTypes.array,
|
||||
index: PropTypes.any.isRequired,
|
||||
value: PropTypes.any.isRequired,
|
||||
};
|
||||
|
||||
function LogRow({ logString, index }) {
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography variant="body2" className={classes.logNumber}>
|
||||
{index}
|
||||
</Typography>
|
||||
<Typography variant="body2" className={classes.logEntry}>
|
||||
<Ansi>{logString.replaceAll("\\n", "\n").replaceAll("\\t", "\t")}</Ansi>
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
function LogPanel(props) {
|
||||
const { logs, value, index, ...other } = props;
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<div
|
||||
role="tabpanel"
|
||||
hidden={value !== index}
|
||||
id={`vertical-tabpanel-${index}`}
|
||||
aria-labelledby={`vertical-tab-${index}`}
|
||||
className={classes.logPanel}
|
||||
{...other}
|
||||
>
|
||||
{value === index && (
|
||||
<Box p={3} className={classes.logEntryWrapper}>
|
||||
{logs?.map((log, index) => {
|
||||
return <LogRow logString={log} index={index} />;
|
||||
})}
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function TableLogs() {
|
||||
const router = useRouter();
|
||||
const { tableState } = useFiretableContext();
|
||||
|
||||
const classes = useStyles();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [tabIndex, setTabIndex] = React.useState(0);
|
||||
|
||||
const tableCollection = decodeURIComponent(router.match.params.id);
|
||||
const ftBuildStreamID =
|
||||
"_FIRETABLE_/settings/schema/" +
|
||||
tableCollection
|
||||
.split("/")
|
||||
.filter(function (_, i) {
|
||||
// replace IDs with subTables that appears at even indexes
|
||||
return i % 2 === 0;
|
||||
})
|
||||
.join("/subTables/");
|
||||
|
||||
const [collectionState] = useTable({
|
||||
path: `${ftBuildStreamID}/ftBuildLogs`,
|
||||
orderBy: [{ key: "startTimeStamp", direction: "desc" }],
|
||||
});
|
||||
|
||||
const handleTabChange = (event, newValue) => {
|
||||
setTabIndex(newValue);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableHeaderButton
|
||||
title="Table Logs"
|
||||
onClick={() => setOpen(true)}
|
||||
icon={<LogsIcon />}
|
||||
/>
|
||||
|
||||
{open && !!tableState && (
|
||||
<Modal
|
||||
onClose={handleClose}
|
||||
maxWidth="xl"
|
||||
fullWidth
|
||||
title={
|
||||
<>
|
||||
Build Logs <Chip label="ALPHA" size="small" />
|
||||
</>
|
||||
}
|
||||
children={
|
||||
<>
|
||||
<div className={classes.root}>
|
||||
<Tabs
|
||||
orientation="vertical"
|
||||
variant="scrollable"
|
||||
value={tabIndex}
|
||||
onChange={handleTabChange}
|
||||
className={classes.tabs}
|
||||
>
|
||||
{collectionState.rows.map((value, index) => (
|
||||
<Tab
|
||||
label={moment(value.startTimeStamp).format(
|
||||
"MMMM D YYYY h:mm:ssa"
|
||||
)}
|
||||
{...a11yProps(index)}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
{collectionState.rows.map((logEntry, index) => (
|
||||
<LogPanel
|
||||
value={tabIndex}
|
||||
index={index}
|
||||
logs={logEntry?.fullLog}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import Filters from "../Filters";
|
||||
import ImportCSV from "./ImportCsv";
|
||||
import Export from "./Export";
|
||||
import TableSettings from "./TableSettings";
|
||||
import TableLogs from "./TableLogs";
|
||||
import HiddenFields from "../HiddenFields";
|
||||
import Sparks from "./Sparks";
|
||||
import ReExecute from "./ReExecute";
|
||||
@@ -219,6 +220,10 @@ export default function TableHeader({
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<Grid item>
|
||||
<TableLogs />
|
||||
</Grid>
|
||||
|
||||
<Grid item>
|
||||
<TableSettings />
|
||||
</Grid>
|
||||
|
||||
@@ -3109,6 +3109,11 @@ alphanum-sort@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
||||
integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
|
||||
|
||||
anser@^1.4.1:
|
||||
version "1.4.10"
|
||||
resolved "https://registry.yarnpkg.com/anser/-/anser-1.4.10.tgz#befa3eddf282684bd03b63dcda3927aef8c2e35b"
|
||||
integrity sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==
|
||||
|
||||
ansi-align@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
|
||||
@@ -3192,6 +3197,14 @@ ansi-styles@^4.1.0:
|
||||
"@types/color-name" "^1.1.1"
|
||||
color-convert "^2.0.1"
|
||||
|
||||
ansi-to-react@^6.1.5:
|
||||
version "6.1.5"
|
||||
resolved "https://registry.yarnpkg.com/ansi-to-react/-/ansi-to-react-6.1.5.tgz#00ca9e4f566b468f0aa6a213f34b752b3e7121a9"
|
||||
integrity sha512-u7fkGMK+p6keOtgExruUDVmEnTBAWizlHJXzx9eJxw4rCVE6omzm0Gw4BQmB9oUPr0WriYf7Wyprms8uL8eL5Q==
|
||||
dependencies:
|
||||
anser "^1.4.1"
|
||||
escape-carriage "^1.3.0"
|
||||
|
||||
ansicolors@~0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
|
||||
@@ -5921,6 +5934,11 @@ escalade@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-carriage@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/escape-carriage/-/escape-carriage-1.3.0.tgz#71006b2d4da8cb6828686addafcb094239c742f3"
|
||||
integrity sha512-ATWi5MD8QlAGQOeMgI8zTp671BG8aKvAC0M7yenlxU4CRLGO/sKthxVUyjiOFKjHdIo+6dZZUNFgHFeVEaKfGQ==
|
||||
|
||||
escape-goat@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
|
||||
@@ -10136,6 +10154,11 @@ mkdirp@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
moment@^2.29.1:
|
||||
version "2.29.1"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
|
||||
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
|
||||
|
||||
monaco-editor@^0.21.2:
|
||||
version "0.21.2"
|
||||
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.21.2.tgz#37054e63e480d51a2dd17d609dcfb192304d5605"
|
||||
|
||||
Reference in New Issue
Block a user