Browse Source

Update Next to 11.0.1 (including lint & import fixes) (#248)

* Bump next from 10.2.3 to 11.0.1

Bumps [next](https://github.com/vercel/next.js) from 10.2.3 to 11.0.1.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v10.2.3...v11.0.1)

---
updated-dependencies:
- dependency-name: next
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* 🚨 apply automatic linting

* 🎨 remove unused imports

* 🔇 allow console.* to give more debugging options

* 🎨 move stuff around to reduce linter messages

* 🚨 use destructuring so lint won't complain

* 📌 link Chartkick and Chart.js

Commit uses the linking code which was previously imported with
`import "chartkick/chart.js" [1]. Next did not like the import path,
but this does works now. ¯\_(ツ)_/¯

[1]: https://github.com/ankane/chartkick.js/blob/master/chart.js/chart.esm.js

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
pull/1886/head
Jannik 5 years ago committed by GitHub
parent
commit
be5243f5f8
  1. 1
      web/.eslintrc.js
  2. 7
      web/components/chart.tsx
  3. 9
      web/components/config/edit-custom-css.tsx
  4. 2
      web/components/config/edit-logo.tsx
  5. 10
      web/components/config/edit-social-links.tsx
  6. 9
      web/components/config/edit-tags.tsx
  7. 23
      web/components/config/form-textfield-with-submit.tsx
  8. 2
      web/components/config/social-icons-dropdown.tsx
  9. 21
      web/components/config/video-codec-selector.tsx
  10. 4
      web/components/config/video-variants-table.tsx
  11. 2
      web/components/main-layout.tsx
  12. 6
      web/components/message-visiblity-toggle.tsx
  13. 2
      web/components/news-feed.tsx
  14. 261
      web/package-lock.json
  15. 3
      web/package.json
  16. 43
      web/pages/access-tokens.tsx
  17. 154
      web/pages/actions.tsx
  18. 24
      web/pages/config-chat.tsx
  19. 9
      web/pages/config-video.tsx
  20. 22
      web/pages/offline-notice.tsx
  21. 94
      web/pages/webhooks.tsx
  22. 2
      web/types/config-section.ts

1
web/.eslintrc.js

@ -21,6 +21,7 @@ module.exports = {
'no-unused-vars': 'off', 'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error', '@typescript-eslint/no-unused-vars': 'error',
'no-console': 'off',
'no-use-before-define': [0], 'no-use-before-define': [0],
'@typescript-eslint/no-use-before-define': [1], '@typescript-eslint/no-use-before-define': [1],

7
web/components/chart.tsx

@ -1,7 +1,10 @@
import ChartJs from 'chart.js/auto';
import Chartkick from 'chartkick';
import format from 'date-fns/format';
import { LineChart } from 'react-chartkick'; import { LineChart } from 'react-chartkick';
import 'chartkick/chart.js'
import format from 'date-fns/format'; // from https://github.com/ankane/chartkick.js/blob/master/chart.js/chart.esm.js
Chartkick.use(ChartJs);
interface TimedValue { interface TimedValue {
time: Date; time: Date;

9
web/components/config/edit-custom-css.tsx

@ -86,13 +86,10 @@ export default function EditCustomStyles() {
<p className="description"> <p className="description">
Customize the look and feel of your Owncast instance by overriding the CSS styles of various Customize the look and feel of your Owncast instance by overriding the CSS styles of various
components on the page. Refer to the{' '} components on the page. Refer to the{' '}
<a <a href="https://owncast.online/docs/website/" rel="noopener noreferrer" target="_blank">
href="https://owncast.online/docs/website/"
rel="noopener noreferrer"
target="_blank"
>
CSS &amp; Components guide CSS &amp; Components guide
</a>. </a>
.
</p> </p>
<p className="description"> <p className="description">
Please input plain CSS text, as this will be directly injected onto your page during load. Please input plain CSS text, as this will be directly injected onto your page during load.

2
web/components/config/edit-logo.tsx

@ -91,7 +91,7 @@ export default function EditLogo() {
} }
}; };
const logoDisplayUrl = NEXT_PUBLIC_API_HOST + 'logo?random=' + logoCachedbuster; const logoDisplayUrl = `${NEXT_PUBLIC_API_HOST}logo?random=${logoCachedbuster}`;
return ( return (
<div className="formfield-container logo-upload-container"> <div className="formfield-container logo-upload-container">

10
web/components/config/edit-social-links.tsx

@ -3,7 +3,7 @@ import { Typography, Table, Button, Modal, Input } from 'antd';
import { ColumnsType } from 'antd/lib/table'; import { ColumnsType } from 'antd/lib/table';
import { DeleteOutlined } from '@ant-design/icons'; import { DeleteOutlined } from '@ant-design/icons';
import SocialDropdown from './social-icons-dropdown'; import SocialDropdown from './social-icons-dropdown';
import { fetchData, SOCIAL_PLATFORMS_LIST } from '../../utils/apis'; import { fetchData, SOCIAL_PLATFORMS_LIST, NEXT_PUBLIC_API_HOST } from '../../utils/apis';
import { ServerStatusContext } from '../../utils/server-status-context'; import { ServerStatusContext } from '../../utils/server-status-context';
import { import {
API_SOCIAL_HANDLES, API_SOCIAL_HANDLES,
@ -17,7 +17,6 @@ import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../../utils/urls';
import TextField from './form-textfield'; import TextField from './form-textfield';
import { createInputStatus, STATUS_ERROR, STATUS_SUCCESS } from '../../utils/input-statuses'; import { createInputStatus, STATUS_ERROR, STATUS_SUCCESS } from '../../utils/input-statuses';
import FormStatusIndicator from './form-status-indicator'; import FormStatusIndicator from './form-status-indicator';
import { NEXT_PUBLIC_API_HOST } from '../../utils/apis';
const { Title } = Typography; const { Title } = Typography;
@ -62,9 +61,8 @@ export default function EditSocialLinks() {
} }
}; };
const isPredefinedSocial = (platform: string) => { const isPredefinedSocial = (platform: string) =>
return availableIconsList.find(item => item.key === platform) || false; availableIconsList.find(item => item.key === platform) || false;
};
const selectedOther = const selectedOther =
modalDataState.platform !== '' && modalDataState.platform !== '' &&
@ -192,7 +190,7 @@ export default function EditSocialLinks() {
); );
} }
const { icon, platform: platformName } = platformInfo; const { icon, platform: platformName } = platformInfo;
const iconUrl = NEXT_PUBLIC_API_HOST + `${icon.slice(1)}`; const iconUrl = `${NEXT_PUBLIC_API_HOST}${icon.slice(1)}`;
return ( return (
<div className="social-handle-cell"> <div className="social-handle-cell">

9
web/components/config/edit-tags.tsx

@ -37,11 +37,12 @@ export default function EditInstanceTags() {
let resetTimer = null; let resetTimer = null;
useEffect(() => { useEffect(
return () => { () => () => {
clearTimeout(resetTimer); clearTimeout(resetTimer);
}; },
}, []); [],
);
const resetStates = () => { const resetStates = () => {
setSubmitStatus(null); setSubmitStatus(null);

23
web/components/config/form-textfield-with-submit.tsx

@ -1,10 +1,8 @@
import React, { useEffect, useState, useContext } from 'react';
import { Button } from 'antd'; import { Button } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { RESET_TIMEOUT, postConfigUpdateToAPI } from '../../utils/config-constants'; import React, { useContext, useEffect, useState } from 'react';
import { UpdateArgs } from '../../types/config-section';
import { ServerStatusContext } from '../../utils/server-status-context'; import { postConfigUpdateToAPI, RESET_TIMEOUT } from '../../utils/config-constants';
import TextField, { TextFieldProps } from './form-textfield';
import { import {
createInputStatus, createInputStatus,
StatusState, StatusState,
@ -12,8 +10,9 @@ import {
STATUS_PROCESSING, STATUS_PROCESSING,
STATUS_SUCCESS, STATUS_SUCCESS,
} from '../../utils/input-statuses'; } from '../../utils/input-statuses';
import { UpdateArgs } from '../../types/config-section'; import { ServerStatusContext } from '../../utils/server-status-context';
import FormStatusIndicator from './form-status-indicator'; import FormStatusIndicator from './form-status-indicator';
import TextField, { TextFieldProps } from './form-textfield';
export const TEXTFIELD_TYPE_TEXT = 'default'; export const TEXTFIELD_TYPE_TEXT = 'default';
export const TEXTFIELD_TYPE_PASSWORD = 'password'; // Input.Password export const TEXTFIELD_TYPE_PASSWORD = 'password'; // Input.Password
@ -72,13 +71,15 @@ export default function TextFieldWithSubmit(props: TextFieldWithSubmitProps) {
// if field is required but value is empty, or equals initial value, then don't show submit/update button. otherwise clear out any result messaging and display button. // if field is required but value is empty, or equals initial value, then don't show submit/update button. otherwise clear out any result messaging and display button.
const handleChange = ({ fieldName: changedFieldName, value: changedValue }: UpdateArgs) => { const handleChange = ({ fieldName: changedFieldName, value: changedValue }: UpdateArgs) => {
if (onChange) { if (onChange) {
let newValue: string = changedValue;
if (useTrim) {
newValue = changedValue.trim();
} else if (useTrimLead) {
newValue = changedValue.replace(/^\s+/g, '');
}
onChange({ onChange({
fieldName: changedFieldName, fieldName: changedFieldName,
value: useTrim value: newValue,
? changedValue.trim()
: useTrimLead
? changedValue.replace(/^\s+/g, '')
: changedValue,
}); });
} }
}; };

2
web/components/config/social-icons-dropdown.tsx

@ -39,7 +39,7 @@ export default function SocialDropdown({ iconList, selectedOption, onSelected }:
> >
{iconList.map(item => { {iconList.map(item => {
const { platform, icon, key } = item; const { platform, icon, key } = item;
const iconUrl = NEXT_PUBLIC_API_HOST + `${icon.slice(1)}`; const iconUrl = `${NEXT_PUBLIC_API_HOST}${icon.slice(1)}`;
return ( return (
<Select.Option className="social-option" key={`platform-${key}`} value={key}> <Select.Option className="social-option" key={`platform-${key}`} value={key}>

21
web/components/config/video-codec-selector.tsx

@ -1,19 +1,18 @@
import React, { useContext, useState, useEffect } from 'react'; import { Popconfirm, Select, Typography } from 'antd';
import { Typography, Select, Popconfirm } from 'antd'; import React, { useContext, useEffect, useState } from 'react';
import { ServerStatusContext } from '../../utils/server-status-context';
import { AlertMessageContext } from '../../utils/alert-message-context'; import { AlertMessageContext } from '../../utils/alert-message-context';
import { import {
API_VIDEO_CODEC, API_VIDEO_CODEC,
RESET_TIMEOUT,
postConfigUpdateToAPI, postConfigUpdateToAPI,
RESET_TIMEOUT,
} from '../../utils/config-constants'; } from '../../utils/config-constants';
import { import {
createInputStatus, createInputStatus,
StatusState, StatusState,
STATUS_ERROR, STATUS_ERROR,
STATUS_PROCESSING,
STATUS_SUCCESS, STATUS_SUCCESS,
} from '../../utils/input-statuses'; } from '../../utils/input-statuses';
import { ServerStatusContext } from '../../utils/server-status-context';
import FormStatusIndicator from './form-status-indicator'; import FormStatusIndicator from './form-status-indicator';
export default function CodecSelector() { export default function CodecSelector() {
@ -76,8 +75,8 @@ export default function CodecSelector() {
}); });
} }
const items = supportedCodecs.map(function (codec) { const items = supportedCodecs.map(codec => {
var title = codec; let title = codec;
if (title === 'libx264') { if (title === 'libx264') {
title = 'Default (libx264)'; title = 'Default (libx264)';
} else if (title === 'h264_nvenc') { } else if (title === 'h264_nvenc') {
@ -97,7 +96,7 @@ export default function CodecSelector() {
); );
}); });
var description = ''; let description = '';
if (selectedCodec === 'libx264') { if (selectedCodec === 'libx264') {
description = description =
'libx264 is the default codec and generally the only working choice for shared VPS enviornments. This is likely what you should be using unless you know you have set up other options.'; 'libx264 is the default codec and generally the only working choice for shared VPS enviornments. This is likely what you should be using unless you know you have set up other options.';
@ -138,10 +137,10 @@ export default function CodecSelector() {
<Popconfirm <Popconfirm
title={`Are you sure you want to change your video codec to ${pendingSaveCodec} and understand what this means?`} title={`Are you sure you want to change your video codec to ${pendingSaveCodec} and understand what this means?`}
visible={confirmPopupVisible} visible={confirmPopupVisible}
placement={'leftBottom'} placement="leftBottom"
onConfirm={save} onConfirm={save}
okText={'Yes'} okText="Yes"
cancelText={'No'} cancelText="No"
> >
<Select <Select
defaultValue={selectedCodec} defaultValue={selectedCodec}

4
web/components/config/video-variants-table.tsx

@ -149,8 +149,8 @@ export default function CurrentVariantsTable() {
title: '', title: '',
dataIndex: '', dataIndex: '',
key: 'edit', key: 'edit',
render: (data: VideoVariant) => { render: ({ key }: VideoVariant) => {
const index = data.key - 1; const index = key - 1;
return ( return (
<span className="actions"> <span className="actions">
<Button <Button

2
web/components/main-layout.tsx

@ -79,7 +79,7 @@ export default function MainLayout(props) {
const upgradeVersionString = `${upgradeVersion}` || ''; const upgradeVersionString = `${upgradeVersion}` || '';
const upgradeMessage = `Upgrade to v${upgradeVersionString}`; const upgradeMessage = `Upgrade to v${upgradeVersionString}`;
const chatMenuItemStyle = 'block'; //upgradeVersion ? 'block' : 'none'; const chatMenuItemStyle = 'block'; // upgradeVersion ? 'block' : 'none';
const clearAlertMessage = () => { const clearAlertMessage = () => {
alertMessage.setMessage(null); alertMessage.setMessage(null);

6
web/components/message-visiblity-toggle.tsx

@ -38,10 +38,8 @@ export default function MessageVisiblityToggle({
}, OUTCOME_TIMEOUT); }, OUTCOME_TIMEOUT);
}; };
useEffect(() => { useEffect(() => () => {
return () => { clearTimeout(outcomeTimeout);
clearTimeout(outcomeTimeout);
};
}); });
const updateChatMessage = async () => { const updateChatMessage = async () => {

2
web/components/news-feed.tsx

@ -61,7 +61,7 @@ export default function NewsFeed() {
getFeed(); getFeed();
}, []); }, []);
const loadingSpinner = loading ? <Skeleton loading={true} active /> : null; const loadingSpinner = loading ? <Skeleton loading active /> : null;
const noNews = !loading && feed.length === 0 ? <div>No news.</div> : null; const noNews = !loading && feed.length === 0 ? <div>No news.</div> : null;
return ( return (

261
web/package-lock.json generated

@ -132,9 +132,9 @@
} }
}, },
"@hapi/boom": { "@hapi/boom": {
"version": "9.1.2", "version": "9.1.3",
"resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.2.tgz", "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.3.tgz",
"integrity": "sha512-uJEJtiNHzKw80JpngDGBCGAmWjBtzxDCz17A9NO2zCi8LLBlb5Frpq4pXwyN+2JQMod4pKz5BALwyneCgDg89Q==", "integrity": "sha512-RlrGyZ603hE/eRTZtTltocRm50HHmrmL3kGOP0SQ9MasazlW1mt/fkv4C5P/6rnpFXjwld/POFX1C8tMZE3ldg==",
"requires": { "requires": {
"@hapi/hoek": "9.x.x" "@hapi/hoek": "9.x.x"
} }
@ -162,9 +162,9 @@
"dev": true "dev": true
}, },
"@next/env": { "@next/env": {
"version": "10.2.3", "version": "11.0.1",
"resolved": "https://registry.npmjs.org/@next/env/-/env-10.2.3.tgz", "resolved": "https://registry.npmjs.org/@next/env/-/env-11.0.1.tgz",
"integrity": "sha512-uBOjRBjsWC4C8X3DfmWWP6ekwLnf2JCCwQX9KVnJtJkqfDsv1yQPakdOEwvJzXQc3JC/v5KKffYPVmV2wHXCgQ==" "integrity": "sha512-yZfKh2U6R9tEYyNUrs2V3SBvCMufkJ07xMH5uWy8wqcl5gAXoEw6A/1LDqwX3j7pUutF9d1ZxpdGDA3Uag+aQQ=="
}, },
"@next/eslint-plugin-next": { "@next/eslint-plugin-next": {
"version": "11.0.1", "version": "11.0.1",
@ -173,14 +173,14 @@
"dev": true "dev": true
}, },
"@next/polyfill-module": { "@next/polyfill-module": {
"version": "10.2.3", "version": "11.0.1",
"resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-10.2.3.tgz", "resolved": "https://registry.npmjs.org/@next/polyfill-module/-/polyfill-module-11.0.1.tgz",
"integrity": "sha512-OkeY4cLhzfYbXxM4fd+6V4s5pTPuyfKSlavItfNRA6PpS7t1/R6YjO7S7rB8tu1pbTGuDHGIdE1ioDv15bAbDQ==" "integrity": "sha512-Cjs7rrKCg4CF4Jhri8PCKlBXhszTfOQNl9AjzdNy4K5jXFyxyoSzuX2rK4IuoyE+yGp5A3XJCBEmOQ4xbUp9Mg=="
}, },
"@next/react-dev-overlay": { "@next/react-dev-overlay": {
"version": "10.2.3", "version": "11.0.1",
"resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-10.2.3.tgz", "resolved": "https://registry.npmjs.org/@next/react-dev-overlay/-/react-dev-overlay-11.0.1.tgz",
"integrity": "sha512-E6g2jws4YW94l0lMMopBVKIZK2mEHfSBvM0d9dmzKG9L/A/kEq6LZCB4SiwGJbNsAdlk2y3USDa0oNbpA+m5Kw==", "integrity": "sha512-lvUjMVpLsgzADs9Q8wtC5LNqvfdN+M0BDMSrqr04EDWAyyX0vURHC9hkvLbyEYWyh+WW32pwjKBXdkMnJhoqMg==",
"requires": { "requires": {
"@babel/code-frame": "7.12.11", "@babel/code-frame": "7.12.11",
"anser": "1.4.9", "anser": "1.4.9",
@ -233,9 +233,9 @@
} }
}, },
"@next/react-refresh-utils": { "@next/react-refresh-utils": {
"version": "10.2.3", "version": "11.0.1",
"resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.2.3.tgz", "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-11.0.1.tgz",
"integrity": "sha512-qtBF56vPC6d6a8p7LYd0iRjW89fhY80kAIzmj+VonvIGjK/nymBjcFUhbKiMFqlhsarCksnhwX+Zmn95Dw9qvA==" "integrity": "sha512-K347DM6Z7gBSE+TfUaTTceWvbj0B6iNAsFZXbFZOlfg3uyz2sbKpzPYYFocCc27yjLaS8OfR8DEdS2mZXi8Saw=="
}, },
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
"version": "2.1.3", "version": "2.1.3",
@ -263,19 +263,6 @@
"fastq": "^1.6.0" "fastq": "^1.6.0"
} }
}, },
"@opentelemetry/api": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.14.0.tgz",
"integrity": "sha512-L7RMuZr5LzMmZiQSQDy9O1jo0q+DaLy6XpYJfIGfYSfoJA5qzYwUP3sP1uMIQ549DvxAgM3ng85EaPTM/hUHwQ==",
"requires": {
"@opentelemetry/context-base": "^0.14.0"
}
},
"@opentelemetry/context-base": {
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.14.0.tgz",
"integrity": "sha512-sDOAZcYwynHFTbLo6n8kIbLiVF3a3BLkrmehJUyEbT9F+Smbi47kLGS2gG2g0fjBLR/Lr1InPD7kXL7FaTqEkw=="
},
"@rushstack/eslint-patch": { "@rushstack/eslint-patch": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.0.6.tgz", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.0.6.tgz",
@ -721,101 +708,6 @@
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
"dev": true "dev": true
}, },
"array.prototype.filter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.0.tgz",
"integrity": "sha512-TfO1gz+tLm+Bswq0FBOXPqAchtCr2Rn48T8dLJoRFl8NoEosjZmzptmuo1X8aZBzZcqsR1W8U761tjACJtngTQ==",
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3",
"es-abstract": "^1.18.0",
"es-array-method-boxes-properly": "^1.0.0",
"is-string": "^1.0.5"
},
"dependencies": {
"es-abstract": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz",
"integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==",
"requires": {
"call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"get-intrinsic": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.2",
"is-callable": "^1.2.3",
"is-negative-zero": "^2.0.1",
"is-regex": "^1.1.2",
"is-string": "^1.0.5",
"object-inspect": "^1.9.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.2",
"string.prototype.trimend": "^1.0.4",
"string.prototype.trimstart": "^1.0.4",
"unbox-primitive": "^1.0.0"
}
},
"has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
},
"is-callable": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
"integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ=="
},
"is-negative-zero": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
"integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w=="
},
"is-regex": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz",
"integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==",
"requires": {
"call-bind": "^1.0.2",
"has-symbols": "^1.0.2"
}
},
"object-inspect": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
"integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw=="
},
"object.assign": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
"integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
"requires": {
"call-bind": "^1.0.0",
"define-properties": "^1.1.3",
"has-symbols": "^1.0.1",
"object-keys": "^1.1.1"
}
},
"string.prototype.trimend": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
"integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
}
},
"string.prototype.trimstart": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
"integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
"requires": {
"call-bind": "^1.0.2",
"define-properties": "^1.1.3"
}
}
}
},
"array.prototype.flat": { "array.prototype.flat": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz",
@ -891,12 +783,9 @@
"integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ==" "integrity": "sha512-8eLCg00W9pIRZSB781UUX/H6Oskmm8xloZfr09lz5bikRpBVDlJ3hRVuxxP1SxcwsEYfJ4IU8Q19Y8/893r3rQ=="
}, },
"available-typed-arrays": { "available-typed-arrays": {
"version": "1.0.3", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.3.tgz", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz",
"integrity": "sha512-CuPhFULixV/d89POo1UG4GqGbR7dmrefY2ZdmsYakeR4gOSJXoF7tfeaiqMHGOMrlTiJoeEs87fpLsBYmE2BMw==", "integrity": "sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA=="
"requires": {
"array.prototype.filter": "^1.0.0"
}
}, },
"axe-core": { "axe-core": {
"version": "4.1.2", "version": "4.1.2",
@ -1088,9 +977,9 @@
"dev": true "dev": true
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001228", "version": "1.0.30001243",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001243.tgz",
"integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==" "integrity": "sha512-vNxw9mkTBtkmLFnJRv/2rhs1yufpDfCkBZexG3Y0xdOH2Z/eE/85E4Dl5j1YUN34nZVsSp6vVRFQRrez9wJMRA=="
}, },
"chalk": { "chalk": {
"version": "2.4.2", "version": "2.4.2",
@ -1139,21 +1028,13 @@
"optional": true "optional": true
}, },
"chartkick": { "chartkick": {
"version": "4.0.3", "version": "4.0.5",
"resolved": "https://registry.npmjs.org/chartkick/-/chartkick-4.0.3.tgz", "resolved": "https://registry.npmjs.org/chartkick/-/chartkick-4.0.5.tgz",
"integrity": "sha512-e2WhXYE0VsevyTxol2J4WaHz26iuuSpduK9BVkvIIVrIt6TFlDw7Vm4iXSYIAsDMdC9/UsIV2ZtYIldMMXpvlA==", "integrity": "sha512-xKak4Fsgfvp1hj/LykRKkniDMaZASx2A4TdVc/sfsiNFFNf1m+D7PGwP1vgj1UsbsCjOCSfGWWyJpOYxkUCBug==",
"requires": { "requires": {
"chart.js": ">=3.0.2", "chart.js": ">=3.0.2",
"chartjs-adapter-date-fns": ">=2.0.0", "chartjs-adapter-date-fns": ">=2.0.0",
"date-fns": ">=2.0.0" "date-fns": ">=2.0.0"
},
"dependencies": {
"chart.js": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.1.0.tgz",
"integrity": "sha512-bKJi2VbC4fqZXlLbK7LKVvmG9crjoG9anfp96utZLyIGPuCx+YN+5/HDXy98QGt3lf74T8gKUPISUZL222tDJQ==",
"optional": true
}
} }
}, },
"chokidar": { "chokidar": {
@ -1469,9 +1350,9 @@
"integrity": "sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ==" "integrity": "sha512-fRA+BaAWOR/yr/t7T9E9GJztHPeFjj8U35ajyAjCDtAAnTn1Rc1f6W6VGPJrO1tkQv9zWu+JRof7z6oQtiYVFQ=="
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.3.736", "version": "1.3.771",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.771.tgz",
"integrity": "sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig==" "integrity": "sha512-zHMomTqkpnAD9W5rhXE1aiU3ogGFrqWzdvM4C6222SREiqsWQb2w0S7P2Ii44qCaGimmAP1z+OydllM438uJyA=="
}, },
"elliptic": { "elliptic": {
"version": "6.5.4", "version": "6.5.4",
@ -1555,11 +1436,6 @@
"string.prototype.trimstart": "^1.0.1" "string.prototype.trimstart": "^1.0.1"
} }
}, },
"es-array-method-boxes-properly": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="
},
"es-to-primitive": { "es-to-primitive": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
@ -2850,6 +2726,14 @@
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
"dev": true "dev": true
}, },
"image-size": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.0.tgz",
"integrity": "sha512-JLJ6OwBfO1KcA+TvJT+v8gbE6iWbj24LyDNFgFEN0lzegn6cC6a/p3NIDaepMsJjQjlUWqIC7wJv8lBFxPNjcw==",
"requires": {
"queue": "6.0.2"
}
},
"import-fresh": { "import-fresh": {
"version": "3.3.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@ -3067,9 +2951,9 @@
}, },
"dependencies": { "dependencies": {
"es-abstract": { "es-abstract": {
"version": "1.18.0", "version": "1.18.3",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz",
"integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==",
"requires": { "requires": {
"call-bind": "^1.0.2", "call-bind": "^1.0.2",
"es-to-primitive": "^1.2.1", "es-to-primitive": "^1.2.1",
@ -3079,14 +2963,14 @@
"has-symbols": "^1.0.2", "has-symbols": "^1.0.2",
"is-callable": "^1.2.3", "is-callable": "^1.2.3",
"is-negative-zero": "^2.0.1", "is-negative-zero": "^2.0.1",
"is-regex": "^1.1.2", "is-regex": "^1.1.3",
"is-string": "^1.0.5", "is-string": "^1.0.6",
"object-inspect": "^1.9.0", "object-inspect": "^1.10.3",
"object-keys": "^1.1.1", "object-keys": "^1.1.1",
"object.assign": "^4.1.2", "object.assign": "^4.1.2",
"string.prototype.trimend": "^1.0.4", "string.prototype.trimend": "^1.0.4",
"string.prototype.trimstart": "^1.0.4", "string.prototype.trimstart": "^1.0.4",
"unbox-primitive": "^1.0.0" "unbox-primitive": "^1.0.1"
}, },
"dependencies": { "dependencies": {
"has-symbols": { "has-symbols": {
@ -3122,6 +3006,11 @@
} }
} }
}, },
"is-string": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz",
"integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w=="
},
"object-inspect": { "object-inspect": {
"version": "1.10.3", "version": "1.10.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz",
@ -3673,17 +3562,16 @@
"dev": true "dev": true
}, },
"next": { "next": {
"version": "10.2.3", "version": "11.0.1",
"resolved": "https://registry.npmjs.org/next/-/next-10.2.3.tgz", "resolved": "https://registry.npmjs.org/next/-/next-11.0.1.tgz",
"integrity": "sha512-dkM1mIfnORtGyzw/Yme8RdqNxlCMZyi4Lqj56F01/yHbe1ZtOaJ0cyqqRB4RGiPhjGGh0319f8ddjDyO1605Ow==", "integrity": "sha512-yR7be7asNbvpVNpi6xxEg28wZ7Gqmj1nOt0sABH9qORmF3+pms2KZ7Cng33oK5nqPIzEEFJD0pp2PCe3/ueMIg==",
"requires": { "requires": {
"@babel/runtime": "7.12.5", "@babel/runtime": "7.12.5",
"@hapi/accept": "5.0.2", "@hapi/accept": "5.0.2",
"@next/env": "10.2.3", "@next/env": "11.0.1",
"@next/polyfill-module": "10.2.3", "@next/polyfill-module": "11.0.1",
"@next/react-dev-overlay": "10.2.3", "@next/react-dev-overlay": "11.0.1",
"@next/react-refresh-utils": "10.2.3", "@next/react-refresh-utils": "11.0.1",
"@opentelemetry/api": "0.14.0",
"assert": "2.0.0", "assert": "2.0.0",
"ast-types": "0.13.2", "ast-types": "0.13.2",
"browserify-zlib": "0.2.0", "browserify-zlib": "0.2.0",
@ -3701,6 +3589,7 @@
"find-cache-dir": "3.3.1", "find-cache-dir": "3.3.1",
"get-orientation": "1.1.2", "get-orientation": "1.1.2",
"https-browserify": "1.0.0", "https-browserify": "1.0.0",
"image-size": "1.0.0",
"jest-worker": "27.0.0-next.5", "jest-worker": "27.0.0-next.5",
"native-url": "0.3.4", "native-url": "0.3.4",
"node-fetch": "2.6.1", "node-fetch": "2.6.1",
@ -3715,7 +3604,7 @@
"prop-types": "15.7.2", "prop-types": "15.7.2",
"querystring-es3": "0.2.1", "querystring-es3": "0.2.1",
"raw-body": "2.4.1", "raw-body": "2.4.1",
"react-is": "16.13.1", "react-is": "17.0.2",
"react-refresh": "0.8.3", "react-refresh": "0.8.3",
"stream-browserify": "3.0.0", "stream-browserify": "3.0.0",
"stream-http": "3.1.1", "stream-http": "3.1.1",
@ -3736,6 +3625,11 @@
"requires": { "requires": {
"regenerator-runtime": "^0.13.4" "regenerator-runtime": "^0.13.4"
} }
},
"react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
} }
} }
}, },
@ -3909,9 +3803,9 @@
} }
}, },
"node-releases": { "node-releases": {
"version": "1.1.72", "version": "1.1.73",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz",
"integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==" "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg=="
}, },
"normalize-package-data": { "normalize-package-data": {
"version": "2.5.0", "version": "2.5.0",
@ -4593,6 +4487,14 @@
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
"integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
}, },
"queue": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz",
"integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==",
"requires": {
"inherits": "~2.0.3"
}
},
"randombytes": { "randombytes": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@ -6005,14 +5907,21 @@
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
}, },
"unbox-primitive": { "unbox-primitive": {
"version": "1.0.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
"integrity": "sha512-P/51NX+JXyxK/aigg1/ZgyccdAxm5K1+n8+tvqSntjOivPt19gvm1VC49RWYetsiub8WViUchdxl/KWHHB0kzA==", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
"requires": { "requires": {
"function-bind": "^1.1.1", "function-bind": "^1.1.1",
"has-bigints": "^1.0.0", "has-bigints": "^1.0.1",
"has-symbols": "^1.0.0", "has-symbols": "^1.0.2",
"which-boxed-primitive": "^1.0.1" "which-boxed-primitive": "^1.0.2"
},
"dependencies": {
"has-symbols": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
}
} }
}, },
"unified": { "unified": {

3
web/package.json

@ -12,10 +12,11 @@
"@ant-design/icons": "^4.6.2", "@ant-design/icons": "^4.6.2",
"antd": "^4.16.6", "antd": "^4.16.6",
"chart.js": "^3.4.1", "chart.js": "^3.4.1",
"chartkick": "^4.0.5",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"date-fns": "^2.22.1", "date-fns": "^2.22.1",
"markdown-it": "^12.1.0", "markdown-it": "^12.1.0",
"next": "^10.2.3", "next": "^11.0.1",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"rc-util": "^5.13.2", "rc-util": "^5.13.2",
"react": "^17.0.2", "react": "^17.0.2",

43
web/pages/access-tokens.tsx

@ -1,5 +1,17 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Table, Tag, Space, Button, Modal, Checkbox, Input, Typography, Tooltip, Row, Col } from 'antd'; import {
Table,
Tag,
Space,
Button,
Modal,
Checkbox,
Input,
Typography,
Tooltip,
Row,
Col,
} from 'antd';
import { DeleteOutlined } from '@ant-design/icons'; import { DeleteOutlined } from '@ant-design/icons';
import format from 'date-fns/format'; import format from 'date-fns/format';
@ -26,7 +38,7 @@ const availableScopes = {
}, },
}; };
function convertScopeStringToTag(scopeString) { function convertScopeStringToTag(scopeString: string) {
if (!scopeString || !availableScopes[scopeString]) { if (!scopeString || !availableScopes[scopeString]) {
return null; return null;
} }
@ -50,9 +62,10 @@ function NewTokenModal(props: Props) {
const [selectedScopes, setSelectedScopes] = useState([]); const [selectedScopes, setSelectedScopes] = useState([]);
const [name, setName] = useState(''); const [name, setName] = useState('');
const scopes = Object.keys(availableScopes).map(key => { const scopes = Object.keys(availableScopes).map(key => ({
return { value: key, label: availableScopes[key].description }; value: key,
}); label: availableScopes[key].description,
}));
function onChange(checkedValues) { function onChange(checkedValues) {
setSelectedScopes(checkedValues); setSelectedScopes(checkedValues);
@ -73,9 +86,11 @@ function NewTokenModal(props: Props) {
function selectAll() { function selectAll() {
setSelectedScopes(Object.keys(availableScopes)); setSelectedScopes(Object.keys(availableScopes));
} }
const checkboxes = scopes.map(function (singleEvent) { const checkboxes = scopes.map(singleEvent => (
return (<Col span={8} key={singleEvent.value}><Checkbox value={singleEvent.value}>{singleEvent.label}</Checkbox></Col>) <Col span={8} key={singleEvent.value}>
}); <Checkbox value={singleEvent.value}>{singleEvent.label}</Checkbox>
</Col>
));
return ( return (
<Modal <Modal
@ -98,9 +113,7 @@ function NewTokenModal(props: Props) {
created. created.
</p> </p>
<Checkbox.Group style={{ width: '100%' }} value={selectedScopes} onChange={onChange}> <Checkbox.Group style={{ width: '100%' }} value={selectedScopes} onChange={onChange}>
<Row> <Row>{checkboxes}</Row>
{checkboxes}
</Row>
</Checkbox.Group> </Checkbox.Group>
<p> <p>
@ -182,13 +195,7 @@ export default function AccessTokens() {
title: 'Scopes', title: 'Scopes',
dataIndex: 'scopes', dataIndex: 'scopes',
key: 'scopes', key: 'scopes',
render: scopes => ( render: ({ map }: string[]) => <>{map(scope => convertScopeStringToTag(scope))}</>,
<>
{scopes.map(scope => {
return convertScopeStringToTag(scope);
})}
</>
),
}, },
{ {
title: 'Last Used', title: 'Last Used',

154
web/pages/actions.tsx

@ -1,24 +1,15 @@
// comment
import React, { useState, useEffect, useContext } from 'react';
import { Table, Space, Button, Modal, Checkbox, Input, Typography } from 'antd';
import { ServerStatusContext } from '../utils/server-status-context';
import { DeleteOutlined } from '@ant-design/icons'; import { DeleteOutlined } from '@ant-design/icons';
import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../utils/urls'; import { Button, Checkbox, Input, Modal, Space, Table, Typography } from 'antd';
import React, { useContext, useEffect, useState } from 'react';
import FormStatusIndicator from '../components/config/form-status-indicator'; import FormStatusIndicator from '../components/config/form-status-indicator';
import { import {
createInputStatus,
StatusState,
STATUS_ERROR,
STATUS_PROCESSING,
STATUS_SUCCESS,
} from '../utils/input-statuses';
import {
postConfigUpdateToAPI,
API_EXTERNAL_ACTIONS, API_EXTERNAL_ACTIONS,
postConfigUpdateToAPI,
RESET_TIMEOUT, RESET_TIMEOUT,
} from '../utils/config-constants'; } from '../utils/config-constants';
import { createInputStatus, STATUS_ERROR, STATUS_SUCCESS } from '../utils/input-statuses';
import { ServerStatusContext } from '../utils/server-status-context';
import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../utils/urls';
const { Title, Paragraph } = Typography; const { Title, Paragraph } = Typography;
let resetTimer = null; let resetTimer = null;
@ -156,65 +147,31 @@ export default function Actions() {
setActions(externalActions || []); setActions(externalActions || []);
}, [externalActions]); }, [externalActions]);
const columns = [ async function save(actionsData) {
{ await postConfigUpdateToAPI({
title: '', apiPath: API_EXTERNAL_ACTIONS,
key: 'delete', data: { value: actionsData },
render: (text, record) => ( onSuccess: () => {
<Space size="middle"> setFieldInConfigState({ fieldName: 'externalActions', value: actionsData, path: '' });
<Button onClick={() => handleDelete(record)} icon={<DeleteOutlined />} /> setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
</Space> resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
),
},
{
title: 'Name',
dataIndex: 'title',
key: 'title',
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
},
{
title: 'URL',
dataIndex: 'url',
key: 'url',
},
{
title: 'Icon',
dataIndex: 'icon',
key: 'icon',
render: (url: string) => {
return url ? <img style={{ width: '2vw' }} src={url} /> : null;
},
},
{
title: 'Color',
dataIndex: 'color',
key: 'color',
render: (color: string) => {
return color ? <div style={{ backgroundColor: color, height: '30px' }}>{color}</div> : null;
}, },
}, onError: (message: string) => {
{ console.log(message);
title: 'Opens', setSubmitStatus(createInputStatus(STATUS_ERROR, message));
dataIndex: 'openExternally', resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
key: 'openExternally',
render: (openExternally: boolean) => {
return openExternally ? 'In a new tab' : 'In a modal';
}, },
}, });
]; }
async function handleDelete(action) { async function handleDelete(action) {
let actionsData = [...actions]; const actionsData = [...actions];
const index = actions.findIndex(item => item.url === action.url); const index = actions.findIndex(item => item.url === action.url);
actionsData.splice(index, 1); actionsData.splice(index, 1);
setActions(actionsData);
save(actionsData);
try { try {
setActions(actionsData);
save(actionsData);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
@ -229,7 +186,7 @@ export default function Actions() {
openExternally: boolean, openExternally: boolean,
) { ) {
try { try {
let actionsData = [...actions]; const actionsData = [...actions];
const updatedActions = actionsData.concat({ const updatedActions = actionsData.concat({
url, url,
title, title,
@ -245,23 +202,6 @@ export default function Actions() {
} }
} }
async function save(actionsData) {
await postConfigUpdateToAPI({
apiPath: API_EXTERNAL_ACTIONS,
data: { value: actionsData },
onSuccess: () => {
setFieldInConfigState({ fieldName: 'externalActions', value: actionsData, path: '' });
setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Updated.'));
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
},
onError: (message: string) => {
console.log(message);
setSubmitStatus(createInputStatus(STATUS_ERROR, message));
resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
},
});
}
const showCreateModal = () => { const showCreateModal = () => {
setIsModalVisible(true); setIsModalVisible(true);
}; };
@ -282,6 +222,52 @@ export default function Actions() {
setIsModalVisible(false); setIsModalVisible(false);
}; };
const columns = [
{
title: '',
key: 'delete',
render: (text, record) => (
<Space size="middle">
<Button onClick={() => handleDelete(record)} icon={<DeleteOutlined />} />
</Space>
),
},
{
title: 'Name',
dataIndex: 'title',
key: 'title',
},
{
title: 'Description',
dataIndex: 'description',
key: 'description',
},
{
title: 'URL',
dataIndex: 'url',
key: 'url',
},
{
title: 'Icon',
dataIndex: 'icon',
key: 'icon',
render: (url: string) => (url ? <img style={{ width: '2vw' }} src={url} alt="" /> : null),
},
{
title: 'Color',
dataIndex: 'color',
key: 'color',
render: (color: string) =>
color ? <div style={{ backgroundColor: color, height: '30px' }}>{color}</div> : null,
},
{
title: 'Opens',
dataIndex: 'openExternally',
key: 'openExternally',
render: (openExternally: boolean) => (openExternally ? 'In a new tab' : 'In a modal'),
},
];
return ( return (
<div> <div>
<Title>External Actions</Title> <Title>External Actions</Title>

24
web/pages/config-chat.tsx

@ -1,14 +1,14 @@
import React, { useState, useContext, useEffect } from 'react';
import { Typography } from 'antd'; import { Typography } from 'antd';
import React, { useContext, useEffect, useState } from 'react';
import { TEXTFIELD_TYPE_TEXTAREA } from '../components/config/form-textfield';
import TextFieldWithSubmit from '../components/config/form-textfield-with-submit';
import ToggleSwitch from '../components/config/form-toggleswitch';
import { UpdateArgs } from '../types/config-section';
import { import {
FIELD_PROPS_DISABLE_CHAT, FIELD_PROPS_DISABLE_CHAT,
TEXTFIELD_PROPS_CHAT_USERNAME_BLOCKLIST, TEXTFIELD_PROPS_CHAT_USERNAME_BLOCKLIST,
} from '../utils/config-constants'; } from '../utils/config-constants';
import { ServerStatusContext } from '../utils/server-status-context'; import { ServerStatusContext } from '../utils/server-status-context';
import ToggleSwitch from '../components/config/form-toggleswitch';
import { UpdateArgs } from '../types/config-section';
import { TEXTFIELD_TYPE_TEXTAREA } from '../components/config/form-textfield';
import TextFieldWithSubmit from '../components/config/form-textfield-with-submit';
export default function ConfigChat() { export default function ConfigChat() {
const { Title } = Typography; const { Title } = Typography;
@ -19,6 +19,13 @@ export default function ConfigChat() {
const { chatDisabled } = serverConfig; const { chatDisabled } = serverConfig;
const { usernameBlocklist } = serverConfig; const { usernameBlocklist } = serverConfig;
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => {
setFormDataValues({
...formDataValues,
[fieldName]: value,
});
};
function handleChatDisableChange(disabled: boolean) { function handleChatDisableChange(disabled: boolean) {
handleFieldChange({ fieldName: 'chatDisabled', value: disabled }); handleFieldChange({ fieldName: 'chatDisabled', value: disabled });
} }
@ -38,13 +45,6 @@ export default function ConfigChat() {
return null; return null;
} }
const handleFieldChange = ({ fieldName, value }: UpdateArgs) => {
setFormDataValues({
...formDataValues,
[fieldName]: value,
});
};
return ( return (
<div className="config-server-details-form"> <div className="config-server-details-form">
<Title>Chat Settings</Title> <Title>Chat Settings</Title>

9
web/pages/config-video.tsx

@ -1,11 +1,10 @@
import { Col, Collapse, Row, Typography } from 'antd';
import React from 'react'; import React from 'react';
import { Typography, Row, Col, Collapse } from 'antd';
import VideoVariantsTable from '../components/config/video-variants-table';
import VideoLatency from '../components/config/video-latency';
import VideoCodecSelector from '../components/config/video-codec-selector'; import VideoCodecSelector from '../components/config/video-codec-selector';
const { Panel } = Collapse; import VideoLatency from '../components/config/video-latency';
import VideoVariantsTable from '../components/config/video-variants-table';
const { Panel } = Collapse;
const { Title } = Typography; const { Title } = Typography;
export default function ConfigVideoSettings() { export default function ConfigVideoSettings() {

22
web/pages/offline-notice.tsx

@ -1,28 +1,34 @@
import Link from 'next/link';
import { Card, Row, Col, Input, Collapse, Typography } from 'antd';
import { import {
MessageTwoTone,
QuestionCircleTwoTone,
BookTwoTone, BookTwoTone,
MessageTwoTone,
PlaySquareTwoTone, PlaySquareTwoTone,
ProfileTwoTone, ProfileTwoTone,
QuestionCircleTwoTone,
} from '@ant-design/icons'; } from '@ant-design/icons';
import OwncastLogo from '../components/logo'; import { Card, Col, Row, Typography } from 'antd';
import Link from 'next/link';
import { useContext } from 'react';
import LogTable from '../components/log-table'; import LogTable from '../components/log-table';
import OwncastLogo from '../components/logo';
import NewsFeed from '../components/news-feed'; import NewsFeed from '../components/news-feed';
import { useContext } from 'react'; import { ConfigDetails } from '../types/config-section';
import { ServerStatusContext } from '../utils/server-status-context'; import { ServerStatusContext } from '../utils/server-status-context';
const { Paragraph, Text } = Typography; const { Paragraph, Text } = Typography;
const { Title } = Typography; const { Title } = Typography;
const { Meta } = Card; const { Meta } = Card;
const { Panel } = Collapse;
function generateStreamURL(serverURL, rtmpServerPort) { function generateStreamURL(serverURL, rtmpServerPort) {
return `rtmp://${serverURL.replace(/(^\w+:|^)\/\//, '')}:${rtmpServerPort}/live/`; return `rtmp://${serverURL.replace(/(^\w+:|^)\/\//, '')}:${rtmpServerPort}/live/`;
} }
export default function Offline({ logs = [], config }) { type OfflineProps = {
logs: any[];
config: ConfigDetails;
};
export default function Offline({ logs = [], config }: OfflineProps) {
const serverStatusData = useContext(ServerStatusContext); const serverStatusData = useContext(ServerStatusContext);
const { serverConfig } = serverStatusData || {}; const { serverConfig } = serverStatusData || {};

94
web/pages/webhooks.tsx

@ -1,22 +1,21 @@
import React, { useState, useEffect } from 'react'; import { DeleteOutlined } from '@ant-design/icons';
import { import {
Table,
Tag,
Space,
Button, Button,
Modal,
Checkbox, Checkbox,
Col,
Input, Input,
Typography, Modal,
Tooltip,
Row, Row,
Col, Space,
Table,
Tag,
Tooltip,
Typography,
} from 'antd'; } from 'antd';
import { DeleteOutlined } from '@ant-design/icons'; import React, { useEffect, useState } from 'react';
import { CREATE_WEBHOOK, DELETE_WEBHOOK, fetchData, WEBHOOKS } from '../utils/apis';
import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../utils/urls'; import isValidUrl, { DEFAULT_TEXTFIELD_URL_PATTERN } from '../utils/urls';
import { fetchData, DELETE_WEBHOOK, CREATE_WEBHOOK, WEBHOOKS } from '../utils/apis';
const { Title, Paragraph } = Typography; const { Title, Paragraph } = Typography;
const availableEvents = { const availableEvents = {
@ -36,7 +35,7 @@ const availableEvents = {
STREAM_STOPPED: { name: 'Stream stopped', description: 'When a stream stops', color: 'cyan' }, STREAM_STOPPED: { name: 'Stream stopped', description: 'When a stream stops', color: 'cyan' },
}; };
function convertEventStringToTag(eventString) { function convertEventStringToTag(eventString: string) {
if (!eventString || !availableEvents[eventString]) { if (!eventString || !availableEvents[eventString]) {
return null; return null;
} }
@ -61,9 +60,10 @@ function NewWebhookModal(props: Props) {
const [selectedEvents, setSelectedEvents] = useState([]); const [selectedEvents, setSelectedEvents] = useState([]);
const [webhookUrl, setWebhookUrl] = useState(''); const [webhookUrl, setWebhookUrl] = useState('');
const events = Object.keys(availableEvents).map(key => { const events = Object.keys(availableEvents).map(key => ({
return { value: key, label: availableEvents[key].description }; value: key,
}); label: availableEvents[key].description,
}));
function onChange(checkedValues) { function onChange(checkedValues) {
setSelectedEvents(checkedValues); setSelectedEvents(checkedValues);
@ -85,13 +85,11 @@ function NewWebhookModal(props: Props) {
disabled: selectedEvents?.length === 0 || !isValidUrl(webhookUrl), disabled: selectedEvents?.length === 0 || !isValidUrl(webhookUrl),
}; };
const checkboxes = events.map(function (singleEvent) { const checkboxes = events.map(singleEvent => (
return ( <Col span={8} key={singleEvent.value}>
<Col span={8} key={singleEvent.value}> <Checkbox value={singleEvent.value}>{singleEvent.label}</Checkbox>
<Checkbox value={singleEvent.value}>{singleEvent.label}</Checkbox> </Col>
</Col> ));
);
});
return ( return (
<Modal <Modal
@ -128,35 +126,6 @@ export default function Webhooks() {
const [webhooks, setWebhooks] = useState([]); const [webhooks, setWebhooks] = useState([]);
const [isModalVisible, setIsModalVisible] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false);
const columns = [
{
title: '',
key: 'delete',
render: (text, record) => (
<Space size="middle">
<Button onClick={() => handleDelete(record.id)} icon={<DeleteOutlined />} />
</Space>
),
},
{
title: 'URL',
dataIndex: 'url',
key: 'url',
},
{
title: 'Events',
dataIndex: 'events',
key: 'events',
render: events => (
<>
{events.map(event => {
return convertEventStringToTag(event);
})}
</>
),
},
];
function handleError(error) { function handleError(error) {
console.error('error', error); console.error('error', error);
alert(error); alert(error);
@ -209,6 +178,29 @@ export default function Webhooks() {
setIsModalVisible(false); setIsModalVisible(false);
}; };
const columns = [
{
title: '',
key: 'delete',
render: (text, record) => (
<Space size="middle">
<Button onClick={() => handleDelete(record.id)} icon={<DeleteOutlined />} />
</Space>
),
},
{
title: 'URL',
dataIndex: 'url',
key: 'url',
},
{
title: 'Events',
dataIndex: 'events',
key: 'events',
render: ({ map }: string[]) => <>{map(event => convertEventStringToTag(event))}</>,
},
];
return ( return (
<div> <div>
<Title>Webhooks</Title> <Title>Webhooks</Title>

2
web/types/config-section.ts

@ -82,7 +82,7 @@ export interface S3Field {
} }
export interface ExternalAction { export interface ExternalAction {
title: string, title: string;
description: string; description: string;
url: string; url: string;
openExternally: boolean; openExternally: boolean;

Loading…
Cancel
Save