Merge branch 'master' into broadcast_notifications
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-apache-airflow': patch
|
||||
---
|
||||
|
||||
added an optional ESLint rule - no-top-level-material-ui-4-imports - which has an auto fix function to migrate the imports and used it to migrate the imports for plugins/apache-airflow
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-api-docs': patch
|
||||
---
|
||||
|
||||
added an optional ESLint rule - no-top-level-material-ui-4-imports - in api-docs plugin which has an auto fix function to migrate the imports and used it to migrate the material-ui imports for plugins/api-docs
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fixed a bug that could cause the `build-workspace` command to fail when invoked with `--alwaysYarnPack` enabled in environments with limited resources.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/plugin-notifications-backend': patch
|
||||
'@backstage/plugin-notifications': patch
|
||||
---
|
||||
|
||||
All notifications can be marked and filtered by severity critical, high, normal or low, the default is 'normal'
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-explore': patch
|
||||
---
|
||||
|
||||
Added an optional ESLint rule - no-top-level-material-ui-4-imports -in explore plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for plugins/explore.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': patch
|
||||
---
|
||||
|
||||
Resolved an issue where the `PaginatedCatalogTable` was not propagating table options to its child table.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-circleci': patch
|
||||
---
|
||||
|
||||
Added an optional ESLint rule - no-top-level-material-ui-4-imports - in CircleCI plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for `plugins/circleci`.
|
||||
@@ -2,4 +2,4 @@
|
||||
'@backstage/plugin-airbrake': patch
|
||||
---
|
||||
|
||||
added an optional ESLint rule - no-top-level-material-ui-4-imports - which has an auto fix function to migrate the imports and using it migrated the imports
|
||||
Added an optional ESLint rule - no-top-level-material-ui-4-imports - which has an auto fix function to migrate the imports and using it migrated the imports.
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-cloudbuild': patch
|
||||
---
|
||||
|
||||
Added an optional ESLint rule - no-top-level-material-ui-4-imports -in cloudbuild plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for plugins/cloudbuild.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-apollo-explorer': patch
|
||||
---
|
||||
|
||||
Added an optional ESLint rule - no-top-level-material-ui-4-imports -in apollo-explorer plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for plugins/apollo-explorer.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-bazaar': patch
|
||||
---
|
||||
|
||||
Added an optional ESLint rule - no-top-level-material-ui-4-imports - in bazaar plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for plugins/bazaar
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-kubernetes': patch
|
||||
---
|
||||
|
||||
Added an optional ESLint rule - no-top-level-material-ui-4-imports -in kubernetes plugin which has an auto fix function to migrate the imports and used it to migrate the Material UI imports for plugins/kubernetes.
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
cache-prefix: ${{ runner.os }}-v18.x
|
||||
|
||||
- name: Create Snyk report
|
||||
uses: snyk/actions/node@1d672a455ab3339ef0a0021e1ec809165ee12fad # master
|
||||
uses: snyk/actions/node@8349f9043a8b7f0f3ee8885bf28f0b388d2446e8 # master
|
||||
continue-on-error: true # Snyk CLI exits with error when vulnerabilities are found
|
||||
with:
|
||||
args: >
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Monitor and Synchronize Snyk Policies
|
||||
uses: snyk/actions/node@1d672a455ab3339ef0a0021e1ec809165ee12fad # master
|
||||
uses: snyk/actions/node@8349f9043a8b7f0f3ee8885bf28f0b388d2446e8 # master
|
||||
with:
|
||||
command: monitor
|
||||
args: >
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
# Above we run the `monitor` command, this runs the `test` command which is
|
||||
# the one that generates the SARIF report that we can upload to GitHub.
|
||||
- name: Create Snyk report
|
||||
uses: snyk/actions/node@1d672a455ab3339ef0a0021e1ec809165ee12fad # master
|
||||
uses: snyk/actions/node@8349f9043a8b7f0f3ee8885bf28f0b388d2446e8 # master
|
||||
continue-on-error: true # To make sure that SARIF upload gets called
|
||||
with:
|
||||
args: >
|
||||
|
||||
@@ -112,6 +112,7 @@
|
||||
"node-libs-browser": "^2.2.1",
|
||||
"npm-packlist": "^5.0.0",
|
||||
"ora": "^5.3.0",
|
||||
"p-limit": "^3.1.0",
|
||||
"p-queue": "^6.6.2",
|
||||
"postcss": "^8.1.0",
|
||||
"process": "^0.11.10",
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
resolve as resolvePath,
|
||||
relative as relativePath,
|
||||
} from 'path';
|
||||
import pLimit from 'p-limit';
|
||||
import { tmpdir } from 'os';
|
||||
import tar, { CreateOptions, FileOptions } from 'tar';
|
||||
import partition from 'lodash/partition';
|
||||
@@ -352,9 +353,11 @@ async function moveToDistWorkspace(
|
||||
}
|
||||
|
||||
// Repacking in parallel is much faster and safe for all packages outside of the Backstage repo
|
||||
// Limit concurrency to 10 to avoid resource exhaustion on larger monorepos.
|
||||
const limit = pLimit(10);
|
||||
await Promise.all(
|
||||
safePackages.map(async (target, index) =>
|
||||
pack(target, `temp-package-${index}.tgz`),
|
||||
safePackages.map((target, index) =>
|
||||
limit(() => pack(target, `temp-package-${index}.tgz`)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
Page,
|
||||
SupportButton,
|
||||
} from '@backstage/core-components';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import React from 'react';
|
||||
import { DagTableComponent } from '../DagTableComponent';
|
||||
import { StatusComponent } from '../StatusComponent';
|
||||
|
||||
@@ -18,17 +18,15 @@ import { apacheAirflowApiRef } from '../../api';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { DagRun } from '../../api/types/Dags';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
makeStyles,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import List from '@material-ui/core/List';
|
||||
import ListItem from '@material-ui/core/ListItem';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import {
|
||||
Link,
|
||||
StatusError,
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
|
||||
import {
|
||||
createApiExtension,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { ApiEntity } from '@backstage/catalog-model';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import React from 'react';
|
||||
import { apiDocsConfigRef } from '../../config';
|
||||
import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget';
|
||||
|
||||
@@ -16,18 +16,16 @@
|
||||
|
||||
import { ApiEntity } from '@backstage/catalog-model';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
makeStyles,
|
||||
Tab,
|
||||
Tabs,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React, { useEffect } from 'react';
|
||||
import { apiDocsConfigRef } from '../../config';
|
||||
import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget';
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { ApiEntity, RELATION_CONSUMES_API } from '@backstage/catalog-model';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
EntityTable,
|
||||
useEntity,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { ApiEntity, RELATION_HAS_PART } from '@backstage/catalog-model';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
EntityTable,
|
||||
useEntity,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { ApiEntity, RELATION_PROVIDES_API } from '@backstage/catalog-model';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
EntityTable,
|
||||
useEntity,
|
||||
|
||||
@@ -18,7 +18,7 @@ import { ApiEntity } from '@backstage/catalog-model';
|
||||
import { TableColumn } from '@backstage/core-components';
|
||||
import { EntityTable } from '@backstage/plugin-catalog-react';
|
||||
import ExtensionIcon from '@material-ui/icons/Extension';
|
||||
import { ToggleButton } from '@material-ui/lab';
|
||||
import ToggleButton from '@material-ui/lab/ToggleButton';
|
||||
import React, { useState } from 'react';
|
||||
import { ApiTypeTitle } from '../ApiDefinitionCard';
|
||||
import { ApiDefinitionDialog } from '../ApiDefinitionDialog';
|
||||
|
||||
@@ -18,7 +18,7 @@ import AsyncApi from '@asyncapi/react-component';
|
||||
import '@asyncapi/react-component/styles/default.css';
|
||||
import { makeStyles, alpha, darken } from '@material-ui/core/styles';
|
||||
import React from 'react';
|
||||
import { useTheme } from '@material-ui/core';
|
||||
import { useTheme } from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
ComponentEntity,
|
||||
RELATION_API_CONSUMED_BY,
|
||||
} from '@backstage/catalog-model';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
EntityTable,
|
||||
useEntity,
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
ComponentEntity,
|
||||
RELATION_API_PROVIDED_BY,
|
||||
} from '@backstage/catalog-model';
|
||||
import { Typography } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
EntityTable,
|
||||
useEntity,
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
+4
-1
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Divider, makeStyles, Tab, Tabs } from '@material-ui/core';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { JSONObject } from '@apollo/explorer/src/helpers/types';
|
||||
import { ApolloExplorer } from '@apollo/explorer/react';
|
||||
import { Content } from '@backstage/core-components';
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Grid, Typography, makeStyles } from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { InfoCard, Link } from '@backstage/core-components';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
|
||||
@@ -26,7 +26,7 @@ import { fetchCatalogItems } from '../../util/fetchMethods';
|
||||
import { parseBazaarProject } from '../../util/parseMethods';
|
||||
import { ErrorPanel, InfoCard, Link } from '@backstage/core-components';
|
||||
import { bazaarPlugin } from '../../plugin';
|
||||
import { IconButton } from '@material-ui/core';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import StorefrontIcon from '@material-ui/icons/Storefront';
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
|
||||
import { useElementFilter } from '@backstage/core-plugin-api';
|
||||
import { Grid, makeStyles, Typography } from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import React from 'react';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Grid,
|
||||
Card,
|
||||
CardContent,
|
||||
Typography,
|
||||
GridSize,
|
||||
} from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { GridSize } from '@material-ui/core/Grid';
|
||||
import { parseEntityRef } from '@backstage/catalog-model';
|
||||
import { Avatar, Link } from '@backstage/core-components';
|
||||
import { useRouteRef } from '@backstage/core-plugin-api';
|
||||
|
||||
@@ -18,12 +18,10 @@ import React from 'react';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import { Controller, Control, UseFormSetValue } from 'react-hook-form';
|
||||
import { FormValues } from '../../types';
|
||||
import {
|
||||
KeyboardDatePicker,
|
||||
MuiPickersUtilsProvider,
|
||||
} from '@material-ui/pickers';
|
||||
import { KeyboardDatePicker } from '@material-ui/pickers/DatePicker';
|
||||
import MuiPickersUtilsProvider from '@material-ui/pickers/MuiPickersUtilsProvider';
|
||||
import LuxonUtils from '@date-io/luxon';
|
||||
import { IconButton } from '@material-ui/core';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import ClearIcon from '@material-ui/icons/Clear';
|
||||
|
||||
type Props = {
|
||||
|
||||
@@ -18,7 +18,8 @@ import React from 'react';
|
||||
import { Control, UseFormSetValue } from 'react-hook-form';
|
||||
import { FormValues } from '../../types';
|
||||
import { DateSelector } from '../DateSelector/DateSelector';
|
||||
import { Typography, makeStyles } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
type Props = {
|
||||
control: Control<FormValues, object>;
|
||||
|
||||
@@ -21,7 +21,8 @@ import { BazaarProject, FormValues } from '../../types';
|
||||
import { bazaarApiRef } from '../../api';
|
||||
import { UseFormGetValues } from 'react-hook-form';
|
||||
import { ConfirmationDialog } from '../ConfirmationDialog';
|
||||
import { Button, makeStyles } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
type Props = {
|
||||
bazaarProject: BazaarProject;
|
||||
|
||||
@@ -21,7 +21,7 @@ import { stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { bazaarApiRef } from '../../api';
|
||||
import { EntityBazaarInfoContent } from '../EntityBazaarInfoContent';
|
||||
import { Card } from '@material-ui/core';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import { parseBazaarResponse } from '../../util/parseMethods';
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { CardHeader, Divider, IconButton, makeStyles } from '@material-ui/core';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
HeaderIconLinkRow,
|
||||
@@ -31,7 +34,7 @@ import { EditProjectDialog } from '../EditProjectDialog';
|
||||
import { useApi, identityApiRef } from '@backstage/core-plugin-api';
|
||||
import { BazaarProject, Member } from '../../types';
|
||||
import { bazaarApiRef } from '../../api';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import useAsyncFn from 'react-use/lib/useAsyncFn';
|
||||
import ExitToAppIcon from '@material-ui/icons/ExitToApp';
|
||||
import { parseEntityRef } from '@backstage/catalog-model';
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
Divider,
|
||||
IconButton,
|
||||
makeStyles,
|
||||
} from '@material-ui/core';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardHeader from '@material-ui/core/CardHeader';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import {
|
||||
HeaderIconLinkRow,
|
||||
@@ -45,7 +43,7 @@ import {
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { Member, BazaarProject } from '../../types';
|
||||
import { bazaarApiRef } from '../../api';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import useAsyncFn from 'react-use/lib/useAsyncFn';
|
||||
import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react';
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
FieldError,
|
||||
ValidationRule,
|
||||
} from 'react-hook-form';
|
||||
import { TextField } from '@material-ui/core';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import { FormValues } from '../../types';
|
||||
|
||||
type Rules = {
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Dialog,
|
||||
DialogActions,
|
||||
Button,
|
||||
DialogContent,
|
||||
makeStyles,
|
||||
} from '@material-ui/core';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { ProjectSelector } from '../ProjectSelector';
|
||||
import { CustomDialogTitle } from '../CustomDialogTitle';
|
||||
import { Entity, stringifyEntityRef } from '@backstage/catalog-model';
|
||||
|
||||
@@ -16,14 +16,12 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { ItemCardHeader } from '@backstage/core-components';
|
||||
import {
|
||||
Card,
|
||||
CardActionArea,
|
||||
CardContent,
|
||||
Dialog,
|
||||
makeStyles,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardActionArea from '@material-ui/core/CardActionArea';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { StatusTag } from '../StatusTag/StatusTag';
|
||||
import { BazaarProject } from '../../types';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Dialog } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import { useForm, UseFormReset, UseFormGetValues } from 'react-hook-form';
|
||||
import { InputField } from '../InputField/InputField';
|
||||
import { InputSelector } from '../InputSelector/InputSelector';
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
import React, { ChangeEvent, useState } from 'react';
|
||||
import { ProjectCard } from '../ProjectCard/ProjectCard';
|
||||
import {
|
||||
Box,
|
||||
makeStyles,
|
||||
Grid,
|
||||
TablePagination,
|
||||
GridSize,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import TablePagination from '@material-ui/core/TablePagination';
|
||||
import { GridSize } from '@material-ui/core/Grid';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { BazaarProject } from '../../types';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
import React from 'react';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Autocomplete } from '@material-ui/lab';
|
||||
import { TextField, makeStyles } from '@material-ui/core';
|
||||
import Autocomplete from '@material-ui/lab/Autocomplete';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
type Props = {
|
||||
catalogEntities: Entity[];
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, ReactNode } from 'react';
|
||||
import { FormControl, MenuItem, Select, makeStyles } from '@material-ui/core';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import MenuItem from '@material-ui/core/MenuItem';
|
||||
import Select from '@material-ui/core/Select';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
const useStyles = makeStyles({
|
||||
select: {
|
||||
|
||||
@@ -18,14 +18,15 @@ import React, { ChangeEvent, useEffect, useState } from 'react';
|
||||
import { Content, SupportButton } from '@backstage/core-components';
|
||||
import { AddProjectDialog } from '../AddProjectDialog';
|
||||
import { ProjectPreview } from '../ProjectPreview/ProjectPreview';
|
||||
import { Button, makeStyles } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import useAsyncFn from 'react-use/lib/useAsyncFn';
|
||||
import { Entity, stringifyEntityRef } from '@backstage/catalog-model';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { BazaarProject } from '../../types';
|
||||
import { bazaarApiRef } from '../../api';
|
||||
import { Alert } from '@material-ui/lab';
|
||||
import Alert from '@material-ui/lab/Alert';
|
||||
import SearchBar from 'material-ui-search-bar';
|
||||
import {
|
||||
sortByDate,
|
||||
|
||||
@@ -32,7 +32,7 @@ type PaginatedCatalogTableProps = {
|
||||
* @internal
|
||||
*/
|
||||
export function PaginatedCatalogTable(props: PaginatedCatalogTableProps) {
|
||||
const { columns, data, next, prev, title, isLoading } = props;
|
||||
const { columns, data, next, prev, title, isLoading, options } = props;
|
||||
const { updateFilters } = useEntityList();
|
||||
|
||||
return (
|
||||
@@ -41,6 +41,8 @@ export function PaginatedCatalogTable(props: PaginatedCatalogTableProps) {
|
||||
columns={columns}
|
||||
data={data}
|
||||
options={{
|
||||
...options,
|
||||
// These settings are configured to force server side pagination
|
||||
paginationPosition: 'both',
|
||||
pageSizeOptions: [],
|
||||
showFirstLastPageButtons: false,
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -17,7 +17,9 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { BuildWithSteps, BuildStepAction } from '../../api';
|
||||
import { Grid, Box, Typography } from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { ActionOutput } from './lib/ActionOutput/ActionOutput';
|
||||
import LaunchIcon from '@material-ui/icons/Launch';
|
||||
|
||||
+4
-6
@@ -15,12 +15,10 @@
|
||||
*/
|
||||
|
||||
import { LogViewer } from '@backstage/core-components';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionDetails,
|
||||
AccordionSummary,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import Accordion from '@material-ui/core/Accordion';
|
||||
import AccordionDetails from '@material-ui/core/AccordionDetails';
|
||||
import AccordionSummary from '@material-ui/core/AccordionSummary';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import { BuildStepAction } from 'circleci-api';
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Builds } from './lib/Builds';
|
||||
import { Grid } from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
|
||||
export const BuildsPage = () => (
|
||||
<Grid container spacing={3} direction="column">
|
||||
|
||||
@@ -15,14 +15,12 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Avatar,
|
||||
Typography,
|
||||
Box,
|
||||
IconButton,
|
||||
makeStyles,
|
||||
Tooltip,
|
||||
} from '@material-ui/core';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import RetryIcon from '@material-ui/icons/Replay';
|
||||
import GitHubIcon from '@material-ui/icons/GitHub';
|
||||
import LaunchIcon from '@material-ui/icons/Launch';
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -19,7 +19,8 @@ import { useWorkflowRuns, WorkflowRun } from '../useWorkflowRuns';
|
||||
import { WorkflowRunsTable } from '../WorkflowRunsTable';
|
||||
import { useEntity } from '@backstage/plugin-catalog-react';
|
||||
import { WorkflowRunStatus } from '../WorkflowRunStatus';
|
||||
import { makeStyles, LinearProgress } from '@material-ui/core';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ExternalLinkIcon from '@material-ui/icons/Launch';
|
||||
import { CLOUDBUILD_ANNOTATION } from '../useProjectName';
|
||||
import { getLocation } from '../useLocation';
|
||||
|
||||
@@ -15,18 +15,16 @@
|
||||
*/
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import {
|
||||
Box,
|
||||
LinearProgress,
|
||||
makeStyles,
|
||||
Paper,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableRow,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Table from '@material-ui/core/Table';
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableCell from '@material-ui/core/TableCell';
|
||||
import TableContainer from '@material-ui/core/TableContainer';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import ExternalLinkIcon from '@material-ui/icons/Launch';
|
||||
import qs from 'qs';
|
||||
import React from 'react';
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Typography, Box, IconButton, Tooltip } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import RetryIcon from '@material-ui/icons/Replay';
|
||||
import GoogleIcon from '@material-ui/icons/CloudCircle';
|
||||
import { useWorkflowRuns, WorkflowRun } from '../useWorkflowRuns';
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ import { ReactNode } from 'react';
|
||||
import { ResultHighlight } from '@backstage/plugin-search-common';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { SearchResultListItemExtensionProps } from '@backstage/plugin-search-react';
|
||||
import { TabProps } from '@material-ui/core';
|
||||
import { TabProps } from '@material-ui/core/Tab';
|
||||
|
||||
// @public @deprecated (undocumented)
|
||||
export const catalogEntityRouteRef: ExternalRouteRef<
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { Button } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import React from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import { EntityCard } from '../EntityCard';
|
||||
|
||||
@@ -21,14 +21,12 @@ import {
|
||||
getEntityRelations,
|
||||
entityRouteRef,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
CardActions,
|
||||
CardContent,
|
||||
CardMedia,
|
||||
Chip,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import React from 'react';
|
||||
|
||||
import { LinkButton, ItemCardHeader } from '@backstage/core-components';
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { DomainEntity } from '@backstage/catalog-model';
|
||||
import { catalogApiRef } from '@backstage/plugin-catalog-react';
|
||||
import { Button } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import React from 'react';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
import {
|
||||
|
||||
@@ -21,14 +21,12 @@ import {
|
||||
getEntityRelations,
|
||||
entityRouteRef,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
CardActions,
|
||||
CardContent,
|
||||
CardMedia,
|
||||
Chip,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import React from 'react';
|
||||
|
||||
import { LinkButton, ItemCardHeader } from '@backstage/core-components';
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
attachComponentData,
|
||||
useElementFilter,
|
||||
} from '@backstage/core-plugin-api';
|
||||
import { TabProps } from '@material-ui/core';
|
||||
import { TabProps } from '@material-ui/core/Tab';
|
||||
import { default as React } from 'react';
|
||||
|
||||
// TODO: This layout could be a shared based component if it was possible to create custom TabbedLayouts
|
||||
|
||||
@@ -33,7 +33,8 @@ import {
|
||||
getEntityRelations,
|
||||
EntityDisplayName,
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { makeStyles, Typography, useTheme } from '@material-ui/core';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles, useTheme } from '@material-ui/core/styles';
|
||||
import ZoomOutMap from '@material-ui/icons/ZoomOutMap';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
@@ -15,17 +15,14 @@
|
||||
*/
|
||||
|
||||
import { ExploreTool } from '@backstage/plugin-explore-react';
|
||||
import {
|
||||
Box,
|
||||
Card,
|
||||
CardActions,
|
||||
CardContent,
|
||||
CardMedia,
|
||||
Chip,
|
||||
makeStyles,
|
||||
Theme,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Card from '@material-ui/core/Card';
|
||||
import CardActions from '@material-ui/core/CardActions';
|
||||
import CardContent from '@material-ui/core/CardContent';
|
||||
import CardMedia from '@material-ui/core/CardMedia';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles, Theme } from '@material-ui/core/styles';
|
||||
import { LinkButton } from '@backstage/core-components';
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
+5
-7
@@ -15,13 +15,11 @@
|
||||
*/
|
||||
|
||||
import React, { ReactNode } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Chip,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
makeStyles,
|
||||
} from '@material-ui/core';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import ListItemIcon from '@material-ui/core/ListItemIcon';
|
||||
import ListItemText from '@material-ui/core/ListItemText';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import { Link } from '@backstage/core-components';
|
||||
import {
|
||||
IndexableDocument,
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname, {
|
||||
rules: {
|
||||
'@backstage/no-top-level-material-ui-4-imports': 'error',
|
||||
},
|
||||
});
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Grid, Typography } from '@material-ui/core';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import {
|
||||
ErrorPanel,
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
} from '@backstage/plugin-catalog-react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import { KubernetesContent } from './KubernetesContent';
|
||||
import { Button } from '@material-ui/core';
|
||||
import Button from '@material-ui/core/Button';
|
||||
|
||||
const KUBERNETES_ANNOTATION = 'backstage.io/kubernetes-id';
|
||||
const KUBERNETES_LABEL_SELECTOR_QUERY_ANNOTATION =
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
|
||||
import { DatabaseNotificationsStore } from './DatabaseNotificationsStore';
|
||||
import { Knex } from 'knex';
|
||||
import { Notification } from '@backstage/plugin-notifications-common';
|
||||
import {
|
||||
Notification,
|
||||
NotificationSeverity,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
|
||||
jest.setTimeout(60_000);
|
||||
|
||||
@@ -48,6 +51,7 @@ const id4 = '04e0871e-e60a-4f68-8110-5ae3513f992e';
|
||||
const id5 = '05e0871e-e60a-4f68-8110-5ae3513f992e';
|
||||
const id6 = '06e0871e-e60a-4f68-8110-5ae3513f992e';
|
||||
const id7 = '07e0871e-e60a-4f68-8110-5ae3513f992e';
|
||||
const ids = [id1, id2, id3, id4, id5, id6, id7];
|
||||
|
||||
const now = Date.now();
|
||||
const timeDelay = 5 * 1000; /* 5 secs */
|
||||
@@ -269,6 +273,64 @@ describe.each(databases.eachSupportedId())(
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNotifications filters on severity', () => {
|
||||
beforeEach(async () => {
|
||||
const severities: (NotificationSeverity | undefined)[] = [
|
||||
'normal',
|
||||
undefined,
|
||||
'critical',
|
||||
'high',
|
||||
'low',
|
||||
];
|
||||
await Promise.all(
|
||||
severities.map((severity, idx) =>
|
||||
storage.saveNotification({
|
||||
id: ids[idx],
|
||||
user,
|
||||
origin: 'test-origin',
|
||||
created: new Date(now - idx * timeDelay),
|
||||
payload: {
|
||||
title: severity || 'default',
|
||||
severity,
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
it('normal', async () => {
|
||||
const normal = await storage.getNotifications({
|
||||
user,
|
||||
minimumSeverity: 'normal',
|
||||
});
|
||||
expect(normal.map(idOnly)).toEqual([id1, id2, id3, id4]);
|
||||
});
|
||||
|
||||
it('critical', async () => {
|
||||
const critical = await storage.getNotifications({
|
||||
user,
|
||||
minimumSeverity: 'critical',
|
||||
});
|
||||
expect(critical.length).toBe(1);
|
||||
expect(critical.at(0)?.id).toEqual(id3);
|
||||
});
|
||||
|
||||
it('high', async () => {
|
||||
const high = await storage.getNotifications({
|
||||
user,
|
||||
minimumSeverity: 'high',
|
||||
});
|
||||
expect(high.map(idOnly)).toEqual([id3, id4]);
|
||||
});
|
||||
|
||||
it('low', async () => {
|
||||
const low = await storage.getNotifications({
|
||||
user,
|
||||
minimumSeverity: 'low',
|
||||
});
|
||||
expect(low.map(idOnly)).toEqual([id1, id2, id3, id4, id5]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNotifications pagination', () => {
|
||||
beforeEach(async () => {
|
||||
await storage.saveNotification(testNotification1);
|
||||
@@ -455,13 +517,14 @@ describe.each(databases.eachSupportedId())(
|
||||
payload: {
|
||||
title: 'New notification',
|
||||
link: '/scaffolder/task/1234',
|
||||
severity: 'normal',
|
||||
severity: 'low',
|
||||
},
|
||||
} as any,
|
||||
});
|
||||
expect(existing).not.toBeNull();
|
||||
expect(existing?.id).toEqual(id2);
|
||||
expect(existing?.payload.title).toEqual('New notification');
|
||||
expect(existing?.payload.severity).toEqual('low');
|
||||
expect(existing?.read).toBeNull();
|
||||
});
|
||||
|
||||
|
||||
@@ -22,7 +22,10 @@ import {
|
||||
NotificationModifyOptions,
|
||||
NotificationsStore,
|
||||
} from './NotificationsStore';
|
||||
import { Notification } from '@backstage/plugin-notifications-common';
|
||||
import {
|
||||
Notification,
|
||||
NotificationSeverity,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
const migrationsDir = resolvePackagePath(
|
||||
@@ -46,6 +49,21 @@ const NOTIFICATION_COLUMNS = [
|
||||
'saved',
|
||||
];
|
||||
|
||||
const severities: NotificationSeverity[] = [
|
||||
'critical',
|
||||
'high',
|
||||
'normal',
|
||||
'low',
|
||||
];
|
||||
|
||||
export const normalizeSeverity = (input?: string): NotificationSeverity => {
|
||||
let lower = (input ?? 'normal').toLowerCase() as NotificationSeverity;
|
||||
if (severities.indexOf(lower) < 0) {
|
||||
lower = 'normal';
|
||||
}
|
||||
return lower;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
export class DatabaseNotificationsStore implements NotificationsStore {
|
||||
private isSQLite = false;
|
||||
@@ -107,7 +125,7 @@ export class DatabaseNotificationsStore implements NotificationsStore {
|
||||
link: notification.payload?.link,
|
||||
title: notification.payload?.title,
|
||||
description: notification.payload?.description,
|
||||
severity: notification.payload?.severity,
|
||||
severity: normalizeSeverity(notification.payload?.severity),
|
||||
scope: notification.payload?.scope,
|
||||
saved: notification.saved,
|
||||
read: notification.read,
|
||||
@@ -198,6 +216,12 @@ export class DatabaseNotificationsStore implements NotificationsStore {
|
||||
query.whereNull('saved');
|
||||
} // or match both if undefined
|
||||
|
||||
if (options.minimumSeverity !== undefined) {
|
||||
const idx = severities.indexOf(options.minimumSeverity);
|
||||
const equalOrHigher = severities.slice(0, idx + 1);
|
||||
query.whereIn('notification.severity', equalOrHigher);
|
||||
}
|
||||
|
||||
return query;
|
||||
};
|
||||
|
||||
@@ -296,17 +320,20 @@ export class DatabaseNotificationsStore implements NotificationsStore {
|
||||
return rows[0] as Notification;
|
||||
}
|
||||
|
||||
async restoreExistingNotification(options: {
|
||||
async restoreExistingNotification({
|
||||
id,
|
||||
notification,
|
||||
}: {
|
||||
id: string;
|
||||
notification: Notification;
|
||||
}) {
|
||||
const updateColumns = {
|
||||
title: options.notification.payload.title,
|
||||
description: options.notification.payload.description,
|
||||
link: options.notification.payload.link,
|
||||
topic: options.notification.payload.topic,
|
||||
title: notification.payload.title,
|
||||
description: notification.payload.description,
|
||||
link: notification.payload.link,
|
||||
topic: notification.payload.topic,
|
||||
updated: new Date(),
|
||||
severity: options.notification.payload.severity,
|
||||
severity: normalizeSeverity(notification.payload?.severity),
|
||||
read: null,
|
||||
};
|
||||
|
||||
@@ -320,7 +347,7 @@ export class DatabaseNotificationsStore implements NotificationsStore {
|
||||
broadcastQuery.update({ ...updateColumns, read: undefined }),
|
||||
]);
|
||||
|
||||
return await this.getNotification(options);
|
||||
return await this.getNotification({ id });
|
||||
}
|
||||
|
||||
async getNotification(options: { id: string }): Promise<Notification | null> {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import {
|
||||
Notification,
|
||||
NotificationSeverity,
|
||||
NotificationStatus,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
|
||||
@@ -32,6 +33,7 @@ export type NotificationGetOptions = {
|
||||
read?: boolean;
|
||||
saved?: boolean;
|
||||
createdAfter?: Date;
|
||||
minimumSeverity?: NotificationSeverity;
|
||||
};
|
||||
|
||||
/** @internal */
|
||||
|
||||
@@ -18,6 +18,7 @@ import express, { Request } from 'express';
|
||||
import Router from 'express-promise-router';
|
||||
import {
|
||||
DatabaseNotificationsStore,
|
||||
normalizeSeverity,
|
||||
NotificationGetOptions,
|
||||
} from '../database';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
@@ -236,6 +237,11 @@ export async function createRouter(
|
||||
}
|
||||
opts.createdAfter = new Date(sinceEpoch);
|
||||
}
|
||||
if (req.query.minimal_severity) {
|
||||
opts.minimumSeverity = normalizeSeverity(
|
||||
req.query.minimal_severity.toString(),
|
||||
);
|
||||
}
|
||||
|
||||
const [notifications, totalCount] = await Promise.all([
|
||||
store.getNotifications(opts),
|
||||
|
||||
@@ -11,6 +11,7 @@ import { DiscoveryApi } from '@backstage/core-plugin-api';
|
||||
import { FetchApi } from '@backstage/core-plugin-api';
|
||||
import { JSX as JSX_2 } from 'react';
|
||||
import { Notification as Notification_2 } from '@backstage/plugin-notifications-common';
|
||||
import { NotificationSeverity } from '@backstage/plugin-notifications-common';
|
||||
import { NotificationStatus } from '@backstage/plugin-notifications-common';
|
||||
import { default as React_2 } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
@@ -26,6 +27,7 @@ export type GetNotificationsOptions = {
|
||||
createdAfter?: Date;
|
||||
sort?: 'created' | 'topic' | 'origin';
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
minimumSeverity?: NotificationSeverity;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import { createApiRef } from '@backstage/core-plugin-api';
|
||||
import {
|
||||
Notification,
|
||||
NotificationSeverity,
|
||||
NotificationStatus,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
|
||||
@@ -34,6 +35,7 @@ export type GetNotificationsOptions = {
|
||||
createdAfter?: Date;
|
||||
sort?: 'created' | 'topic' | 'origin';
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
minimumSeverity?: NotificationSeverity;
|
||||
};
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -67,6 +67,9 @@ export class NotificationsClient implements NotificationsApi {
|
||||
if (options?.createdAfter !== undefined) {
|
||||
queryString.append('created_after', options.createdAfter.toISOString());
|
||||
}
|
||||
if (options?.minimumSeverity !== undefined) {
|
||||
queryString.append('minimal_severity', options.minimumSeverity);
|
||||
}
|
||||
const urlSegment = `?${queryString}`;
|
||||
|
||||
return await this.request<GetNotificationsResponse>(urlSegment);
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { GetNotificationsOptions } from '../../api';
|
||||
import { NotificationSeverity } from '@backstage/plugin-notifications-common';
|
||||
|
||||
export type SortBy = Required<
|
||||
Pick<GetNotificationsOptions, 'sort' | 'sortOrder'>
|
||||
@@ -39,6 +40,8 @@ export type NotificationsFiltersProps = {
|
||||
onSortingChanged: (sortBy: SortBy) => void;
|
||||
saved?: boolean;
|
||||
onSavedChanged: (checked: boolean | undefined) => void;
|
||||
severity: NotificationSeverity;
|
||||
onSeverityChanged: (severity: NotificationSeverity) => void;
|
||||
};
|
||||
|
||||
export const CreatedAfterOptions: {
|
||||
@@ -108,6 +111,13 @@ const getSortByText = (sortBy?: SortBy): string => {
|
||||
return 'newest';
|
||||
};
|
||||
|
||||
const AllSeverityOptions: { [key in NotificationSeverity]: string } = {
|
||||
critical: 'Critical',
|
||||
high: 'High',
|
||||
normal: 'Normal',
|
||||
low: 'Low',
|
||||
};
|
||||
|
||||
export const NotificationsFilters = ({
|
||||
sorting,
|
||||
onSortingChanged,
|
||||
@@ -117,6 +127,8 @@ export const NotificationsFilters = ({
|
||||
onCreatedAfterChanged,
|
||||
saved,
|
||||
onSavedChanged,
|
||||
severity,
|
||||
onSeverityChanged,
|
||||
}: NotificationsFiltersProps) => {
|
||||
const sortByText = getSortByText(sorting);
|
||||
|
||||
@@ -162,6 +174,14 @@ export const NotificationsFilters = ({
|
||||
viewValue = 'read';
|
||||
}
|
||||
|
||||
const handleOnSeverityChanged = (
|
||||
event: React.ChangeEvent<{ name?: string; value: unknown }>,
|
||||
) => {
|
||||
const value: NotificationSeverity =
|
||||
(event.target.value as NotificationSeverity) || 'normal';
|
||||
onSeverityChanged(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container>
|
||||
@@ -169,6 +189,7 @@ export const NotificationsFilters = ({
|
||||
<Typography variant="h6">Filters</Typography>
|
||||
<Divider variant="fullWidth" />
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth variant="outlined" size="small">
|
||||
<InputLabel id="notifications-filter-view">View</InputLabel>
|
||||
@@ -185,14 +206,16 @@ export const NotificationsFilters = ({
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth variant="outlined" size="small">
|
||||
<InputLabel id="notifications-filter-view">
|
||||
<InputLabel id="notifications-filter-created">
|
||||
Created after
|
||||
</InputLabel>
|
||||
|
||||
<Select
|
||||
label="Created after"
|
||||
labelId="notifications-filter-created"
|
||||
placeholder="Notifications since"
|
||||
value={createdAfter}
|
||||
onChange={handleOnCreatedAfterChanged}
|
||||
@@ -212,6 +235,7 @@ export const NotificationsFilters = ({
|
||||
|
||||
<Select
|
||||
label="Sort by"
|
||||
labelId="notifications-filter-sort"
|
||||
placeholder="Field to sort by"
|
||||
value={sortByText}
|
||||
onChange={handleOnSortByChanged}
|
||||
@@ -224,6 +248,25 @@ export const NotificationsFilters = ({
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<FormControl fullWidth variant="outlined" size="small">
|
||||
<InputLabel id="notifications-filter-severity">Severity</InputLabel>
|
||||
|
||||
<Select
|
||||
label="Severity"
|
||||
labelId="notifications-filter-severity"
|
||||
value={severity}
|
||||
onChange={handleOnSeverityChanged}
|
||||
>
|
||||
{Object.keys(AllSeverityOptions).map((key: string) => (
|
||||
<MenuItem value={key} key={key}>
|
||||
{AllSeverityOptions[key as NotificationSeverity]}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
SortByOptions,
|
||||
} from '../NotificationsFilters';
|
||||
import { GetNotificationsOptions } from '../../api';
|
||||
import { NotificationSeverity } from '@backstage/plugin-notifications-common';
|
||||
|
||||
export const NotificationsPage = () => {
|
||||
const [refresh, setRefresh] = React.useState(false);
|
||||
@@ -45,6 +46,7 @@ export const NotificationsPage = () => {
|
||||
const [sorting, setSorting] = React.useState<SortBy>(
|
||||
SortByOptions.newest.sortBy,
|
||||
);
|
||||
const [severity, setSeverity] = React.useState<NotificationSeverity>('low');
|
||||
|
||||
const { error, value, retry, loading } = useNotificationsApi(
|
||||
api => {
|
||||
@@ -52,6 +54,7 @@ export const NotificationsPage = () => {
|
||||
search: containsText,
|
||||
limit: pageSize,
|
||||
offset: pageNumber * pageSize,
|
||||
minimumSeverity: severity,
|
||||
...(sorting || {}),
|
||||
};
|
||||
if (unreadOnly !== undefined) {
|
||||
@@ -76,6 +79,7 @@ export const NotificationsPage = () => {
|
||||
pageSize,
|
||||
sorting,
|
||||
saved,
|
||||
severity,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -114,6 +118,8 @@ export const NotificationsPage = () => {
|
||||
sorting={sorting}
|
||||
saved={saved}
|
||||
onSavedChanged={setSaved}
|
||||
severity={severity}
|
||||
onSeverityChanged={setSeverity}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={10}>
|
||||
|
||||
@@ -33,6 +33,7 @@ import MarkAsUnreadIcon from '@material-ui/icons/Markunread' /* TODO: use Drafts
|
||||
import MarkAsReadIcon from '@material-ui/icons/CheckCircle';
|
||||
import MarkAsUnsavedIcon from '@material-ui/icons/LabelOff' /* TODO: use BookmarkRemove and BookmarkAdd once we have mui 5 icons */;
|
||||
import MarkAsSavedIcon from '@material-ui/icons/Label';
|
||||
import { SeverityIcon } from './SeverityIcon';
|
||||
|
||||
const ThrottleDelayMs = 1000;
|
||||
|
||||
@@ -93,6 +94,12 @@ export const NotificationsTable = ({
|
||||
|
||||
const compactColumns = React.useMemo(
|
||||
(): TableColumn<Notification>[] => [
|
||||
{
|
||||
width: '1rem',
|
||||
render: (notification: Notification) => (
|
||||
<SeverityIcon severity={notification.payload?.severity} />
|
||||
),
|
||||
},
|
||||
{
|
||||
customFilterAndSearch: () =>
|
||||
true /* Keep it on backend due to pagination. If recent flickering is an issue, implement search here as well. */,
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { NotificationSeverity } from '@backstage/plugin-notifications-common';
|
||||
import NormalIcon from '@material-ui/icons/CheckOutlined';
|
||||
import CriticalIcon from '@material-ui/icons/ErrorOutline';
|
||||
import HighIcon from '@material-ui/icons/WarningOutlined';
|
||||
import LowIcon from '@material-ui/icons/InfoOutlined';
|
||||
|
||||
export const SeverityIcon = ({
|
||||
severity,
|
||||
}: {
|
||||
severity?: NotificationSeverity;
|
||||
}) => {
|
||||
switch (severity) {
|
||||
case 'critical':
|
||||
return <CriticalIcon htmlColor="#C9190B" />;
|
||||
case 'high':
|
||||
return <HighIcon htmlColor="#F0AB00" />;
|
||||
case 'low':
|
||||
return <LowIcon htmlColor="#2B9AF3" />;
|
||||
case 'normal':
|
||||
default:
|
||||
return <NormalIcon htmlColor="#5BA352" />;
|
||||
}
|
||||
};
|
||||
@@ -3691,6 +3691,7 @@ __metadata:
|
||||
nodemon: ^3.0.1
|
||||
npm-packlist: ^5.0.0
|
||||
ora: ^5.3.0
|
||||
p-limit: ^3.1.0
|
||||
p-queue: ^6.6.2
|
||||
postcss: ^8.1.0
|
||||
process: ^0.11.10
|
||||
@@ -18735,12 +18736,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@types/dockerode@npm:^3.3.0, @types/dockerode@npm:^3.3.21":
|
||||
version: 3.3.24
|
||||
resolution: "@types/dockerode@npm:3.3.24"
|
||||
version: 3.3.26
|
||||
resolution: "@types/dockerode@npm:3.3.26"
|
||||
dependencies:
|
||||
"@types/docker-modem": "*"
|
||||
"@types/node": "*"
|
||||
checksum: 00329ba9225f5b57bfc0ba8c4dddb17100ebe13c5192fe8a14fce59eec456d258e814b6c78df26d7d7bb878fc38455f559f278490c9c8efad8f708335643b40e
|
||||
checksum: ec1e83ef2d938813c8fa72f7c8744a9bf598369d8a0f340377ddff25c6e7d118379cd297eecbe4af2b7aa64bf5cd1bb66b32d1e3874a062433b967265be94f09
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user