mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-20 01:28:45 +01:00
* feat(ui): setup eslint Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com> * chore(ui): update `lint:fix` command Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com> * fix(ui-lint): run `yarn lint:fix` > solve remaining manually Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com> * chore(ui): remove tslint from `ui` Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com> * chore(docs-ui): add docs for VSCode configuration eslint Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com> * chore(ui): prettier set `trailingComma` to `none` > prettier config default is changed after version bump - https://prettier.io/docs/en/options.html#trailing-commas Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com> --------- Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>
This commit is contained in:
committed by
GitHub
parent
ef96dec5b2
commit
7945b26d95
@@ -2,7 +2,7 @@
|
||||
|
||||
We use the following static code analysis tools:
|
||||
|
||||
* golangci-lint and tslint for compile time linting
|
||||
* golangci-lint and eslint for compile time linting
|
||||
* [codecov.io](https://codecov.io/gh/argoproj/argo-cd) - for code coverage
|
||||
* [snyk.io](https://app.snyk.io/org/argoproj/projects) - for image scanning
|
||||
* [sonarcloud.io](https://sonarcloud.io/organizations/argoproj/projects) - for code scans and security alerts
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
"tabWidth": 4,
|
||||
"jsxBracketSameLine": true,
|
||||
"quoteProps": "consistent",
|
||||
"arrowParens": "avoid"
|
||||
"arrowParens": "avoid",
|
||||
"trailingComma": "none"
|
||||
}
|
||||
|
||||
23
ui/README.md
23
ui/README.md
@@ -22,4 +22,25 @@ Make sure your code passes the lint checks:
|
||||
|
||||
```
|
||||
yarn lint --fix
|
||||
```
|
||||
```
|
||||
|
||||
If you are using VSCode, add this configuration to `.vscode/settings.json` in the root of this repository to identify and fix lint issues automatically before you save file.
|
||||
|
||||
Install [Eslint Extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) in VSCode.
|
||||
|
||||
`.vscode/settings.json`
|
||||
```json
|
||||
{
|
||||
"eslint.format.enable": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "always"
|
||||
},
|
||||
"eslint.workingDirectories": [
|
||||
{
|
||||
"directory": "./ui",
|
||||
"!cwd": false
|
||||
}
|
||||
],
|
||||
"eslint.experimental.useFlatConfig": true
|
||||
}
|
||||
```
|
||||
|
||||
37
ui/eslint.config.mjs
Normal file
37
ui/eslint.config.mjs
Normal file
@@ -0,0 +1,37 @@
|
||||
import globals from 'globals';
|
||||
import pluginJs from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import pluginReactConfig from 'eslint-plugin-react/configs/recommended.js';
|
||||
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||
|
||||
export default [
|
||||
{languageOptions: {globals: globals.browser}},
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
},
|
||||
...pluginReactConfig,
|
||||
rules: {
|
||||
'react/display-name': 'off',
|
||||
'react/no-string-refs': 'off'
|
||||
}
|
||||
},
|
||||
eslintPluginPrettierRecommended,
|
||||
{
|
||||
files: ['./src/**/*.{ts,tsx}']
|
||||
},
|
||||
{
|
||||
ignores: ['dist', 'assets', '**/*.config.js', '__mocks__', 'coverage', '**/*.test.{ts,tsx}']
|
||||
}
|
||||
];
|
||||
@@ -6,8 +6,8 @@
|
||||
"start": "webpack-dev-server --config ./src/app/webpack.config.js --mode development",
|
||||
"docker": "./scripts/build_docker.sh",
|
||||
"build": "find ./dist -type f -not -name gitkeep -delete && webpack --config ./src/app/webpack.config.js --mode production",
|
||||
"lint": "tsc --noEmit --project ./src/app && tslint -p ./src/app",
|
||||
"lint:fix": "tslint -p ./src/app --fix",
|
||||
"lint": "tsc --noEmit --project ./src/app && eslint",
|
||||
"lint:fix": "eslint --fix",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -69,6 +69,7 @@
|
||||
"@babel/preset-env": "^7.7.1",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.7.2",
|
||||
"@eslint/js": "^9.1.1",
|
||||
"@types/classnames": "^2.2.3",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"@types/dagre": "^0.7.40",
|
||||
@@ -96,6 +97,11 @@
|
||||
"codecov": "^3.8.3",
|
||||
"copy-webpack-plugin": "^6.1.1",
|
||||
"esbuild-loader": "^2.18.0",
|
||||
"eslint": "^9.1.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"globals": "^15.1.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^27.5.1",
|
||||
@@ -103,7 +109,7 @@
|
||||
"jest-transform-css": "^2.0.0",
|
||||
"monaco-editor-webpack-plugin": "^7.0.0",
|
||||
"postcss": "^8.4.38",
|
||||
"prettier": "1.19",
|
||||
"prettier": "^3.2.5",
|
||||
"raw-loader": "^0.5.1",
|
||||
"react-test-renderer": "16.8.3",
|
||||
"sass": "^1.49.9",
|
||||
@@ -112,11 +118,8 @@
|
||||
"style-loader": "^0.20.1",
|
||||
"ts-jest": "^27.1.3",
|
||||
"ts-node": "10.9.1",
|
||||
"tslint": "^6.1.3",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"tslint-plugin-prettier": "^2.0.1",
|
||||
"tslint-react": "^5.0.0",
|
||||
"typescript": "^4.9.5",
|
||||
"typescript-eslint": "^7.8.0",
|
||||
"webpack": "^5.84.1",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.7.4",
|
||||
|
||||
@@ -98,10 +98,7 @@ requests.onError.subscribe(async err => {
|
||||
}
|
||||
// Query for basehref and remove trailing /.
|
||||
// If basehref is the default `/` it will become an empty string.
|
||||
const basehref = document
|
||||
.querySelector('head > base')
|
||||
.getAttribute('href')
|
||||
.replace(/\/$/, '');
|
||||
const basehref = document.querySelector('head > base').getAttribute('href').replace(/\/$/, '');
|
||||
if (isSSO) {
|
||||
window.location.href = `${basehref}/auth/login?return_url=${encodeURIComponent(location.href)}`;
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
import {AutocompleteField, Checkbox, DataLoader, DropDownMenu, FormField, HelpIcon, Select} from 'argo-ui';
|
||||
import * as deepMerge from 'deepmerge';
|
||||
import * as React from 'react';
|
||||
|
||||
@@ -6,7 +6,6 @@ import {ResourceIcon} from '../resource-icon';
|
||||
import {ResourceLabel} from '../resource-label';
|
||||
import {ComparisonStatusIcon, HealthStatusIcon, nodeKey, createdOrNodeKey} from '../utils';
|
||||
import {Consumer} from '../../../shared/context';
|
||||
import * as _ from 'lodash';
|
||||
import Moment from 'react-moment';
|
||||
import {format} from 'date-fns';
|
||||
import {ResourceNode, ResourceRef} from '../../../shared/models';
|
||||
|
||||
@@ -250,8 +250,10 @@ export const ApplicationParameters = (props: {
|
||||
if (params) {
|
||||
for (const param of params) {
|
||||
if (param.map && param.array) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
param.map = param.array.reduce((acc, {name, value}) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
acc[name] = value;
|
||||
return acc;
|
||||
@@ -322,6 +324,7 @@ function gatherDetails(
|
||||
setAppParamsDeletedState: any
|
||||
): EditablePanelItem[] {
|
||||
const hasMultipleSources = app.spec.sources && app.spec.sources.length > 0;
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
const isHelm = source.hasOwnProperty('chart');
|
||||
if (hasMultipleSources) {
|
||||
attributes.push({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { format, parse } from './kustomize-image';
|
||||
import {format, parse} from './kustomize-image';
|
||||
|
||||
test('parse image version override', () => {
|
||||
const image = parse('foo/bar:v1.0.0');
|
||||
@@ -8,7 +8,7 @@ test('parse image version override', () => {
|
||||
});
|
||||
|
||||
test('format image version override', () => {
|
||||
const formatted = format({ name: 'foo/bar', newTag: 'v1.0.0' });
|
||||
const formatted = format({name: 'foo/bar', newTag: 'v1.0.0'});
|
||||
expect(formatted).toBe('foo/bar:v1.0.0');
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ test('parse image name override', () => {
|
||||
});
|
||||
|
||||
test('format image name override', () => {
|
||||
const formatted = format({ name: 'foo/bar', newTag: 'v1.0.0', newName: 'foo/bar1' });
|
||||
const formatted = format({name: 'foo/bar', newTag: 'v1.0.0', newName: 'foo/bar1'});
|
||||
expect(formatted).toBe('foo/bar=foo/bar1:v1.0.0');
|
||||
});
|
||||
|
||||
@@ -33,6 +33,6 @@ test('parse image digest override', () => {
|
||||
});
|
||||
|
||||
test('format image digest override', () => {
|
||||
const formatted = format({ name: 'foo/bar', digest: 'sha:123' });
|
||||
const formatted = format({name: 'foo/bar', digest: 'sha:123'});
|
||||
expect(formatted).toBe('foo/bar@sha:123');
|
||||
});
|
||||
|
||||
@@ -145,9 +145,7 @@ export class PodView extends React.Component<PodViewProps> {
|
||||
</Moment>
|
||||
</div>
|
||||
) : null}
|
||||
{group.info?.map(infoItem => (
|
||||
<div key={infoItem.name}>{infoItem.value}</div>
|
||||
))}
|
||||
{group.info?.map(infoItem => <div key={infoItem.name}>{infoItem.value}</div>)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,93 +1,109 @@
|
||||
import {compareNodes, describeNode, ResourceTreeNode} from "./application-resource-tree";
|
||||
import {compareNodes, describeNode, ResourceTreeNode} from './application-resource-tree';
|
||||
|
||||
test("describeNode.NoImages", () => {
|
||||
expect(describeNode({
|
||||
kind: "my-kind",
|
||||
name: "my-name",
|
||||
namespace: "my-ns",
|
||||
} as ResourceTreeNode)).toBe(`Kind: my-kind
|
||||
test('describeNode.NoImages', () => {
|
||||
expect(
|
||||
describeNode({
|
||||
kind: 'my-kind',
|
||||
name: 'my-name',
|
||||
namespace: 'my-ns',
|
||||
} as ResourceTreeNode),
|
||||
).toBe(`Kind: my-kind
|
||||
Namespace: my-ns
|
||||
Name: my-name`)
|
||||
Name: my-name`);
|
||||
});
|
||||
|
||||
test("describeNode.Images", () => {
|
||||
expect(describeNode({
|
||||
kind: "my-kind",
|
||||
name: "my-name",
|
||||
namespace: "my-ns",
|
||||
images: ['my-image:v1'],
|
||||
} as ResourceTreeNode)).toBe(`Kind: my-kind
|
||||
test('describeNode.Images', () => {
|
||||
expect(
|
||||
describeNode({
|
||||
kind: 'my-kind',
|
||||
name: 'my-name',
|
||||
namespace: 'my-ns',
|
||||
images: ['my-image:v1'],
|
||||
} as ResourceTreeNode),
|
||||
).toBe(`Kind: my-kind
|
||||
Namespace: my-ns
|
||||
Name: my-name
|
||||
Images:
|
||||
- my-image:v1`)
|
||||
- my-image:v1`);
|
||||
});
|
||||
|
||||
test("compareNodes", () => {
|
||||
test('compareNodes', () => {
|
||||
const nodes = [
|
||||
{
|
||||
resourceVersion: "1",
|
||||
name: "a",
|
||||
info: [{
|
||||
"name": "Revision",
|
||||
"value": "Rev:1"
|
||||
}],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: "1",
|
||||
name: "a",
|
||||
info: [{
|
||||
"name": "Revision",
|
||||
"value": "Rev:1"
|
||||
}],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: "1",
|
||||
name: "b",
|
||||
info: [{
|
||||
"name": "Revision",
|
||||
"value": "Rev:1"
|
||||
}],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: "2",
|
||||
name: "a",
|
||||
info: [{
|
||||
"name": "Revision",
|
||||
"value": "Rev:2"
|
||||
}],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: "2",
|
||||
name: "b",
|
||||
info: [{
|
||||
"name": "Revision",
|
||||
"value": "Rev:2"
|
||||
}],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: true,
|
||||
resourceVersion: "1",
|
||||
name: "a",
|
||||
info: [{
|
||||
"name": "Revision",
|
||||
"value": "Rev:1"
|
||||
}],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
resourceVersion: '1',
|
||||
name: 'a',
|
||||
info: [
|
||||
{
|
||||
name: 'Revision',
|
||||
value: 'Rev:1',
|
||||
},
|
||||
],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: '1',
|
||||
name: 'a',
|
||||
info: [
|
||||
{
|
||||
name: 'Revision',
|
||||
value: 'Rev:1',
|
||||
},
|
||||
],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: '1',
|
||||
name: 'b',
|
||||
info: [
|
||||
{
|
||||
name: 'Revision',
|
||||
value: 'Rev:1',
|
||||
},
|
||||
],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: '2',
|
||||
name: 'a',
|
||||
info: [
|
||||
{
|
||||
name: 'Revision',
|
||||
value: 'Rev:2',
|
||||
},
|
||||
],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: false,
|
||||
resourceVersion: '2',
|
||||
name: 'b',
|
||||
info: [
|
||||
{
|
||||
name: 'Revision',
|
||||
value: 'Rev:2',
|
||||
},
|
||||
],
|
||||
} as ResourceTreeNode,
|
||||
{
|
||||
orphaned: true,
|
||||
resourceVersion: '1',
|
||||
name: 'a',
|
||||
info: [
|
||||
{
|
||||
name: 'Revision',
|
||||
value: 'Rev:1',
|
||||
},
|
||||
],
|
||||
} as ResourceTreeNode,
|
||||
];
|
||||
expect(compareNodes(nodes[0], nodes[1])).toBe(0)
|
||||
expect(compareNodes(nodes[2], nodes[1])).toBe(1)
|
||||
expect(compareNodes(nodes[1], nodes[2])).toBe(-1)
|
||||
expect(compareNodes(nodes[3], nodes[2])).toBe(-1)
|
||||
expect(compareNodes(nodes[2], nodes[3])).toBe(1)
|
||||
expect(compareNodes(nodes[4], nodes[3])).toBe(1)
|
||||
expect(compareNodes(nodes[3], nodes[4])).toBe(-1)
|
||||
expect(compareNodes(nodes[5], nodes[4])).toBe(1)
|
||||
expect(compareNodes(nodes[4], nodes[5])).toBe(-1)
|
||||
expect(compareNodes(nodes[0], nodes[4])).toBe(-1)
|
||||
expect(compareNodes(nodes[4], nodes[0])).toBe(1)
|
||||
expect(compareNodes(nodes[0], nodes[1])).toBe(0);
|
||||
expect(compareNodes(nodes[2], nodes[1])).toBe(1);
|
||||
expect(compareNodes(nodes[1], nodes[2])).toBe(-1);
|
||||
expect(compareNodes(nodes[3], nodes[2])).toBe(-1);
|
||||
expect(compareNodes(nodes[2], nodes[3])).toBe(1);
|
||||
expect(compareNodes(nodes[4], nodes[3])).toBe(1);
|
||||
expect(compareNodes(nodes[3], nodes[4])).toBe(-1);
|
||||
expect(compareNodes(nodes[5], nodes[4])).toBe(1);
|
||||
expect(compareNodes(nodes[4], nodes[5])).toBe(-1);
|
||||
expect(compareNodes(nodes[0], nodes[4])).toBe(-1);
|
||||
expect(compareNodes(nodes[4], nodes[0])).toBe(1);
|
||||
});
|
||||
|
||||
@@ -94,15 +94,7 @@ const NODE_TYPES = {
|
||||
podGroup: 'pod_group'
|
||||
};
|
||||
// generate lots of colors with different darkness
|
||||
const TRAFFIC_COLORS = [0, 0.25, 0.4, 0.6]
|
||||
.map(darken =>
|
||||
BASE_COLORS.map(item =>
|
||||
color(item)
|
||||
.darken(darken)
|
||||
.hex()
|
||||
)
|
||||
)
|
||||
.reduce((first, second) => first.concat(second), []);
|
||||
const TRAFFIC_COLORS = [0, 0.25, 0.4, 0.6].map(darken => BASE_COLORS.map(item => color(item).darken(darken).hex())).reduce((first, second) => first.concat(second), []);
|
||||
|
||||
function getGraphSize(nodes: dagre.Node[]): {width: number; height: number} {
|
||||
let width = 0;
|
||||
@@ -892,7 +884,8 @@ export const ApplicationResourceTree = (props: ApplicationResourceTreeProps) =>
|
||||
resourceVersion: props.app.metadata.resourceVersion,
|
||||
group: 'argoproj.io',
|
||||
version: '',
|
||||
children: Array(),
|
||||
// @ts-expect-error its not any
|
||||
children: [],
|
||||
status: props.app.status.sync.status,
|
||||
health: props.app.status.health,
|
||||
uid: props.app.kind + '-' + props.app.metadata.namespace + '-' + props.app.metadata.name,
|
||||
@@ -1035,7 +1028,7 @@ export const ApplicationResourceTree = (props: ApplicationResourceTreeProps) =>
|
||||
const loadBalancers = root.networkingInfo.ingress.map(ingress => ingress.hostname || ingress.ip);
|
||||
const colorByService = new Map<string, string>();
|
||||
(childrenByParentKey.get(treeNodeKey(root)) || []).forEach((child, i) => colorByService.set(treeNodeKey(child), TRAFFIC_COLORS[i % TRAFFIC_COLORS.length]));
|
||||
(childrenByParentKey.get(treeNodeKey(root)) || []).sort(compareNodes).forEach((child, i) => {
|
||||
(childrenByParentKey.get(treeNodeKey(root)) || []).sort(compareNodes).forEach(child => {
|
||||
processNode(child, root, [colorByService.get(treeNodeKey(child))]);
|
||||
});
|
||||
if (root.podGroup && props.showCompactNodes) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
import * as React from 'react';
|
||||
import {FormApi, NestedForm, Text, Form} from 'react-form';
|
||||
import {Checkbox, FormField} from 'argo-ui';
|
||||
@@ -7,6 +8,7 @@ import * as models from '../../../shared/models';
|
||||
|
||||
import './application-retry-options.scss';
|
||||
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const durationRegex = /^([\d\.]+[HMS])+$/i;
|
||||
const durationRegexError = 'Should be 1h10m10s/10h10m/10m/10s';
|
||||
|
||||
|
||||
@@ -21,6 +21,6 @@ const retryOptionsView: Array<(initData: models.RetryStrategy) => React.ReactNod
|
||||
];
|
||||
|
||||
export const ApplicationRetryView = ({initValues}: {initValues?: models.RetryStrategy}) => {
|
||||
const result = !initValues ? 'Retry disabled' : retryOptionsView.map((render, i) => render(initValues));
|
||||
const result = !initValues ? 'Retry disabled' : retryOptionsView.map(render => render(initValues));
|
||||
return <div className='application-retry-option-view-list'>{result}</div>;
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
import {AutocompleteField, DropDownMenu, ErrorNotification, FormField, FormSelect, HelpIcon, NotificationType} from 'argo-ui';
|
||||
import * as React from 'react';
|
||||
import {FormApi, Text} from 'react-form';
|
||||
|
||||
@@ -10,6 +10,7 @@ import './edit-notification-subscriptions.scss';
|
||||
|
||||
export const NOTIFICATION_SUBSCRIPTION_ANNOTATION_PREFIX = 'notifications.argoproj.io/subscribe';
|
||||
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
export const NOTIFICATION_SUBSCRIPTION_ANNOTATION_REGEX = new RegExp(`^notifications\.argoproj\.io\/subscribe\.[a-zA-Z-]{1,100}\.[a-zA-Z-]{1,100}$`);
|
||||
|
||||
export type TNotificationSubscription = {
|
||||
@@ -96,20 +97,22 @@ export const useEditNotificationSubscriptions = (annotations: models.Application
|
||||
|
||||
const onRemoveSubscription = (idx: number) => idx >= 0 && setSubscriptions(subscriptions.filter((_, i) => i !== idx));
|
||||
|
||||
const withNotificationSubscriptions = (updateApp: ApplicationSummaryProps['updateApp']) => (...args: Parameters<ApplicationSummaryProps['updateApp']>) => {
|
||||
const app = args[0];
|
||||
const withNotificationSubscriptions =
|
||||
(updateApp: ApplicationSummaryProps['updateApp']) =>
|
||||
(...args: Parameters<ApplicationSummaryProps['updateApp']>) => {
|
||||
const app = args[0];
|
||||
|
||||
const notificationSubscriptionsRaw = notificationSubscriptionsParser.subscriptionsToAnnotations(subscriptions);
|
||||
const notificationSubscriptionsRaw = notificationSubscriptionsParser.subscriptionsToAnnotations(subscriptions);
|
||||
|
||||
if (Object.keys(notificationSubscriptionsRaw)?.length) {
|
||||
app.metadata.annotations = {
|
||||
...notificationSubscriptionsRaw,
|
||||
...(app.metadata.annotations || {})
|
||||
};
|
||||
}
|
||||
if (Object.keys(notificationSubscriptionsRaw)?.length) {
|
||||
app.metadata.annotations = {
|
||||
...notificationSubscriptionsRaw,
|
||||
...(app.metadata.annotations || {})
|
||||
};
|
||||
}
|
||||
|
||||
return updateApp(app, args[1]);
|
||||
};
|
||||
return updateApp(app, args[1]);
|
||||
};
|
||||
|
||||
const onResetNotificationSubscriptions = () => setSubscriptions(notificationSubscriptionsParser.annotationsToSubscriptions(annotations));
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ExternalLink, ExternalLinks, InvalidExternalLinkError } from './application-urls';
|
||||
import {ExternalLink, ExternalLinks, InvalidExternalLinkError} from './application-urls';
|
||||
|
||||
test('rejects malicious URLs', () => {
|
||||
expect(() => {
|
||||
@@ -29,24 +29,19 @@ test('allows relative URLs', () => {
|
||||
expect(new ExternalLink('/applications').ref).toEqual('/applications');
|
||||
});
|
||||
|
||||
|
||||
test('URLs format', () => {
|
||||
expect(new ExternalLink('https://localhost:8080/applications')).toEqual({
|
||||
ref: 'https://localhost:8080/applications',
|
||||
title: 'https://localhost:8080/applications',
|
||||
})
|
||||
});
|
||||
expect(new ExternalLink('title|https://localhost:8080/applications')).toEqual({
|
||||
ref: 'https://localhost:8080/applications',
|
||||
title: 'title',
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('malicious URLs from list to be removed', () => {
|
||||
const urls: string[] = [
|
||||
'javascript:alert("hi")',
|
||||
'https://localhost:8080/applications',
|
||||
]
|
||||
const urls: string[] = ['javascript:alert("hi")', 'https://localhost:8080/applications'];
|
||||
const links = ExternalLinks(urls);
|
||||
|
||||
expect(links).toHaveLength(1);
|
||||
@@ -56,16 +51,8 @@ test('malicious URLs from list to be removed', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
test('list to be sorted', () => {
|
||||
const urls: string[] = [
|
||||
'https://a',
|
||||
'https://b',
|
||||
'a|https://c',
|
||||
'z|https://c',
|
||||
'x|https://d',
|
||||
'x|https://c',
|
||||
]
|
||||
const urls: string[] = ['https://a', 'https://b', 'a|https://c', 'z|https://c', 'x|https://d', 'x|https://c'];
|
||||
const links = ExternalLinks(urls);
|
||||
|
||||
// 'a|https://c',
|
||||
@@ -75,12 +62,12 @@ test('list to be sorted', () => {
|
||||
// 'https://a',
|
||||
// 'https://b',
|
||||
expect(links).toHaveLength(6);
|
||||
expect(links[0].title).toEqual('a')
|
||||
expect(links[1].title).toEqual('x')
|
||||
expect(links[1].ref).toEqual('https://c')
|
||||
expect(links[2].title).toEqual('x')
|
||||
expect(links[2].ref).toEqual('https://d')
|
||||
expect(links[3].title).toEqual('z')
|
||||
expect(links[4].title).toEqual('https://a')
|
||||
expect(links[5].title).toEqual('https://b')
|
||||
expect(links[0].title).toEqual('a');
|
||||
expect(links[1].title).toEqual('x');
|
||||
expect(links[1].ref).toEqual('https://c');
|
||||
expect(links[2].title).toEqual('x');
|
||||
expect(links[2].ref).toEqual('https://d');
|
||||
expect(links[3].title).toEqual('z');
|
||||
expect(links[4].title).toEqual('https://a');
|
||||
expect(links[5].title).toEqual('https://b');
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ export const ApplicationsStatusBar = ({applications}: ApplicationsStatusBarProps
|
||||
|
||||
return (
|
||||
<Consumer>
|
||||
{ctx => (
|
||||
{() => (
|
||||
<>
|
||||
{totalItems > 1 && (
|
||||
<div className='status-bar'>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
type operatorFn = (labels: {[name: string]: string}, key: string, values: string[]) => boolean;
|
||||
|
||||
const operators: {[type: string]: operatorFn} = {
|
||||
|
||||
@@ -94,6 +94,7 @@ export const PodsLogsViewer = (props: PodLogsProps) => {
|
||||
useEffect(() => {
|
||||
// https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
|
||||
// matchNothing this is chosen instead of empty regexp, because that would match everything and break colored logs
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
setHighlight(filter === '' ? matchNothing : new RegExp(filter.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'));
|
||||
}, [filter]);
|
||||
|
||||
|
||||
@@ -373,7 +373,7 @@ async function getSources(app: models.Application) {
|
||||
const length = sources.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const aSource = sources[i];
|
||||
const repoDetail = await services.repos.appDetails(aSource, app.metadata.name, app.spec.project).catch(e => ({
|
||||
const repoDetail = await services.repos.appDetails(aSource, app.metadata.name, app.spec.project).catch(() => ({
|
||||
type: 'Directory' as AppSourceType,
|
||||
path: aSource.path
|
||||
}));
|
||||
|
||||
@@ -22,7 +22,7 @@ test('getAppOperationState.Operation', () => {
|
||||
test('getAppOperationState.Status', () => {
|
||||
const state = getAppOperationState({
|
||||
metadata: {},
|
||||
status: {operationState: {phase: OperationPhases.Error, startedAt: zero}}
|
||||
status: {operationState: {phase: OperationPhases.Error, startedAt: zero}},
|
||||
} as Application);
|
||||
|
||||
expect(state.phase).toBe(OperationPhases.Error);
|
||||
@@ -188,10 +188,10 @@ test('ResourceResultIcon.Hook.Running', () => {
|
||||
{
|
||||
hookType: 'Sync',
|
||||
hookPhase: OperationPhases.Running,
|
||||
message: 'my-message'
|
||||
message: 'my-message',
|
||||
} as ResourceResult
|
||||
}
|
||||
/>
|
||||
/>,
|
||||
)
|
||||
.toJSON();
|
||||
|
||||
|
||||
@@ -245,6 +245,7 @@ export const ComparisonStatusIcon = ({
|
||||
title = 'Synced';
|
||||
break;
|
||||
case appModels.SyncStatuses.OutOfSync:
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const requiresPruning = resource && resource.requiresPruning;
|
||||
className = requiresPruning ? 'fa fa-trash' : 'fa fa-arrow-alt-circle-up';
|
||||
title = 'OutOfSync';
|
||||
@@ -433,7 +434,7 @@ function getResourceActionsMenuItems(resource: ResourceTreeNode, metadata: model
|
||||
});
|
||||
}
|
||||
}
|
||||
} as MenuItem)
|
||||
}) as MenuItem
|
||||
);
|
||||
})
|
||||
.catch(() => [] as MenuItem[]);
|
||||
@@ -514,7 +515,7 @@ function getActionItems(
|
||||
iconClassName: `fa fa-fw ${link.iconClass ? link.iconClass : 'fa-external-link'}`,
|
||||
action: () => window.open(link.url, '_blank'),
|
||||
tooltip: link.description
|
||||
} as MenuItem)
|
||||
}) as MenuItem
|
||||
);
|
||||
})
|
||||
.catch(() => [] as MenuItem[]);
|
||||
@@ -610,8 +611,7 @@ export function renderResourceButtons(
|
||||
apis: ContextApis,
|
||||
appChanged: BehaviorSubject<appModels.Application>
|
||||
): React.ReactNode {
|
||||
let menuItems: Observable<ActionMenuItem[]>;
|
||||
menuItems = getActionItems(resource, application, tree, apis, appChanged, true);
|
||||
const menuItems: Observable<ActionMenuItem[]> = getActionItems(resource, application, tree, apis, appChanged, true);
|
||||
return (
|
||||
<DataLoader load={() => menuItems}>
|
||||
{items => (
|
||||
@@ -628,12 +628,7 @@ export function renderResourceButtons(
|
||||
}
|
||||
}}
|
||||
icon={item.iconClassName}
|
||||
tooltip={
|
||||
item.title
|
||||
.toString()
|
||||
.charAt(0)
|
||||
.toUpperCase() + item.title.toString().slice(1)
|
||||
}
|
||||
tooltip={item.title.toString().charAt(0).toUpperCase() + item.title.toString().slice(1)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@@ -1250,14 +1245,8 @@ export function appInstanceName(app: appModels.Application): string {
|
||||
}
|
||||
|
||||
export function formatCreationTimestamp(creationTimestamp: string) {
|
||||
const createdAt = moment
|
||||
.utc(creationTimestamp)
|
||||
.local()
|
||||
.format('MM/DD/YYYY HH:mm:ss');
|
||||
const fromNow = moment
|
||||
.utc(creationTimestamp)
|
||||
.local()
|
||||
.fromNow();
|
||||
const createdAt = moment.utc(creationTimestamp).local().format('MM/DD/YYYY HH:mm:ss');
|
||||
const fromNow = moment.utc(creationTimestamp).local().fromNow();
|
||||
return (
|
||||
<span>
|
||||
{createdAt}
|
||||
|
||||
@@ -219,7 +219,7 @@ export class CertsList extends React.Component<RouteComponentProps<any>> {
|
||||
let knownHostEntries: models.RepoCert[] = [];
|
||||
atob(params.certData)
|
||||
.split('\n')
|
||||
.forEach(function processEntry(item, index) {
|
||||
.forEach(function processEntry(item) {
|
||||
const trimmedLine = item.trimLeft();
|
||||
if (trimmedLine.startsWith('#') === false) {
|
||||
const knownHosts = trimmedLine.split(' ', 3);
|
||||
@@ -227,6 +227,7 @@ export class CertsList extends React.Component<RouteComponentProps<any>> {
|
||||
// Perform a little sanity check on the data - server
|
||||
// checks too, but let's not send it invalid data in
|
||||
// the first place.
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const subType = knownHosts[1].match(/^(ssh\-[a-z0-9]+|ecdsa-[a-z0-9\-]+)$/gi);
|
||||
if (subType != null) {
|
||||
// Key could be valid for multiple hosts
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {DropDownMenu, ErrorNotification, NotificationType} from 'argo-ui';
|
||||
import {Tooltip, Toolbar} from 'argo-ui';
|
||||
import * as React from 'react';
|
||||
import {RouteComponentProps} from 'react-router-dom';
|
||||
import {clusterName, ConnectionStateIcon, DataLoader, EmptyState, Page} from '../../../shared/components';
|
||||
import {Consumer, Context} from '../../../shared/context';
|
||||
import * as models from '../../../shared/models';
|
||||
@@ -46,7 +45,7 @@ const CustomTopBar = (props: {toolbar?: Toolbar | Observable<Toolbar>}) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ClustersList = (props: RouteComponentProps<{}>) => {
|
||||
export const ClustersList = () => {
|
||||
const clustersLoaderRef = React.useRef<DataLoader>();
|
||||
return (
|
||||
<Consumer>
|
||||
|
||||
@@ -574,7 +574,7 @@ export class ProjectDetails extends React.Component<RouteComponentProps<{name: s
|
||||
{
|
||||
title: 'NAME',
|
||||
view: proj.metadata.name,
|
||||
edit: (_: FormApi) => proj.metadata.name
|
||||
edit: () => proj.metadata.name
|
||||
},
|
||||
{
|
||||
title: 'DESCRIPTION',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
import {AutocompleteField, DropDownMenu, FormField, FormSelect, HelpIcon, NotificationType, SlidingPanel, Tooltip} from 'argo-ui';
|
||||
import * as PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
|
||||
@@ -54,14 +54,14 @@ export const BadgePanel = ({app, project, appNamespace, nsEnabled}: {app?: strin
|
||||
badgeType === 'URL'
|
||||
? badgeURL
|
||||
: badgeType === 'Markdown'
|
||||
? `[](${entityURL})`
|
||||
: badgeType === 'Textile'
|
||||
? `!${badgeURL}!:${entityURL}`
|
||||
: badgeType === 'Rdoc'
|
||||
? `{<img src="${badgeURL}" alt="${alt}" />}[${entityURL}]`
|
||||
: badgeType === 'AsciiDoc'
|
||||
? `image:${badgeURL}["${alt}", link="${entityURL}"]`
|
||||
: ''
|
||||
? `[](${entityURL})`
|
||||
: badgeType === 'Textile'
|
||||
? `!${badgeURL}!:${entityURL}`
|
||||
: badgeType === 'Rdoc'
|
||||
? `{<img src="${badgeURL}" alt="${alt}" />}[${entityURL}]`
|
||||
: badgeType === 'AsciiDoc'
|
||||
? `image:${badgeURL}["${alt}", link="${entityURL}"]`
|
||||
: ''
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -52,7 +52,7 @@ export class EditablePanel<T = {}> extends React.Component<EditablePanelProps<T>
|
||||
|
||||
public UNSAFE_componentWillReceiveProps(nextProps: EditablePanelProps<T>) {
|
||||
if (this.formApi && JSON.stringify(this.props.values) !== JSON.stringify(nextProps.values)) {
|
||||
if (!!nextProps.noReadonlyMode) {
|
||||
if (nextProps.noReadonlyMode) {
|
||||
this.formApi.setAllValues(nextProps.values);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ export class ErrorBoundary extends React.Component<{message?: string}, {hasError
|
||||
this.state = {hasError: false};
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error: React.ErrorInfo) {
|
||||
static getDerivedStateFromError() {
|
||||
return {hasError: true};
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export const Page = (props: PageProps) => {
|
||||
return (
|
||||
<DataLoader load={() => services.viewPreferences.getPreferences()}>
|
||||
{pref => (
|
||||
<div className={`${props.hideAuth ? 'page-wrapper' : ''} ${!!pref.hideSidebar ? 'sb-page-wrapper__sidebar-collapsed' : 'sb-page-wrapper'}`}>
|
||||
<div className={`${props.hideAuth ? 'page-wrapper' : ''} ${pref.hideSidebar ? 'sb-page-wrapper__sidebar-collapsed' : 'sb-page-wrapper'}`}>
|
||||
<ArgoPage
|
||||
title={props.title}
|
||||
children={props.children}
|
||||
|
||||
@@ -3,22 +3,19 @@ import * as React from 'react';
|
||||
import {ProgressPopup} from './progress-popup';
|
||||
|
||||
test('ProgressPopup.0%', () => {
|
||||
const state = renderer.create(<ProgressPopup onClose={() => {
|
||||
}} percentage={0} title={''}/>);
|
||||
const state = renderer.create(<ProgressPopup onClose={() => {}} percentage={0} title={''} />);
|
||||
|
||||
expect(state).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('ProgressPopup.50%', () => {
|
||||
const state = renderer.create(<ProgressPopup onClose={() => {
|
||||
}} percentage={50} title={'My Title'}/>);
|
||||
const state = renderer.create(<ProgressPopup onClose={() => {}} percentage={50} title={'My Title'} />);
|
||||
|
||||
expect(state).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('ProgressPopup.100%', () => {
|
||||
const state = renderer.create(<ProgressPopup onClose={() => {
|
||||
}} percentage={100} title={''}/>);
|
||||
const state = renderer.create(<ProgressPopup onClose={() => {}} percentage={100} title={''} />);
|
||||
|
||||
expect(state).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -1,33 +1,44 @@
|
||||
import * as renderer from 'react-test-renderer';
|
||||
import * as React from 'react';
|
||||
import {isSHA, Revision} from "./revision";
|
||||
import {isSHA, Revision} from './revision';
|
||||
|
||||
test('Revision.SHA1.Children', () => {
|
||||
const tree = renderer.create(<Revision repoUrl='http://github.com/my-org/my-repo' revision='24eb0b24099b2e9afff72558724e88125eaa0176'>foo</Revision>).toJSON();
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Revision repoUrl='http://github.com/my-org/my-repo' revision='24eb0b24099b2e9afff72558724e88125eaa0176'>
|
||||
foo
|
||||
</Revision>,
|
||||
)
|
||||
.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot()
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Revision.SHA1.NoChildren', () => {
|
||||
const tree = renderer.create(<Revision repoUrl='http://github.com/my-org/my-repo' revision='24eb0b24099b2e9afff72558724e88125eaa0176'/>).toJSON();
|
||||
const tree = renderer.create(<Revision repoUrl='http://github.com/my-org/my-repo' revision='24eb0b24099b2e9afff72558724e88125eaa0176' />).toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot()
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Revision.Branch.Children', () => {
|
||||
const tree = renderer.create(<Revision repoUrl='http://github.com/my-org/my-repo' revision='long-branch-name'>foo</Revision>).toJSON();
|
||||
const tree = renderer
|
||||
.create(
|
||||
<Revision repoUrl='http://github.com/my-org/my-repo' revision='long-branch-name'>
|
||||
foo
|
||||
</Revision>,
|
||||
)
|
||||
.toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot()
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
test('Revision.Branch.NoChildren', () => {
|
||||
const tree = renderer.create(<Revision repoUrl='http://github.com/my-org/my-repo' revision='long-branch-name'/>).toJSON();
|
||||
const tree = renderer.create(<Revision repoUrl='http://github.com/my-org/my-repo' revision='long-branch-name' />).toJSON();
|
||||
|
||||
expect(tree).toMatchSnapshot()
|
||||
expect(tree).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('isSHA1', () => {
|
||||
expect(isSHA('24eb0b24099b2e9afff72558724e88125eaa0176')).toBe(true);
|
||||
expect(isSHA('master')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,7 +16,8 @@ test('github.com', () => {
|
||||
'git@github.com:argoproj/argo-cd.git',
|
||||
'024dee09f543ce7bb5af7ca50260504d89dfda94',
|
||||
'https://github.com/argoproj/argo-cd',
|
||||
'https://github.com/argoproj/argo-cd/commit/024dee09f543ce7bb5af7ca50260504d89dfda94');
|
||||
'https://github.com/argoproj/argo-cd/commit/024dee09f543ce7bb5af7ca50260504d89dfda94',
|
||||
);
|
||||
});
|
||||
|
||||
// for enterprise github installations
|
||||
@@ -26,7 +27,8 @@ test('github.my-enterprise.com', () => {
|
||||
'git@github.my-enterprise.com:my-org/my-repo.git',
|
||||
'a06f2be80a4da89abb8ced904beab75b3ec6db0e',
|
||||
'https://github.my-enterprise.com/my-org/my-repo',
|
||||
'https://github.my-enterprise.com/my-org/my-repo/commit/a06f2be80a4da89abb8ced904beab75b3ec6db0e');
|
||||
'https://github.my-enterprise.com/my-org/my-repo/commit/a06f2be80a4da89abb8ced904beab75b3ec6db0e',
|
||||
);
|
||||
});
|
||||
|
||||
test('gitlab.com', () => {
|
||||
@@ -35,7 +37,8 @@ test('gitlab.com', () => {
|
||||
'git@gitlab.com:alex_collins/private-repo.git',
|
||||
'b1fe9426ead684d7af16958920968342ee295c1f',
|
||||
'https://gitlab.com/alex_collins/private-repo',
|
||||
'https://gitlab.com/alex_collins/private-repo/-/commit/b1fe9426ead684d7af16958920968342ee295c1f');
|
||||
'https://gitlab.com/alex_collins/private-repo/-/commit/b1fe9426ead684d7af16958920968342ee295c1f',
|
||||
);
|
||||
});
|
||||
|
||||
test('bitbucket.org', () => {
|
||||
@@ -44,7 +47,8 @@ test('bitbucket.org', () => {
|
||||
'git@bitbucket.org:alexcollinsinuit/test-repo.git',
|
||||
'38fb93957deb45ff546af13399a92ac0d568c350',
|
||||
'https://bitbucket.org/alexcollinsinuit/test-repo',
|
||||
'https://bitbucket.org/alexcollinsinuit/test-repo/commits/38fb93957deb45ff546af13399a92ac0d568c350');
|
||||
'https://bitbucket.org/alexcollinsinuit/test-repo/commits/38fb93957deb45ff546af13399a92ac0d568c350',
|
||||
);
|
||||
});
|
||||
|
||||
test('empty url', () => {
|
||||
|
||||
@@ -12,6 +12,6 @@ export interface ContextApis {
|
||||
baseHref: string;
|
||||
}
|
||||
export const Context = React.createContext<ContextApis & {history: History}>(null);
|
||||
export let {Provider, Consumer} = Context;
|
||||
export const {Provider, Consumer} = Context;
|
||||
|
||||
export const AuthSettingsCtx = React.createContext<models.AuthSettings>(null);
|
||||
|
||||
@@ -3,11 +3,11 @@ import {concatMaps} from './utils';
|
||||
test('map concatenation', () => {
|
||||
const map1 = {
|
||||
a: '1',
|
||||
b: '2'
|
||||
b: '2',
|
||||
};
|
||||
const map2 = {
|
||||
a: '9',
|
||||
c: '8'
|
||||
c: '8',
|
||||
};
|
||||
const map3 = concatMaps(map1, map2);
|
||||
expect(map3).toEqual(new Map(Object.entries({a: '9', b: '2', c: '8'})));
|
||||
|
||||
4
ui/src/app/typings.d.ts
vendored
4
ui/src/app/typings.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
declare var SYSTEM_INFO: { version: string; };
|
||||
declare let SYSTEM_INFO: {version: string};
|
||||
// suppress TS7016: Could not find a declaration file for module
|
||||
declare module 'react-diff-view';
|
||||
declare module 'unidiff';
|
||||
declare module 'unidiff';
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"tslint:recommended", "tslint-react", "tslint-plugin-prettier", "tslint-config-prettier"
|
||||
],
|
||||
"jsRules": {},
|
||||
"rules": {
|
||||
"prettier": true,
|
||||
"quotemark": [true, "single"],
|
||||
"no-var-requires": false,
|
||||
"interface-name": false,
|
||||
"jsx-no-multiline-js": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"jsx-alignment": false,
|
||||
"max-line-length": [true, 200],
|
||||
"jsx-no-lambda": false,
|
||||
"array-type": false,
|
||||
"max-classes-per-file": false,
|
||||
"newline-per-chained-call": false
|
||||
},
|
||||
"rulesDirectory": []
|
||||
}
|
||||
1483
ui/yarn.lock
1483
ui/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user