From cdbdbd236e5cc0918d1a4b03b76d3eb133046610 Mon Sep 17 00:00:00 2001 From: Arnaud Jeannin Date: Thu, 18 Mar 2021 09:27:23 +0100 Subject: [PATCH 001/151] feat: add with qovery --- docs/Get started.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Get started.md b/docs/Get started.md index 7feebeff..fa92b84c 100644 --- a/docs/Get started.md +++ b/docs/Get started.md @@ -14,6 +14,7 @@ The node server shows you the UI and receives the request from all of your sites - [With Netlify](#with-netlify) - [With Vercel](#with-vercel) - [With Heroku](#with-heroku) +- [With Qovery](#with-qovery) - [With Render](#with-render) ## With Docker Compose From 98d3a1549ae90d5ccf7115b2d840fc2b2e73b5e5 Mon Sep 17 00:00:00 2001 From: Arnaud Jeannin Date: Thu, 18 Mar 2021 09:44:19 +0100 Subject: [PATCH 002/151] add deploy with Qovery --- README.md | 1 + docs/Get started.md | 46 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/README.md b/README.md index e68c637d..868b846e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Get Ackee up and running… - […with Netlify](docs/Get%20started.md#with-netlify) - […with Vercel](docs/Get%20started.md#with-vercel) - […with Heroku](docs/Get%20started.md#with-heroku) +- […with Qovery](docs/Get%20started.md#with-qovery) - […with Render](docs/Get%20started.md#with-render) And configure Ackee and your server correctly… diff --git a/docs/Get started.md b/docs/Get started.md index fa92b84c..3e083165 100644 --- a/docs/Get started.md +++ b/docs/Get started.md @@ -238,6 +238,52 @@ git push heroku master After your application re-deploys you'll have the latest version of Ackee! +## With Qovery + +[Qovery](https://qovery.com) is a fully-managed cloud platform that runs on your AWS, GCP, Azure and Digital Ocean account where you can host static sites, backend APIs, databases, cron jobs, and all your other apps in one place. + +### 1. Create a Qovery account. + +Visit the [Qovery dashboard](https://console.qovery.com) to create an account if you don't already have one. + +### 2. Create a project + +Click on "Create a new project" and give a name to your project. + +Click on "Next". + +### 3. Add an application + +Click on "Create an application" then choose "I have an application" and select your GitHub or GitLab repository where your Ackee app is located. + +Click on "Next". + +### 4. Add a PostgreSQL database + +Select "PostgreSQL" among the services. + +Select the version. + +Give a name to your PostgreSQL databse. + +Click on "Next". + +### 5. Add a storage + +Select "Storage" among the services. + +Give a name to your storage. + +Select the storage type between Slow HDD, HDD, SSD, and Fast SSD. (SSD is recommended). + +Select the size. + +Give a mount point. + +### 6. Deploy + +Click on the Deploy button. Your app should be deployed: you can see the status in real time by clicking on deployment logs. + ## With Render You can use [Render's](https://render.com/) one-click deploy button to get up and running with Ackee in minutes. From 91dbf691334738e5a444c8f56b3894930cb14f81 Mon Sep 17 00:00:00 2001 From: Arnaud Jeannin Date: Wed, 21 Apr 2021 16:04:00 +0200 Subject: [PATCH 003/151] refacto: reduce doc tutorial --- docs/Get started.md | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/docs/Get started.md b/docs/Get started.md index 3e083165..a360f9c6 100644 --- a/docs/Get started.md +++ b/docs/Get started.md @@ -250,39 +250,15 @@ Visit the [Qovery dashboard](https://console.qovery.com) to create an account if Click on "Create a new project" and give a name to your project. -Click on "Next". - ### 3. Add an application Click on "Create an application" then choose "I have an application" and select your GitHub or GitLab repository where your Ackee app is located. -Click on "Next". - -### 4. Add a PostgreSQL database - -Select "PostgreSQL" among the services. - -Select the version. - -Give a name to your PostgreSQL databse. - -Click on "Next". - -### 5. Add a storage - -Select "Storage" among the services. - -Give a name to your storage. - -Select the storage type between Slow HDD, HDD, SSD, and Fast SSD. (SSD is recommended). - -Select the size. - -Give a mount point. +Select "MongoDB" service then choose a version. Give the database a name and continue with "Next". -### 6. Deploy +Click on "Deploy". -Click on the Deploy button. Your app should be deployed: you can see the status in real time by clicking on deployment logs. +Chat with Qovery developers on [Discord](https://discord.qovery.com) if you need help. ## With Render From 9e660f02eb0444a62ca98f26591bdad0285afc23 Mon Sep 17 00:00:00 2001 From: Qovery Date: Wed, 21 Apr 2021 14:58:56 +0000 Subject: [PATCH 004/151] =?UTF-8?q?chore:=20Add=20.qovery.yml=20file=20to?= =?UTF-8?q?=20deploy=20app=20with=20Qovery=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .qovery.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .qovery.yml diff --git a/.qovery.yml b/.qovery.yml new file mode 100644 index 00000000..98db608e --- /dev/null +++ b/.qovery.yml @@ -0,0 +1,15 @@ +--- +application: + name: "ackee" + project: "my-app" + organization: "QoveryCommunity" +databases: +- type: "POSTGRESQL" + name: "name" + version: "12" +routers: +- name: "main-ackee" + routes: + - application_name: "ackee" + paths: + - "/*" From a23130776f8ea1e9a2588c9556de607fa87c6927 Mon Sep 17 00:00:00 2001 From: Arnaud Jeannin Date: Wed, 21 Apr 2021 23:22:19 +0200 Subject: [PATCH 005/151] fix: rm qovery.yml --- .qovery.yml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .qovery.yml diff --git a/.qovery.yml b/.qovery.yml deleted file mode 100644 index 98db608e..00000000 --- a/.qovery.yml +++ /dev/null @@ -1,15 +0,0 @@ ---- -application: - name: "ackee" - project: "my-app" - organization: "QoveryCommunity" -databases: -- type: "POSTGRESQL" - name: "name" - version: "12" -routers: -- name: "main-ackee" - routes: - - application_name: "ackee" - paths: - - "/*" From 36a7c0a44d8ceaf67fd073c0f95116047a56f506 Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sat, 24 Apr 2021 17:47:20 +0200 Subject: [PATCH 006/151] Add apollo client --- package.json | 1 + src/ui/scripts/api/useDomains.js | 28 ++++++++++ src/ui/scripts/api/useEvents.js | 29 ++++++++++ src/ui/scripts/api/usePermanentTokens.js | 28 ++++++++++ src/ui/scripts/components/Dashboard.js | 18 +++--- .../components/routes/RouteSettings.js | 27 +++++---- src/ui/scripts/index.js | 10 +++- src/ui/scripts/utils/createClient.js | 31 +++++++++++ yarn.lock | 55 +++++++++++++++++++ 9 files changed, 200 insertions(+), 27 deletions(-) create mode 100644 src/ui/scripts/api/useDomains.js create mode 100644 src/ui/scripts/api/useEvents.js create mode 100644 src/ui/scripts/api/usePermanentTokens.js create mode 100644 src/ui/scripts/utils/createClient.js diff --git a/package.json b/package.json index ee66a08c..ec35c2c6 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "uuid": "^8.3.2" }, "devDependencies": { + "@apollo/client": "^3.3.15", "@electerious/eslint-config": "^1.4.0", "ava": "3.15.0", "classnames": "^2.2.6", diff --git a/src/ui/scripts/api/useDomains.js b/src/ui/scripts/api/useDomains.js new file mode 100644 index 00000000..f6321fc6 --- /dev/null +++ b/src/ui/scripts/api/useDomains.js @@ -0,0 +1,28 @@ +import { useMemo } from 'react' +import { useQuery, gql } from '@apollo/client' + +const query = gql` + query domains { + domains { + id + title + } + } +` + +export default () => { + + const { loading: fetching, error, data } = useQuery(query, { + fetchPolicy: 'cache-and-network' + }) + + const value = useMemo(() => data == null ? [] : data.domains, [ data ]) + + return useMemo(() => ({ + fetching, + stale: fetching === true && data != null, + error, + value + }), [ fetching, error, value ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/useEvents.js b/src/ui/scripts/api/useEvents.js new file mode 100644 index 00000000..a62b2fb1 --- /dev/null +++ b/src/ui/scripts/api/useEvents.js @@ -0,0 +1,29 @@ +import { useMemo } from 'react' +import { useQuery, gql } from '@apollo/client' + +const query = gql` + query events { + events { + id + title + type + } + } +` + +export default () => { + + const { loading: fetching, error, data } = useQuery(query, { + fetchPolicy: 'cache-and-network' + }) + + const value = useMemo(() => data == null ? [] : data.events, [ data ]) + + return useMemo(() => ({ + fetching, + stale: fetching === true && data != null, + error, + value + }), [ fetching, error, value ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/usePermanentTokens.js b/src/ui/scripts/api/usePermanentTokens.js new file mode 100644 index 00000000..7669282c --- /dev/null +++ b/src/ui/scripts/api/usePermanentTokens.js @@ -0,0 +1,28 @@ +import { useMemo } from 'react' +import { useQuery, gql } from '@apollo/client' + +const query = gql` + query permanentTokens { + permanentTokens { + id + title + } + } +` + +export default () => { + + const { loading: fetching, error, data } = useQuery(query, { + fetchPolicy: 'cache-and-network' + }) + + const value = useMemo(() => data == null ? [] : data.permanentTokens, [ data ]) + + return useMemo(() => ({ + fetching, + stale: fetching === true && data != null, + error, + value + }), [ fetching, error, value ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/components/Dashboard.js b/src/ui/scripts/components/Dashboard.js index 5259de26..b28ff5ac 100644 --- a/src/ui/scripts/components/Dashboard.js +++ b/src/ui/scripts/components/Dashboard.js @@ -1,6 +1,7 @@ import { createElement as h, useEffect } from 'react' import { useHotkeys } from 'react-hotkeys-hook' +import useDomains from '../api/useDomains' import whenBelow from '../utils/whenBelow' import * as routes from '../constants/routes' import useRoute from '../hooks/useRoute' @@ -40,7 +41,7 @@ const routeComponents = { const gotoDomainWhenDefined = (domains, setRoute, index) => { - const domain = domains.value[index] + const domain = domains[index] if (domain != null) setRoute(`/domains/${ domain.id }`) } @@ -49,19 +50,14 @@ const Dashboard = (props) => { const currentRoute = useRoute(props.route) - useEffect(() => { - - props.fetchDomains(props) - props.fetchEvents(props) - - }, []) - useEffect(() => { document.scrollingElement.scrollTop = 0 }, [ props.route ]) + const domains = useDomains() + useHotkeys('o', () => props.setRoute('/')) useHotkeys('v', () => props.setRoute('/insights/views')) useHotkeys('p', () => props.setRoute('/insights/pages')) @@ -69,14 +65,14 @@ const Dashboard = (props) => { useHotkeys('d', () => props.setRoute('/insights/durations')) useHotkeys('e', () => props.setRoute('/insights/events')) useHotkeys('s', () => props.setRoute('/settings')) - useHotkeys('0,1,2,3,4,5,6,7,8,9', (e, { key }) => gotoDomainWhenDefined(props.domains, props.setRoute, key), [ props.domains ]) + useHotkeys('0,1,2,3,4,5,6,7,8,9', (e, { key }) => gotoDomainWhenDefined(domains.value, props.setRoute, key), [ domains.value ]) - const hasDomains = props.domains.value.length > 0 + const hasDomains = domains.value.length > 0 const domainsLabel = (activeItem) => activeItem == null ? 'Domains' : activeItem.label const insightsLabel = (activeItem) => activeItem == null ? 'Insights' : activeItem.label - const domainsItems = props.domains.value.map((domain, index) => + const domainsItems = domains.value.map((domain, index) => createDropdownButton(domain.title, `/domains/${ domain.id }`, props, whenBelow(index, 10)) ) diff --git a/src/ui/scripts/components/routes/RouteSettings.js b/src/ui/scripts/components/routes/RouteSettings.js index 71af42da..5da398c8 100644 --- a/src/ui/scripts/components/routes/RouteSettings.js +++ b/src/ui/scripts/components/routes/RouteSettings.js @@ -1,6 +1,9 @@ -import { createElement as h, Fragment, useEffect } from 'react' +import { createElement as h, Fragment } from 'react' import { version, homepage } from '../../../../../package.json' +import useDomains from '../../api/useDomains' +import useEvents from '../../api/useEvents' +import usePermanentTokens from '../../api/usePermanentTokens' import { MODALS_DOMAIN_ADD, MODALS_DOMAIN_EDIT, @@ -23,13 +26,9 @@ const FetchingMessage = (props) => { const RouteSettings = (props) => { - useEffect(() => { - - props.fetchDomains(props) - props.fetchEvents(props) - props.fetchPermanentTokens(props) - - }, []) + const domains = useDomains() + const events = useEvents() + const permanentTokens = usePermanentTokens() const showModal = (type, data = {}) => { @@ -65,9 +64,9 @@ const RouteSettings = (props) => { const eventsFetching = h(FetchingMessage, { label: 'events' }) const permanentTokensFetching = h(FetchingMessage, { label: 'permanent tokens' }) - const domainsItems = createItems(props.domains.value, showDomainEditModal, showDomainAddModal, 'New domain') - const eventsItems = createItems(props.events.value, showEventEditModal, showEventAddModal, 'New event') - const permanentTokensItems = createItems(props.permanentTokens.value, showPermanentTokenEditModal, showPermanentTokenAddModal, 'New permanent token') + const domainsItems = createItems(domains.value, showDomainEditModal, showDomainAddModal, 'New domain') + const eventsItems = createItems(events.value, showEventEditModal, showEventAddModal, 'New event') + const permanentTokensItems = createItems(permanentTokens.value, showPermanentTokenEditModal, showPermanentTokenAddModal, 'New permanent token') return ( h(Fragment, {}, @@ -83,19 +82,19 @@ const RouteSettings = (props) => { h(CardSetting, { headline: 'Domains' }, - ...(props.domains.fetching === true ? [ domainsFetching ] : domainsItems) + ...(domains.fetching === true && domains.stale !== true ? [ domainsFetching ] : domainsItems) ), h(CardSetting, { headline: 'Events' }, - ...(props.events.fetching === true ? [ eventsFetching ] : eventsItems) + ...(events.fetching === true && events.stale !== true ? [ eventsFetching ] : eventsItems) ), h(CardSetting, { headline: 'Permanent Tokens' }, - ...(props.permanentTokens.fetching === true ? [ permanentTokensFetching ] : permanentTokensItems) + ...(permanentTokens.fetching === true && permanentTokens.stale !== true ? [ permanentTokensFetching ] : permanentTokensItems) ), h(CardSetting, { diff --git a/src/ui/scripts/index.js b/src/ui/scripts/index.js index 342da1af..a90c5051 100644 --- a/src/ui/scripts/index.js +++ b/src/ui/scripts/index.js @@ -2,8 +2,10 @@ import { createElement as h } from 'react' import { render } from 'react-dom' import { bindActionCreators } from 'redux' import { Provider, connect } from 'react-redux' +import { ApolloProvider } from '@apollo/client/react' import enhanceState from './enhancers/enhanceState' +import createClient from './utils/createClient' import createStore from './utils/createStore' import * as storage from './utils/storage' import reducers from './reducers/index' @@ -14,6 +16,8 @@ import { initialState as initialFilterState } from './reducers/filter' import Main from './components/Main' +const client = createClient() + const persistedState = storage.load() const store = createStore(reducers, persistedState) @@ -44,8 +48,10 @@ store.subscribe(() => { }) -const App = h(Provider, { store }, - h(ConnectedMain) +const App = h(ApolloProvider, { client }, + h(Provider, { store }, + h(ConnectedMain) + ) ) render(App, container) \ No newline at end of file diff --git a/src/ui/scripts/utils/createClient.js b/src/ui/scripts/utils/createClient.js new file mode 100644 index 00000000..d119d1b8 --- /dev/null +++ b/src/ui/scripts/utils/createClient.js @@ -0,0 +1,31 @@ +import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client' +import { setContext } from '@apollo/client/link/context' + +export default () => { + + const httpLink = createHttpLink({ + uri: '/api' + }) + + const authLink = setContext((_, { headers }) => { + + const state = localStorage.getItem('ackee_state_3.0.6') + if (state == null) return { headers } + + const token = JSON.parse(state).token.value + + return { + headers: { + ...headers, + Authorization: `Bearer ${ token }` + } + } + + }) + + return new ApolloClient({ + link: authLink.concat(httpLink), + cache: new InMemoryCache() + }) + +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 2bc45528..33bc0ea5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21,6 +21,25 @@ tslib "^1.10.0" zen-observable "^0.8.14" +"@apollo/client@^3.3.15": + version "3.3.15" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.3.15.tgz#bdd230894aac4beb8ade2b472a1d3c9ea6152812" + integrity sha512-/WQmNvLEZMA0mA3u+FkEPTXKzxZD/KhyO7WlbKcy3zKGrXKza83tAbNMzsitQE7DTcSc3DLEcIu1Z5Rc7PFq0Q== + dependencies: + "@graphql-typed-document-node/core" "^3.0.0" + "@types/zen-observable" "^0.8.0" + "@wry/context" "^0.6.0" + "@wry/equality" "^0.4.0" + fast-json-stable-stringify "^2.0.0" + graphql-tag "^2.12.0" + hoist-non-react-statics "^3.3.2" + optimism "^0.15.0" + prop-types "^15.7.2" + symbol-observable "^2.0.0" + ts-invariant "^0.7.0" + tslib "^1.10.0" + zen-observable "^0.8.14" + "@apollo/protobufjs@^1.0.3": version "1.0.5" resolved "https://registry.yarnpkg.com/@apollo/protobufjs/-/protobufjs-1.0.5.tgz#a78b726147efc0795e74c8cb8a11aafc6e02f773" @@ -1642,6 +1661,13 @@ dependencies: tslib "^1.14.1" +"@wry/context@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.0.tgz#f903eceb89d238ef7e8168ed30f4511f92d83e06" + integrity sha512-sAgendOXR8dM7stJw3FusRxFHF/ZinU0lffsA2YTyyIOfic86JX02qlPqPVqJNZJPAxFt+2EE8bvq6ZlS0Kf+Q== + dependencies: + tslib "^2.1.0" + "@wry/equality@^0.1.2": version "0.1.11" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -1656,6 +1682,13 @@ dependencies: tslib "^1.14.1" +"@wry/equality@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.4.0.tgz#474491869a8d0590f4a33fd2a4850a77a0f63408" + integrity sha512-DxN/uawWfhRbgYE55zVCPOoe+jvsQ4m7PT1Wlxjyb/LCCLuU1UsucV2BbCxFAX8bjcSueFBbB5Qfj1Zfe8e7Fw== + dependencies: + tslib "^2.1.0" + "@wry/trie@^0.2.1": version "0.2.2" resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.2.2.tgz#99f20f0fcbbcda17006069b155c826cbabfc402f" @@ -1663,6 +1696,13 @@ dependencies: tslib "^1.14.1" +"@wry/trie@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.0.tgz#3245e74988c4e3033299e479a1bf004430752463" + integrity sha512-Yw1akIogPhAT6XPYsRHlZZIS0tIGmAl9EYXHi2scf7LPKKqdqmow/Hu4kEqP2cJR3EjaU/9L0ZlAjFf3hFxmug== + dependencies: + tslib "^2.1.0" + "@xobotyi/scrollbar-width@^1.9.5": version "1.9.5" resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" @@ -5659,6 +5699,14 @@ optimism@^0.14.0: "@wry/context" "^0.5.2" "@wry/trie" "^0.2.1" +optimism@^0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.15.0.tgz#c65e694bec7ce439f41e9cb8fc261a72d798125b" + integrity sha512-KLKl3Kb7hH++s9ewRcBhmfpXgXF0xQ+JZ3xQFuPjnoT6ib2TDmYyVkKENmGxivsN2G3VRxpXuauCkB4GYOhtPw== + dependencies: + "@wry/context" "^0.6.0" + "@wry/trie" "^0.3.0" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" @@ -7645,6 +7693,13 @@ ts-invariant@^0.6.0: "@ungap/global-this" "^0.4.2" tslib "^1.9.3" +ts-invariant@^0.7.0: + version "0.7.3" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.7.3.tgz#13aae22a4a165393aaf5cecdee45ef4128d358b8" + integrity sha512-UWDDeovyUTIMWj+45g5nhnl+8oo+GhxL5leTaHn5c8FkQWfh8v66gccLd2/YzVmV5hoQUjCEjhrXnQqVDJdvKA== + dependencies: + tslib "^2.1.0" + tsconfig-paths@^3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" From dc52f2a65b6f68a81078a3863333ddd29005d192 Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sat, 24 Apr 2021 20:18:43 +0200 Subject: [PATCH 007/151] Restructure create client and links --- package.json | 1 + src/ui/scripts/api/createClient.js | 10 ++++++++++ src/ui/scripts/api/{ => hooks}/useDomains.js | 0 src/ui/scripts/api/{ => hooks}/useEvents.js | 0 .../scripts/api/{ => hooks}/usePermanentTokens.js | 0 .../links/createAuthLink.js} | 12 +----------- src/ui/scripts/api/links/createHttpLink.js | 14 ++++++++++++++ .../scripts/api/links/createNetworkStatusLink.js | 12 ++++++++++++ src/ui/scripts/components/Dashboard.js | 2 +- src/ui/scripts/components/routes/RouteSettings.js | 6 +++--- src/ui/scripts/index.js | 12 ++++++++++-- yarn.lock | 5 +++++ 12 files changed, 57 insertions(+), 17 deletions(-) create mode 100644 src/ui/scripts/api/createClient.js rename src/ui/scripts/api/{ => hooks}/useDomains.js (100%) rename src/ui/scripts/api/{ => hooks}/useEvents.js (100%) rename src/ui/scripts/api/{ => hooks}/usePermanentTokens.js (100%) rename src/ui/scripts/{utils/createClient.js => api/links/createAuthLink.js} (53%) create mode 100644 src/ui/scripts/api/links/createHttpLink.js create mode 100644 src/ui/scripts/api/links/createNetworkStatusLink.js diff --git a/package.json b/package.json index ec35c2c6..1a795258 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "nyc": "^15.1.0", "prop-types": "^15.7.2", "react": "^17.0.1", + "react-apollo-network-status": "^5.0.1", "react-dom": "^17.0.1", "react-error-boundary": "^3.1.1", "react-fast-compare": "^3.2.0", diff --git a/src/ui/scripts/api/createClient.js b/src/ui/scripts/api/createClient.js new file mode 100644 index 00000000..09f33564 --- /dev/null +++ b/src/ui/scripts/api/createClient.js @@ -0,0 +1,10 @@ +import { ApolloClient, InMemoryCache, from } from '@apollo/client' + +export default (links) => { + + return new ApolloClient({ + link: from(links), + cache: new InMemoryCache({}) + }) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/useDomains.js b/src/ui/scripts/api/hooks/useDomains.js similarity index 100% rename from src/ui/scripts/api/useDomains.js rename to src/ui/scripts/api/hooks/useDomains.js diff --git a/src/ui/scripts/api/useEvents.js b/src/ui/scripts/api/hooks/useEvents.js similarity index 100% rename from src/ui/scripts/api/useEvents.js rename to src/ui/scripts/api/hooks/useEvents.js diff --git a/src/ui/scripts/api/usePermanentTokens.js b/src/ui/scripts/api/hooks/usePermanentTokens.js similarity index 100% rename from src/ui/scripts/api/usePermanentTokens.js rename to src/ui/scripts/api/hooks/usePermanentTokens.js diff --git a/src/ui/scripts/utils/createClient.js b/src/ui/scripts/api/links/createAuthLink.js similarity index 53% rename from src/ui/scripts/utils/createClient.js rename to src/ui/scripts/api/links/createAuthLink.js index d119d1b8..adb8b00f 100644 --- a/src/ui/scripts/utils/createClient.js +++ b/src/ui/scripts/api/links/createAuthLink.js @@ -1,13 +1,8 @@ -import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client' import { setContext } from '@apollo/client/link/context' export default () => { - const httpLink = createHttpLink({ - uri: '/api' - }) - - const authLink = setContext((_, { headers }) => { + return setContext((request, { headers }) => { const state = localStorage.getItem('ackee_state_3.0.6') if (state == null) return { headers } @@ -23,9 +18,4 @@ export default () => { }) - return new ApolloClient({ - link: authLink.concat(httpLink), - cache: new InMemoryCache() - }) - } \ No newline at end of file diff --git a/src/ui/scripts/api/links/createHttpLink.js b/src/ui/scripts/api/links/createHttpLink.js new file mode 100644 index 00000000..3e115816 --- /dev/null +++ b/src/ui/scripts/api/links/createHttpLink.js @@ -0,0 +1,14 @@ +import { BatchHttpLink } from '@apollo/client/link/batch-http' + +import userTimeZone from '../../../../utils/timeZone' + +export default () => { + + return new BatchHttpLink({ + uri: '/api', + headers: { + 'Time-Zone': userTimeZone + } + }) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/links/createNetworkStatusLink.js b/src/ui/scripts/api/links/createNetworkStatusLink.js new file mode 100644 index 00000000..7f7feed6 --- /dev/null +++ b/src/ui/scripts/api/links/createNetworkStatusLink.js @@ -0,0 +1,12 @@ +import { createNetworkStatusNotifier } from 'react-apollo-network-status' + +export default () => { + + const networkStatusNotifier = createNetworkStatusNotifier() + + return { + networkStatusLink: networkStatusNotifier.link, + useNetworkStatusLink: networkStatusNotifier.useApolloNetworkStatus + } + +} \ No newline at end of file diff --git a/src/ui/scripts/components/Dashboard.js b/src/ui/scripts/components/Dashboard.js index b28ff5ac..961ad670 100644 --- a/src/ui/scripts/components/Dashboard.js +++ b/src/ui/scripts/components/Dashboard.js @@ -1,7 +1,7 @@ import { createElement as h, useEffect } from 'react' import { useHotkeys } from 'react-hotkeys-hook' -import useDomains from '../api/useDomains' +import useDomains from '../api/hooks/useDomains' import whenBelow from '../utils/whenBelow' import * as routes from '../constants/routes' import useRoute from '../hooks/useRoute' diff --git a/src/ui/scripts/components/routes/RouteSettings.js b/src/ui/scripts/components/routes/RouteSettings.js index 5da398c8..d00ff1e6 100644 --- a/src/ui/scripts/components/routes/RouteSettings.js +++ b/src/ui/scripts/components/routes/RouteSettings.js @@ -1,9 +1,9 @@ import { createElement as h, Fragment } from 'react' import { version, homepage } from '../../../../../package.json' -import useDomains from '../../api/useDomains' -import useEvents from '../../api/useEvents' -import usePermanentTokens from '../../api/usePermanentTokens' +import useDomains from '../../api/hooks/useDomains' +import useEvents from '../../api/hooks/useEvents' +import usePermanentTokens from '../../api/hooks/usePermanentTokens' import { MODALS_DOMAIN_ADD, MODALS_DOMAIN_EDIT, diff --git a/src/ui/scripts/index.js b/src/ui/scripts/index.js index a90c5051..179d9c5f 100644 --- a/src/ui/scripts/index.js +++ b/src/ui/scripts/index.js @@ -4,8 +4,11 @@ import { bindActionCreators } from 'redux' import { Provider, connect } from 'react-redux' import { ApolloProvider } from '@apollo/client/react' +import createNetworkStatusLink from './api/links/createNetworkStatusLink' +import createAuthLink from './api/links/createAuthLink' +import createHttpLink from './api/links/createHttpLink' +import createClient from './api/createClient' import enhanceState from './enhancers/enhanceState' -import createClient from './utils/createClient' import createStore from './utils/createStore' import * as storage from './utils/storage' import reducers from './reducers/index' @@ -16,7 +19,12 @@ import { initialState as initialFilterState } from './reducers/filter' import Main from './components/Main' -const client = createClient() +const { networkStatusLink } = createNetworkStatusLink() +const client = createClient([ + networkStatusLink, + createAuthLink(), + createHttpLink() +]) const persistedState = storage.load() const store = createStore(reducers, persistedState) diff --git a/yarn.lock b/yarn.lock index 33bc0ea5..dfc919dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6459,6 +6459,11 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-apollo-network-status@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/react-apollo-network-status/-/react-apollo-network-status-5.0.1.tgz#25a7ccf956e9c0dd2b7b7bab9efe2681ba0b841c" + integrity sha512-kA4WqEHUegc3IjvC9ZmA/hABRFpN9sjJ2wDehbRoyMyV2mVMoDcLq9BH/OQ6hpoeYZhTpl9F8np6fcWYERtn4g== + react-dom@^17.0.1: version "17.0.1" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.1.tgz#1de2560474ec9f0e334285662ede52dbc5426fc6" From ecab5307a8a10e14a0625cb1c7683f4c2df3b71f Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sat, 24 Apr 2021 20:55:43 +0200 Subject: [PATCH 008/151] Syntax adjustment --- src/ui/scripts/api/links/createAuthLink.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ui/scripts/api/links/createAuthLink.js b/src/ui/scripts/api/links/createAuthLink.js index adb8b00f..5f78c22a 100644 --- a/src/ui/scripts/api/links/createAuthLink.js +++ b/src/ui/scripts/api/links/createAuthLink.js @@ -3,7 +3,6 @@ import { setContext } from '@apollo/client/link/context' export default () => { return setContext((request, { headers }) => { - const state = localStorage.getItem('ackee_state_3.0.6') if (state == null) return { headers } @@ -15,7 +14,6 @@ export default () => { Authorization: `Bearer ${ token }` } } - }) } \ No newline at end of file From c834a9fc466f270a87ac88024c1ffd6b11d19f87 Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sat, 24 Apr 2021 21:38:15 +0200 Subject: [PATCH 009/151] Mutations for domains, events, permanentTokens --- src/ui/scripts/actions/domains.js | 164 ----------------- src/ui/scripts/actions/events.js | 167 ------------------ src/ui/scripts/actions/index.js | 3 - src/ui/scripts/actions/permanentTokens.js | 164 ----------------- src/ui/scripts/api/fragments/domainFields.js | 8 + src/ui/scripts/api/fragments/eventFields.js | 9 + .../api/fragments/permanentTokenFields.js | 8 + src/ui/scripts/api/hooks/useCreateDomain.js | 32 ++++ src/ui/scripts/api/hooks/useCreateEvent.js | 32 ++++ .../api/hooks/useCreatePermanentToken.js | 32 ++++ src/ui/scripts/api/hooks/useDeleteDomain.js | 29 +++ src/ui/scripts/api/hooks/useDeleteEvent.js | 29 +++ .../api/hooks/useDeletePermanentToken.js | 29 +++ src/ui/scripts/api/hooks/useDomains.js | 7 +- src/ui/scripts/api/hooks/useEvents.js | 8 +- .../scripts/api/hooks/usePermanentTokens.js | 7 +- src/ui/scripts/api/hooks/useUpdateDomain.js | 32 ++++ src/ui/scripts/api/hooks/useUpdateEvent.js | 32 ++++ .../api/hooks/useUpdatePermanentToken.js | 32 ++++ src/ui/scripts/components/Modals.js | 27 +-- .../components/modals/ModalDomainAdd.js | 26 +-- .../components/modals/ModalDomainEdit.js | 37 ++-- .../components/modals/ModalEventAdd.js | 28 +-- .../components/modals/ModalEventEdit.js | 39 ++-- .../modals/ModalPermanentTokenAdd.js | 26 +-- .../modals/ModalPermanentTokenEdit.js | 37 ++-- src/ui/scripts/enhancers/enhanceState.js | 10 +- src/ui/scripts/reducers/domains.js | 35 ---- src/ui/scripts/reducers/events.js | 35 ---- src/ui/scripts/reducers/index.js | 6 - src/ui/scripts/reducers/permanentTokens.js | 35 ---- 31 files changed, 449 insertions(+), 716 deletions(-) delete mode 100644 src/ui/scripts/actions/domains.js delete mode 100644 src/ui/scripts/actions/events.js delete mode 100644 src/ui/scripts/actions/permanentTokens.js create mode 100644 src/ui/scripts/api/fragments/domainFields.js create mode 100644 src/ui/scripts/api/fragments/eventFields.js create mode 100644 src/ui/scripts/api/fragments/permanentTokenFields.js create mode 100644 src/ui/scripts/api/hooks/useCreateDomain.js create mode 100644 src/ui/scripts/api/hooks/useCreateEvent.js create mode 100644 src/ui/scripts/api/hooks/useCreatePermanentToken.js create mode 100644 src/ui/scripts/api/hooks/useDeleteDomain.js create mode 100644 src/ui/scripts/api/hooks/useDeleteEvent.js create mode 100644 src/ui/scripts/api/hooks/useDeletePermanentToken.js create mode 100644 src/ui/scripts/api/hooks/useUpdateDomain.js create mode 100644 src/ui/scripts/api/hooks/useUpdateEvent.js create mode 100644 src/ui/scripts/api/hooks/useUpdatePermanentToken.js delete mode 100644 src/ui/scripts/reducers/domains.js delete mode 100644 src/ui/scripts/reducers/events.js delete mode 100644 src/ui/scripts/reducers/permanentTokens.js diff --git a/src/ui/scripts/actions/domains.js b/src/ui/scripts/actions/domains.js deleted file mode 100644 index 4f6bd11e..00000000 --- a/src/ui/scripts/actions/domains.js +++ /dev/null @@ -1,164 +0,0 @@ -import api from '../utils/api' -import signalHandler from '../utils/signalHandler' - -export const SET_DOMAINS_START = Symbol() -export const SET_DOMAINS_END = Symbol() -export const SET_DOMAINS_FETCHING = Symbol() -export const SET_DOMAINS_ERROR = Symbol() - -export const setDomainsStart = () => ({ - type: SET_DOMAINS_START -}) - -export const setDomainsEnd = (value) => ({ - type: SET_DOMAINS_END, - value -}) - -export const setDomainsFetching = (payload) => ({ - type: SET_DOMAINS_FETCHING, - payload -}) - -export const setDomainsError = (payload) => ({ - type: SET_DOMAINS_ERROR, - payload -}) - -export const fetchDomains = signalHandler((signal) => (props) => async (dispatch) => { - - dispatch(setDomainsStart()) - - try { - - const data = await api({ - query: ` - query fetchDomains { - domains { - id - title - } - } - `, - props, - signal: signal() - }) - - dispatch(setDomainsEnd(data.domains)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setDomainsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setDomainsError(err)) - - } - -}) - -export const addDomain = (props, state) => async (dispatch) => { - - dispatch(setDomainsStart()) - - try { - - await api({ - query: ` - mutation createDomain($input: CreateDomainInput!) { - createDomain(input: $input) { - success - } - } - `, - variables: { - input: { - title: state.title - } - }, - props - }) - - await dispatch(fetchDomains(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setDomainsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setDomainsError(err)) - - } - -} - -export const updateDomain = signalHandler((signal) => (props, domainId, state) => async (dispatch) => { - - dispatch(setDomainsStart()) - - try { - - await api({ - query: ` - mutation updateDomain($id: ID!, $input: UpdateDomainInput!) { - updateDomain(id: $id, input: $input) { - success - } - } - `, - variables: { - id: domainId, - input: { - title: state.title - } - }, - props, - signal: signal(domainId) - }) - - await dispatch(fetchDomains(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setDomainsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setDomainsError(err)) - - } - -}) - -export const deleteDomain = signalHandler((signal) => (props, domainId) => async (dispatch) => { - - dispatch(setDomainsStart()) - - try { - - await api({ - query: ` - mutation deleteDomain($id: ID!) { - deleteDomain(id: $id) { - success - } - } - `, - variables: { - id: domainId - }, - props, - signal: signal(domainId) - }) - - await dispatch(fetchDomains(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setDomainsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setDomainsError(err)) - - } - -}) \ No newline at end of file diff --git a/src/ui/scripts/actions/events.js b/src/ui/scripts/actions/events.js deleted file mode 100644 index ef5d71f9..00000000 --- a/src/ui/scripts/actions/events.js +++ /dev/null @@ -1,167 +0,0 @@ -import api from '../utils/api' -import signalHandler from '../utils/signalHandler' - -export const SET_EVENTS_START = Symbol() -export const SET_EVENTS_END = Symbol() -export const SET_EVENTS_FETCHING = Symbol() -export const SET_EVENTS_ERROR = Symbol() - -export const setEventsStart = () => ({ - type: SET_EVENTS_START -}) - -export const setEventsEnd = (value) => ({ - type: SET_EVENTS_END, - value -}) - -export const setEventsFetching = (payload) => ({ - type: SET_EVENTS_FETCHING, - payload -}) - -export const setEventsError = (payload) => ({ - type: SET_EVENTS_ERROR, - payload -}) - -export const fetchEvents = signalHandler((signal) => (props) => async (dispatch) => { - - dispatch(setEventsStart(true)) - - try { - - const data = await api({ - query: ` - query fetchEvents { - events { - id - title - type - } - } - `, - props, - signal: signal() - }) - - dispatch(setEventsEnd(data.events)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setEventsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setEventsError(err)) - - } - -}) - -export const addEvent = (props, state) => async (dispatch) => { - - dispatch(setEventsStart(true)) - - try { - - await api({ - query: ` - mutation createEvent($input: CreateEventInput!) { - createEvent(input: $input) { - success - } - } - `, - variables: { - input: { - title: state.title, - type: state.type - } - }, - props - }) - - await dispatch(fetchEvents(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setEventsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setEventsError(err)) - - } - -} - -export const updateEvent = signalHandler((signal) => (props, eventId, state) => async (dispatch) => { - - dispatch(setEventsStart(true)) - - try { - - await api({ - query: ` - mutation updateEvent($id: ID!, $input: UpdateEventInput!) { - updateEvent(id: $id, input: $input) { - success - } - } - `, - variables: { - id: eventId, - input: { - title: state.title, - type: state.type - } - }, - props, - signal: signal(eventId) - }) - - await dispatch(fetchEvents(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setEventsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setEventsError(err)) - - } - -}) - -export const deleteEvent = signalHandler((signal) => (props, eventId) => async (dispatch) => { - - dispatch(setEventsStart(true)) - - try { - - await api({ - query: ` - mutation deleteEvent($id: ID!) { - deleteEvent(id: $id) { - success - } - } - `, - variables: { - id: eventId - }, - props, - signal: signal(eventId) - }) - - await dispatch(fetchEvents(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setEventsFetching(false)) - if (err.name === 'HandledError') return - dispatch(setEventsError(err)) - - } - -}) \ No newline at end of file diff --git a/src/ui/scripts/actions/index.js b/src/ui/scripts/actions/index.js index 6f6b89df..1670ab70 100644 --- a/src/ui/scripts/actions/index.js +++ b/src/ui/scripts/actions/index.js @@ -1,7 +1,4 @@ export * from './modals' export * from './token' -export * from './permanentTokens' export * from './filter' -export * from './domains' -export * from './events' export * from './widgets' \ No newline at end of file diff --git a/src/ui/scripts/actions/permanentTokens.js b/src/ui/scripts/actions/permanentTokens.js deleted file mode 100644 index 1e557ec6..00000000 --- a/src/ui/scripts/actions/permanentTokens.js +++ /dev/null @@ -1,164 +0,0 @@ -import api from '../utils/api' -import signalHandler from '../utils/signalHandler' - -export const SET_PERMANENT_TOKENS_START = Symbol() -export const SET_PERMANENT_TOKENS_END = Symbol() -export const SET_PERMANENT_TOKENS_FETCHING = Symbol() -export const SET_PERMANENT_TOKENS_ERROR = Symbol() - -export const setPermanentTokensStart = () => ({ - type: SET_PERMANENT_TOKENS_START -}) - -export const setPermanentTokensEnd = (value) => ({ - type: SET_PERMANENT_TOKENS_END, - value -}) - -export const setPermanentTokensFetching = (payload) => ({ - type: SET_PERMANENT_TOKENS_FETCHING, - payload -}) - -export const setPermanentTokensError = (payload) => ({ - type: SET_PERMANENT_TOKENS_ERROR, - payload -}) - -export const fetchPermanentTokens = signalHandler((signal) => (props) => async (dispatch) => { - - dispatch(setPermanentTokensStart()) - - try { - - const data = await api({ - query: ` - query fetchPermanentTokens { - permanentTokens { - id - title - } - } - `, - props, - signal: signal() - }) - - dispatch(setPermanentTokensEnd(data.permanentTokens)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setPermanentTokensFetching(false)) - if (err.name === 'HandledError') return - dispatch(setPermanentTokensError(err)) - - } - -}) - -export const addPermanentToken = (props, state) => async (dispatch) => { - - dispatch(setPermanentTokensStart()) - - try { - - await api({ - query: ` - mutation createPermanentToken($input: CreatePermanentTokenInput!) { - createPermanentToken(input: $input) { - success - } - } - `, - variables: { - input: { - title: state.title - } - }, - props - }) - - await dispatch(fetchPermanentTokens(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setPermanentTokensFetching(false)) - if (err.name === 'HandledError') return - dispatch(setPermanentTokensError(err)) - - } - -} - -export const updatePermanentToken = signalHandler((signal) => (props, permanentTokenId, state) => async (dispatch) => { - - dispatch(setPermanentTokensStart()) - - try { - - await api({ - query: ` - mutation updatePermanentToken($id: ID!, $input: UpdatePermanentTokenInput!) { - updatePermanentToken(id: $id, input: $input) { - success - } - } - `, - variables: { - id: permanentTokenId, - input: { - title: state.title - } - }, - props, - signal: signal(permanentTokenId) - }) - - await dispatch(fetchPermanentTokens(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setPermanentTokensFetching(false)) - if (err.name === 'HandledError') return - dispatch(setPermanentTokensError(err)) - - } - -}) - -export const deletePermanentToken = signalHandler((signal) => (props, permanentTokenId) => async (dispatch) => { - - dispatch(setPermanentTokensStart()) - - try { - - await api({ - query: ` - mutation deletePermanentToken($id: ID!) { - deletePermanentToken(id: $id) { - success - } - } - `, - variables: { - id: permanentTokenId - }, - props, - signal: signal(permanentTokenId) - }) - - await dispatch(fetchPermanentTokens(props)) - - } catch (err) { - - if (err.name === 'AbortError') return - dispatch(setPermanentTokensFetching(false)) - if (err.name === 'HandledError') return - dispatch(setPermanentTokensError(err)) - - } - -}) \ No newline at end of file diff --git a/src/ui/scripts/api/fragments/domainFields.js b/src/ui/scripts/api/fragments/domainFields.js new file mode 100644 index 00000000..8aad3a0d --- /dev/null +++ b/src/ui/scripts/api/fragments/domainFields.js @@ -0,0 +1,8 @@ +import { gql } from '@apollo/client' + +export default gql` + fragment domainFields on Domain { + id + title + } +` \ No newline at end of file diff --git a/src/ui/scripts/api/fragments/eventFields.js b/src/ui/scripts/api/fragments/eventFields.js new file mode 100644 index 00000000..213d3e23 --- /dev/null +++ b/src/ui/scripts/api/fragments/eventFields.js @@ -0,0 +1,9 @@ +import { gql } from '@apollo/client' + +export default gql` + fragment eventFields on Event { + id + title + type + } +` \ No newline at end of file diff --git a/src/ui/scripts/api/fragments/permanentTokenFields.js b/src/ui/scripts/api/fragments/permanentTokenFields.js new file mode 100644 index 00000000..2ac4b99e --- /dev/null +++ b/src/ui/scripts/api/fragments/permanentTokenFields.js @@ -0,0 +1,8 @@ +import { gql } from '@apollo/client' + +export default gql` + fragment permanentTokenFields on PermanentToken { + id + title + } +` \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useCreateDomain.js b/src/ui/scripts/api/hooks/useCreateDomain.js new file mode 100644 index 00000000..c37290ae --- /dev/null +++ b/src/ui/scripts/api/hooks/useCreateDomain.js @@ -0,0 +1,32 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +import domainFields from '../fragments/domainFields' + +const mutation = gql` + mutation createDomain($input: CreateDomainInput!) { + createDomain(input: $input) { + payload { + ...domainFields + } + } + } + + ${ domainFields } +` + +export default () => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + refetchQueries: [ + 'domains' + ] + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useCreateEvent.js b/src/ui/scripts/api/hooks/useCreateEvent.js new file mode 100644 index 00000000..a4449f79 --- /dev/null +++ b/src/ui/scripts/api/hooks/useCreateEvent.js @@ -0,0 +1,32 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +import eventFields from '../fragments/eventFields' + +const mutation = gql` + mutation createEvent($input: CreateEventInput!) { + createEvent(input: $input) { + payload { + ...eventFields + } + } + } + + ${ eventFields } +` + +export default () => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + refetchQueries: [ + 'events' + ] + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useCreatePermanentToken.js b/src/ui/scripts/api/hooks/useCreatePermanentToken.js new file mode 100644 index 00000000..8470d603 --- /dev/null +++ b/src/ui/scripts/api/hooks/useCreatePermanentToken.js @@ -0,0 +1,32 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +import permanentTokenFields from '../fragments/permanentTokenFields' + +const mutation = gql` + mutation createPermanentToken($input: CreatePermanentTokenInput!) { + createPermanentToken(input: $input) { + payload { + ...permanentTokenFields + } + } + } + + ${ permanentTokenFields } +` + +export default () => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + refetchQueries: [ + 'permanentTokens' + ] + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useDeleteDomain.js b/src/ui/scripts/api/hooks/useDeleteDomain.js new file mode 100644 index 00000000..013dec15 --- /dev/null +++ b/src/ui/scripts/api/hooks/useDeleteDomain.js @@ -0,0 +1,29 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +const mutation = gql` + mutation deleteDomain($id: ID!) { + deleteDomain(id: $id) { + success + } + } +` + +export default (id) => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + variables: { + id + }, + refetchQueries: [ + 'domains' + ] + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useDeleteEvent.js b/src/ui/scripts/api/hooks/useDeleteEvent.js new file mode 100644 index 00000000..40ee1a1b --- /dev/null +++ b/src/ui/scripts/api/hooks/useDeleteEvent.js @@ -0,0 +1,29 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +const mutation = gql` + mutation deleteEvent($id: ID!) { + deleteEvent(id: $id) { + success + } + } +` + +export default (id) => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + variables: { + id + }, + refetchQueries: [ + 'events' + ] + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useDeletePermanentToken.js b/src/ui/scripts/api/hooks/useDeletePermanentToken.js new file mode 100644 index 00000000..48802062 --- /dev/null +++ b/src/ui/scripts/api/hooks/useDeletePermanentToken.js @@ -0,0 +1,29 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +const mutation = gql` + mutation deletePermanentToken($id: ID!) { + deletePermanentToken(id: $id) { + success + } + } +` + +export default (id) => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + variables: { + id + }, + refetchQueries: [ + 'permanentTokens' + ] + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useDomains.js b/src/ui/scripts/api/hooks/useDomains.js index f6321fc6..553399d5 100644 --- a/src/ui/scripts/api/hooks/useDomains.js +++ b/src/ui/scripts/api/hooks/useDomains.js @@ -1,13 +1,16 @@ import { useMemo } from 'react' import { useQuery, gql } from '@apollo/client' +import domainFields from '../fragments/domainFields' + const query = gql` query domains { domains { - id - title + ...domainFields } } + + ${ domainFields } ` export default () => { diff --git a/src/ui/scripts/api/hooks/useEvents.js b/src/ui/scripts/api/hooks/useEvents.js index a62b2fb1..7d32c913 100644 --- a/src/ui/scripts/api/hooks/useEvents.js +++ b/src/ui/scripts/api/hooks/useEvents.js @@ -1,14 +1,16 @@ import { useMemo } from 'react' import { useQuery, gql } from '@apollo/client' +import eventFields from '../fragments/eventFields' + const query = gql` query events { events { - id - title - type + ...eventFields } } + + ${ eventFields } ` export default () => { diff --git a/src/ui/scripts/api/hooks/usePermanentTokens.js b/src/ui/scripts/api/hooks/usePermanentTokens.js index 7669282c..74c836ed 100644 --- a/src/ui/scripts/api/hooks/usePermanentTokens.js +++ b/src/ui/scripts/api/hooks/usePermanentTokens.js @@ -1,13 +1,16 @@ import { useMemo } from 'react' import { useQuery, gql } from '@apollo/client' +import permanentTokenFields from '../fragments/permanentTokenFields' + const query = gql` query permanentTokens { permanentTokens { - id - title + ...permanentTokenFields } } + + ${ permanentTokenFields } ` export default () => { diff --git a/src/ui/scripts/api/hooks/useUpdateDomain.js b/src/ui/scripts/api/hooks/useUpdateDomain.js new file mode 100644 index 00000000..ad5aa56e --- /dev/null +++ b/src/ui/scripts/api/hooks/useUpdateDomain.js @@ -0,0 +1,32 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +import domainFields from '../fragments/domainFields' + +const mutation = gql` + mutation updateDomain($id: ID!, $input: UpdateDomainInput!) { + updateDomain(id: $id, input: $input) { + payload { + ...domainFields + } + } + } + + ${ domainFields } +` + +export default (id) => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + variables: { + id + } + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useUpdateEvent.js b/src/ui/scripts/api/hooks/useUpdateEvent.js new file mode 100644 index 00000000..1c6704cd --- /dev/null +++ b/src/ui/scripts/api/hooks/useUpdateEvent.js @@ -0,0 +1,32 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +import eventFields from '../fragments/eventFields' + +const mutation = gql` + mutation updateEvent($id: ID!, $input: UpdateEventInput!) { + updateEvent(id: $id, input: $input) { + payload { + ...eventFields + } + } + } + + ${ eventFields } +` + +export default (id) => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + variables: { + id + } + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/api/hooks/useUpdatePermanentToken.js b/src/ui/scripts/api/hooks/useUpdatePermanentToken.js new file mode 100644 index 00000000..149be756 --- /dev/null +++ b/src/ui/scripts/api/hooks/useUpdatePermanentToken.js @@ -0,0 +1,32 @@ +import { useMemo } from 'react' +import { useMutation, gql } from '@apollo/client' + +import permanentTokenFields from '../fragments/permanentTokenFields' + +const mutation = gql` + mutation updatePermanentToken($id: ID!, $input: UpdatePermanentTokenInput!) { + updatePermanentToken(id: $id, input: $input) { + payload { + ...permanentTokenFields + } + } + } + + ${ permanentTokenFields } +` + +export default (id) => { + + const [ mutate, { loading: fetching, error }] = useMutation(mutation, { + variables: { + id + } + }) + + return useMemo(() => ({ + mutate, + fetching, + error + }), [ mutate, fetching, error ]) + +} \ No newline at end of file diff --git a/src/ui/scripts/components/Modals.js b/src/ui/scripts/components/Modals.js index 8136cc16..8eddaabf 100644 --- a/src/ui/scripts/components/Modals.js +++ b/src/ui/scripts/components/Modals.js @@ -34,44 +34,29 @@ const Modals = (props) => { return ( h(Modal, { key: modalId, visible: modalData.visible, ...commonProps }, modalData.type === MODALS_DOMAIN_ADD && h(ModalDomainAdd, { - ...commonProps, - fetching: props.domains.fetching, - addDomain: props.addDomain.bind(null, props) + ...commonProps }), modalData.type === MODALS_DOMAIN_EDIT && h(ModalDomainEdit, { ...commonProps, id: modalData.props.id, - title: modalData.props.title, - fetching: props.domains.fetching, - updateDomain: props.updateDomain.bind(null, props), - deleteDomain: props.deleteDomain.bind(null, props) + title: modalData.props.title }), modalData.type === MODALS_EVENT_ADD && h(ModalEventAdd, { - ...commonProps, - fetching: props.events.fetching, - addEvent: props.addEvent.bind(null, props) + ...commonProps }), modalData.type === MODALS_EVENT_EDIT && h(ModalEventEdit, { ...commonProps, id: modalData.props.id, title: modalData.props.title, - type: modalData.props.type, - fetching: props.events.fetching, - updateEvent: props.updateEvent.bind(null, props), - deleteEvent: props.deleteEvent.bind(null, props) + type: modalData.props.type }), modalData.type === MODALS_PERMANENT_TOKEN_ADD && h(ModalPermanentTokenAdd, { - ...commonProps, - fetching: props.permanentTokens.fetching, - addPermanentToken: props.addPermanentToken.bind(null, props) + ...commonProps }), modalData.type === MODALS_PERMANENT_TOKEN_EDIT && h(ModalPermanentTokenEdit, { ...commonProps, id: modalData.props.id, - title: modalData.props.title, - fetching: props.permanentTokens.fetching, - updatePermanentToken: props.updatePermanentToken.bind(null, props), - deletePermanentToken: props.deletePermanentToken.bind(null, props) + title: modalData.props.title }) ) ) diff --git a/src/ui/scripts/components/modals/ModalDomainAdd.js b/src/ui/scripts/components/modals/ModalDomainAdd.js index d8eb8fc3..412c66b8 100644 --- a/src/ui/scripts/components/modals/ModalDomainAdd.js +++ b/src/ui/scripts/components/modals/ModalDomainAdd.js @@ -1,16 +1,20 @@ import { createElement as h, useState } from 'react' -import PropTypes from 'prop-types' import Input from '../Input' import Label from '../Label' import Spinner from '../Spinner' import Spacer from '../Spacer' +import useCreateDomain from '../../api/hooks/useCreateDomain' import commonModalProps from '../../utils/commonModalProps' import shortId from '../../utils/shortId' const ModalDomainAdd = (props) => { + const createDomain = useCreateDomain() + + const fetching = createDomain.fetching === true + const [ inputs, setInputs ] = useState({ title: '' }) @@ -20,15 +24,19 @@ const ModalDomainAdd = (props) => { [key]: e.target.value }) - const addDomain = (e) => { + const onSubmit = (e) => { e.preventDefault() - props.addDomain(inputs).then(props.closeModal) + createDomain.mutate({ + variables: { + input: inputs + } + }).then(props.closeModal) } const titleId = shortId() return ( - h('form', { className: 'card', onSubmit: addDomain }, + h('form', { className: 'card', onSubmit }, h('div', { className: 'card__inner' }, h(Spacer, { size: 0.5 }), @@ -39,7 +47,7 @@ const ModalDomainAdd = (props) => { type: 'text', id: titleId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, focused: true, placeholder: 'Domain title', value: inputs.title, @@ -62,8 +70,8 @@ const ModalDomainAdd = (props) => { h('button', { className: 'card__button card__button--primary link color-white', - disabled: props.fetching === true || props.active === false - }, props.fetching === true ? h(Spinner) : 'Add') + disabled: fetching === true || props.active === false + }, fetching === true ? h(Spinner) : 'Add') ) ) @@ -72,9 +80,7 @@ const ModalDomainAdd = (props) => { } ModalDomainAdd.propTypes = { - ...commonModalProps, - fetching: PropTypes.bool.isRequired, - addDomain: PropTypes.func.isRequired + ...commonModalProps } export default ModalDomainAdd \ No newline at end of file diff --git a/src/ui/scripts/components/modals/ModalDomainEdit.js b/src/ui/scripts/components/modals/ModalDomainEdit.js index d925ef3e..70dc8f17 100644 --- a/src/ui/scripts/components/modals/ModalDomainEdit.js +++ b/src/ui/scripts/components/modals/ModalDomainEdit.js @@ -7,11 +7,18 @@ import Label from '../Label' import Spinner from '../Spinner' import Spacer from '../Spacer' +import useUpdateDomain from '../../api/hooks/useUpdateDomain' +import useDeleteDomain from '../../api/hooks/useDeleteDomain' import commonModalProps from '../../utils/commonModalProps' import shortId from '../../utils/shortId' const ModalDomainEdit = (props) => { + const updateDomain = useUpdateDomain(props.id) + const deleteDomain = useDeleteDomain(props.id) + + const fetching = updateDomain.fetching === true || deleteDomain.fetching === true + const [ inputs, setInputs ] = useState({ title: props.title }) @@ -21,15 +28,22 @@ const ModalDomainEdit = (props) => { [key]: e.target.value }) - const updateDomain = (e) => { + const onSubmit = (e) => { e.preventDefault() - props.updateDomain(props.id, inputs).then(props.closeModal) + updateDomain.mutate({ + variables: { + input: inputs + } + }).then(props.closeModal) } - const deleteDomain = (e) => { + const onDelete = (e) => { e.preventDefault() + const c = confirm(`Are you sure you want to delete the domain "${ props.title }"? This action cannot be undone.`) - if (c === true) props.deleteDomain(props.id, inputs).then(props.closeModal) + if (c === false) return + + deleteDomain.mutate().then(props.closeModal) } const titleId = shortId() @@ -41,7 +55,7 @@ const ModalDomainEdit = (props) => { const serverUrl = location.origin return ( - h('form', { className: 'card', onSubmit: updateDomain }, + h('form', { className: 'card', onSubmit }, h('div', { className: 'card__inner' }, h(Spacer, { size: 0.5 }), @@ -52,7 +66,7 @@ const ModalDomainEdit = (props) => { type: 'text', id: titleId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, focused: true, placeholder: 'Domain title', value: inputs.title, @@ -97,7 +111,7 @@ const ModalDomainEdit = (props) => { h('button', { type: 'button', className: 'card__button link color-destructive', - onClick: deleteDomain, + onClick: onDelete, disabled: props.active === false }, 'Delete'), @@ -107,8 +121,8 @@ const ModalDomainEdit = (props) => { h('button', { className: 'card__button card__button--primary link color-white', - disabled: props.fetching === true || props.active === false - }, props.fetching === true ? h(Spinner) : 'Rename') + disabled: fetching === true || props.active === false + }, fetching === true ? h(Spinner) : 'Rename') ) ) @@ -119,10 +133,7 @@ const ModalDomainEdit = (props) => { ModalDomainEdit.propTypes = { ...commonModalProps, id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - fetching: PropTypes.bool.isRequired, - updateDomain: PropTypes.func.isRequired, - deleteDomain: PropTypes.func.isRequired + title: PropTypes.string.isRequired } export default ModalDomainEdit \ No newline at end of file diff --git a/src/ui/scripts/components/modals/ModalEventAdd.js b/src/ui/scripts/components/modals/ModalEventAdd.js index 41cf475a..888405c0 100644 --- a/src/ui/scripts/components/modals/ModalEventAdd.js +++ b/src/ui/scripts/components/modals/ModalEventAdd.js @@ -1,5 +1,4 @@ import { createElement as h, useState } from 'react' -import PropTypes from 'prop-types' import * as events from '../../../../constants/events' @@ -10,11 +9,16 @@ import Spinner from '../Spinner' import Spacer from '../Spacer' import Tooltip from '../Tooltip' +import useCreateEvent from '../../api/hooks/useCreateEvent' import commonModalProps from '../../utils/commonModalProps' import shortId from '../../utils/shortId' const ModalEventAdd = (props) => { + const createEvent = useCreateEvent() + + const fetching = createEvent.fetching === true + const [ inputs, setInputs ] = useState({ title: '', type: events.EVENTS_TYPE_TOTAL_CHART @@ -25,16 +29,20 @@ const ModalEventAdd = (props) => { [key]: e.target.value }) - const addEvent = (e) => { + const onSubmit = (e) => { e.preventDefault() - props.addEvent(inputs).then(props.closeModal) + createEvent.mutate({ + variables: { + input: inputs + } + }).then(props.closeModal) } const titleId = shortId() const typeId = shortId() return ( - h('form', { className: 'card', onSubmit: addEvent }, + h('form', { className: 'card', onSubmit }, h('div', { className: 'card__inner' }, h(Spacer, { size: 0.5 }), @@ -45,7 +53,7 @@ const ModalEventAdd = (props) => { type: 'text', id: titleId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, focused: true, placeholder: 'Event title', value: inputs.title, @@ -60,7 +68,7 @@ const ModalEventAdd = (props) => { h(Select, { id: typeId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, value: inputs.type, items: [ { @@ -99,8 +107,8 @@ const ModalEventAdd = (props) => { h('button', { className: 'card__button card__button--primary link color-white', - disabled: props.fetching === true || props.active === false - }, props.fetching === true ? h(Spinner) : 'Add') + disabled: fetching === true || props.active === false + }, fetching === true ? h(Spinner) : 'Add') ) ) @@ -109,9 +117,7 @@ const ModalEventAdd = (props) => { } ModalEventAdd.propTypes = { - ...commonModalProps, - fetching: PropTypes.bool.isRequired, - addEvent: PropTypes.func.isRequired + ...commonModalProps } export default ModalEventAdd \ No newline at end of file diff --git a/src/ui/scripts/components/modals/ModalEventEdit.js b/src/ui/scripts/components/modals/ModalEventEdit.js index f3c7f116..5b72e323 100644 --- a/src/ui/scripts/components/modals/ModalEventEdit.js +++ b/src/ui/scripts/components/modals/ModalEventEdit.js @@ -11,11 +11,18 @@ import Spinner from '../Spinner' import Spacer from '../Spacer' import Tooltip from '../Tooltip' +import useUpdateEvent from '../../api/hooks/useUpdateEvent' +import useDeleteEvent from '../../api/hooks/useDeleteEvent' import commonModalProps from '../../utils/commonModalProps' import shortId from '../../utils/shortId' const ModalEventEdit = (props) => { + const updateEvent = useUpdateEvent(props.id) + const deleteEvent = useDeleteEvent(props.id) + + const fetching = updateEvent.fetching === true || deleteEvent.fetching === true + const [ inputs, setInputs ] = useState({ title: props.title, type: props.type @@ -26,15 +33,22 @@ const ModalEventEdit = (props) => { [key]: e.target.value }) - const updateEvent = (e) => { + const onSubmit = (e) => { e.preventDefault() - props.updateEvent(props.id, inputs).then(props.closeModal) + updateEvent.mutate({ + variables: { + input: inputs + } + }).then(props.closeModal) } - const deleteEvent = (e) => { + const onDelete = (e) => { e.preventDefault() + const c = confirm(`Are you sure you want to delete the event "${ props.title }"? This action cannot be undone.`) - if (c === true) props.deleteEvent(props.id, inputs).then(props.closeModal) + if (c === false) return + + deleteEvent.mutate().then(props.closeModal) } const titleId = shortId() @@ -43,7 +57,7 @@ const ModalEventEdit = (props) => { const embedId = shortId() return ( - h('form', { className: 'card', onSubmit: updateEvent }, + h('form', { className: 'card', onSubmit }, h('div', { className: 'card__inner' }, h(Spacer, { size: 0.5 }), @@ -54,7 +68,7 @@ const ModalEventEdit = (props) => { type: 'text', id: titleId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, focused: true, placeholder: 'Event title', value: inputs.title, @@ -69,7 +83,7 @@ const ModalEventEdit = (props) => { h(Select, { id: typeId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, value: inputs.type, items: [ { @@ -130,7 +144,7 @@ const ModalEventEdit = (props) => { h('button', { type: 'button', className: 'card__button link color-destructive', - onClick: deleteEvent, + onClick: onDelete, disabled: props.active === false }, 'Delete'), @@ -140,8 +154,8 @@ const ModalEventEdit = (props) => { h('button', { className: 'card__button card__button--primary link color-white', - disabled: props.fetching === true || props.active === false - }, props.fetching === true ? h(Spinner) : 'Save') + disabled: fetching === true || props.active === false + }, fetching === true ? h(Spinner) : 'Save') ) ) @@ -152,10 +166,7 @@ const ModalEventEdit = (props) => { ModalEventEdit.propTypes = { ...commonModalProps, id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - fetching: PropTypes.bool.isRequired, - updateEvent: PropTypes.func.isRequired, - deleteEvent: PropTypes.func.isRequired + title: PropTypes.string.isRequired } export default ModalEventEdit \ No newline at end of file diff --git a/src/ui/scripts/components/modals/ModalPermanentTokenAdd.js b/src/ui/scripts/components/modals/ModalPermanentTokenAdd.js index d4f49f52..a6c8a047 100644 --- a/src/ui/scripts/components/modals/ModalPermanentTokenAdd.js +++ b/src/ui/scripts/components/modals/ModalPermanentTokenAdd.js @@ -1,16 +1,20 @@ import { createElement as h, useState } from 'react' -import PropTypes from 'prop-types' import Input from '../Input' import Label from '../Label' import Spinner from '../Spinner' import Spacer from '../Spacer' +import useCreatePermanentToken from '../../api/hooks/useCreatePermanentToken' import commonModalProps from '../../utils/commonModalProps' import shortId from '../../utils/shortId' const ModalPermanentTokenAdd = (props) => { + const createPermanentToken = useCreatePermanentToken() + + const fetching = createPermanentToken.fetching === true + const [ inputs, setInputs ] = useState({ title: '' }) @@ -20,15 +24,19 @@ const ModalPermanentTokenAdd = (props) => { [key]: e.target.value }) - const addPermanentToken = (e) => { + const onSubmit = (e) => { e.preventDefault() - props.addPermanentToken(inputs).then(props.closeModal) + createPermanentToken.mutate({ + variables: { + input: inputs + } + }).then(props.closeModal) } const titleId = shortId() return ( - h('form', { className: 'card', onSubmit: addPermanentToken }, + h('form', { className: 'card', onSubmit }, h('div', { className: 'card__inner' }, h(Spacer, { size: 0.5 }), @@ -39,7 +47,7 @@ const ModalPermanentTokenAdd = (props) => { type: 'text', id: titleId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, focused: true, placeholder: 'Permanent token title', value: inputs.title, @@ -62,8 +70,8 @@ const ModalPermanentTokenAdd = (props) => { h('button', { className: 'card__button card__button--primary link color-white', - disabled: props.fetching === true || props.active === false - }, props.fetching === true ? h(Spinner) : 'Add') + disabled: fetching === true || props.active === false + }, fetching === true ? h(Spinner) : 'Add') ) ) @@ -72,9 +80,7 @@ const ModalPermanentTokenAdd = (props) => { } ModalPermanentTokenAdd.propTypes = { - ...commonModalProps, - fetching: PropTypes.bool.isRequired, - addPermanentToken: PropTypes.func.isRequired + ...commonModalProps } export default ModalPermanentTokenAdd \ No newline at end of file diff --git a/src/ui/scripts/components/modals/ModalPermanentTokenEdit.js b/src/ui/scripts/components/modals/ModalPermanentTokenEdit.js index 03d73e16..d9d80125 100644 --- a/src/ui/scripts/components/modals/ModalPermanentTokenEdit.js +++ b/src/ui/scripts/components/modals/ModalPermanentTokenEdit.js @@ -6,11 +6,18 @@ import Label from '../Label' import Spinner from '../Spinner' import Spacer from '../Spacer' +import useUpdatePermanentToken from '../../api/hooks/useUpdatePermanentToken' +import useDeletePermanentToken from '../../api/hooks/useDeletePermanentToken' import commonModalProps from '../../utils/commonModalProps' import shortId from '../../utils/shortId' const ModalPermanentTokenEdit = (props) => { + const updatePermanentToken = useUpdatePermanentToken(props.id) + const deletePermanentToken = useDeletePermanentToken(props.id) + + const fetching = updatePermanentToken.fetching === true || deletePermanentToken.fetching === true + const [ inputs, setInputs ] = useState({ title: props.title }) @@ -20,22 +27,29 @@ const ModalPermanentTokenEdit = (props) => { [key]: e.target.value }) - const updatePermanentToken = (e) => { + const onSubmit = (e) => { e.preventDefault() - props.updatePermanentToken(props.id, inputs).then(props.closeModal) + updatePermanentToken.mutate({ + variables: { + input: inputs + } + }).then(props.closeModal) } - const deletePermanentToken = (e) => { + const onDelete = (e) => { e.preventDefault() + const c = confirm(`Are you sure you want to delete the permanent token "${ props.title }"? This action cannot be undone.`) - if (c === true) props.deletePermanentToken(props.id, inputs).then(props.closeModal) + if (c === false) return + + deletePermanentToken.mutate().then(props.closeModal) } const titleId = shortId() const idId = shortId() return ( - h('form', { className: 'card', onSubmit: updatePermanentToken }, + h('form', { className: 'card', onSubmit }, h('div', { className: 'card__inner' }, h(Spacer, { size: 0.5 }), @@ -46,7 +60,7 @@ const ModalPermanentTokenEdit = (props) => { type: 'text', id: titleId, required: true, - disabled: props.fetching === true, + disabled: fetching === true, focused: true, placeholder: 'Permanent token title', value: inputs.title, @@ -81,7 +95,7 @@ const ModalPermanentTokenEdit = (props) => { h('button', { type: 'button', className: 'card__button link color-destructive', - onClick: deletePermanentToken, + onClick: onDelete, disabled: props.active === false }, 'Delete'), @@ -91,8 +105,8 @@ const ModalPermanentTokenEdit = (props) => { h('button', { className: 'card__button card__button--primary link color-white', - disabled: props.fetching === true || props.active === false - }, props.fetching === true ? h(Spinner) : 'Rename') + disabled: fetching === true || props.active === false + }, fetching === true ? h(Spinner) : 'Rename') ) ) @@ -103,10 +117,7 @@ const ModalPermanentTokenEdit = (props) => { ModalPermanentTokenEdit.propTypes = { ...commonModalProps, id: PropTypes.string.isRequired, - title: PropTypes.string.isRequired, - fetching: PropTypes.bool.isRequired, - updatePermanentToken: PropTypes.func.isRequired, - deletePermanentToken: PropTypes.func.isRequired + title: PropTypes.string.isRequired } export default ModalPermanentTokenEdit \ No newline at end of file diff --git a/src/ui/scripts/enhancers/enhanceState.js b/src/ui/scripts/enhancers/enhanceState.js index 154a1b66..ce017179 100644 --- a/src/ui/scripts/enhancers/enhanceState.js +++ b/src/ui/scripts/enhancers/enhanceState.js @@ -2,18 +2,12 @@ export default (state) => { const fetching = ( Object.values(state.widgets.value).some((value) => value.fetching) === true || - state.domains.fetching === true || - state.token.fetching === true || - state.permanentTokens.fetching === true || - state.events.fetching === true + state.token.fetching === true ) const errors = [ state.widgets.error, - state.domains.error, - state.token.error, - state.permanentTokens.error, - state.events.error + state.token.error ].filter(Boolean) return Object.assign({}, state, { diff --git a/src/ui/scripts/reducers/domains.js b/src/ui/scripts/reducers/domains.js deleted file mode 100644 index 5781a362..00000000 --- a/src/ui/scripts/reducers/domains.js +++ /dev/null @@ -1,35 +0,0 @@ -import produce from 'immer' - -import { - SET_DOMAINS_START, - SET_DOMAINS_END, - SET_DOMAINS_FETCHING, - SET_DOMAINS_ERROR -} from '../actions' - -export const initialState = () => ({ - value: [], - fetching: false, - error: undefined -}) - -export default produce((draft, action) => { - - switch (action.type) { - case SET_DOMAINS_START: - draft.fetching = true - draft.error = initialState().error - break - case SET_DOMAINS_END: - draft.value = action.value || initialState().value - draft.fetching = false - break - case SET_DOMAINS_FETCHING: - draft.fetching = action.payload || initialState().fetching - break - case SET_DOMAINS_ERROR: - draft.error = action.payload || initialState().error - break - } - -}, initialState()) \ No newline at end of file diff --git a/src/ui/scripts/reducers/events.js b/src/ui/scripts/reducers/events.js deleted file mode 100644 index a21f2171..00000000 --- a/src/ui/scripts/reducers/events.js +++ /dev/null @@ -1,35 +0,0 @@ -import produce from 'immer' - -import { - SET_EVENTS_START, - SET_EVENTS_END, - SET_EVENTS_FETCHING, - SET_EVENTS_ERROR -} from '../actions' - -export const initialState = () => ({ - value: [], - fetching: false, - error: undefined -}) - -export default produce((draft, action) => { - - switch (action.type) { - case SET_EVENTS_START: - draft.fetching = true - draft.error = initialState().error - break - case SET_EVENTS_END: - draft.value = action.value || initialState().value - draft.fetching = false - break - case SET_EVENTS_FETCHING: - draft.fetching = action.payload || initialState().fetching - break - case SET_EVENTS_ERROR: - draft.error = action.payload || initialState().error - break - } - -}, initialState()) \ No newline at end of file diff --git a/src/ui/scripts/reducers/index.js b/src/ui/scripts/reducers/index.js index 4b4c547a..95d3c536 100644 --- a/src/ui/scripts/reducers/index.js +++ b/src/ui/scripts/reducers/index.js @@ -6,19 +6,13 @@ import { import modals from './modals' import token from './token' -import permanentTokens from './permanentTokens' import filter from './filter' -import domains from './domains' -import events from './events' import widgets from './widgets' const reducers = combineReducers({ modals, token, - permanentTokens, filter, - domains, - events, widgets }) diff --git a/src/ui/scripts/reducers/permanentTokens.js b/src/ui/scripts/reducers/permanentTokens.js deleted file mode 100644 index 938d0aa4..00000000 --- a/src/ui/scripts/reducers/permanentTokens.js +++ /dev/null @@ -1,35 +0,0 @@ -import produce from 'immer' - -import { - SET_PERMANENT_TOKENS_START, - SET_PERMANENT_TOKENS_END, - SET_PERMANENT_TOKENS_FETCHING, - SET_PERMANENT_TOKENS_ERROR -} from '../actions' - -export const initialState = () => ({ - value: [], - fetching: false, - error: undefined -}) - -export default produce((draft, action) => { - - switch (action.type) { - case SET_PERMANENT_TOKENS_START: - draft.fetching = true - draft.error = initialState().error - break - case SET_PERMANENT_TOKENS_END: - draft.value = action.value || initialState().value - draft.fetching = false - break - case SET_PERMANENT_TOKENS_FETCHING: - draft.fetching = action.payload || initialState().fetching - break - case SET_PERMANENT_TOKENS_ERROR: - draft.error = action.payload || initialState().error - break - } - -}, initialState()) \ No newline at end of file From 54013e27e7530fe099e92a762a6b638ea1598acc Mon Sep 17 00:00:00 2001 From: Tobias Reich Date: Sun, 25 Apr 2021 11:21:18 +0200 Subject: [PATCH 010/151] Optimize later --- dist/index.js | 181 +++++++++++++++++- src/ui/index.js | 1 + src/ui/scripts/api/hooks/useCreateDomain.js | 5 +- src/ui/scripts/api/hooks/useCreateEvent.js | 5 +- .../api/hooks/useCreatePermanentToken.js | 5 +- src/ui/scripts/api/hooks/useDeleteDomain.js | 5 +- src/ui/scripts/api/hooks/useDeleteEvent.js | 5 +- .../api/hooks/useDeletePermanentToken.js | 5 +- src/ui/scripts/api/hooks/useDomains.js | 9 +- src/ui/scripts/api/hooks/useEvents.js | 9 +- .../scripts/api/hooks/usePermanentTokens.js | 9 +- src/ui/scripts/api/hooks/useUpdateDomain.js | 5 +- src/ui/scripts/api/hooks/useUpdateEvent.js | 5 +- .../api/hooks/useUpdatePermanentToken.js | 5 +- 14 files changed, 199 insertions(+), 55 deletions(-) diff --git a/dist/index.js b/dist/index.js index 96571713..d0f52b76 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3,7 +3,7 @@ object-assign (c) Sindre Sorhus @license MIT - */}var r=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,o=Object.prototype.propertyIsEnumerable;function i(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}var l=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,l,u=i(e),s=1;s=b},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125>>1,a=e[r];if(!(void 0!==a&&0x(i,n))void 0!==u&&0>x(u,i)?(e[r]=u,e[l]=n,r=l):(e[r]=i,e[o]=n,r=o);else{if(!(void 0!==u&&0>x(u,n)))break e;e[r]=u,e[l]=n,r=l}}}return t}return null}function x(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var T=[],C=[],N=1,R=null,P=3,O=!1,M=!1,L=!1;function D(e){for(var t=S(C);null!==t;){if(null===t.callback)_(C);else{if(!(t.startTime<=e))break;_(C),t.sortIndex=t.expirationTime,k(T,t)}t=S(C)}}function A(e){if(L=!1,D(e),!M)if(null!==S(T))M=!0,n(I);else{var t=S(C);null!==t&&r(A,t.startTime-e)}}function I(e,n){M=!1,L&&(L=!1,a()),O=!0;var o=P;try{for(D(n),R=S(T);null!==R&&(!(R.expirationTime>n)||e&&!t.unstable_shouldYield());){var i=R.callback;if("function"==typeof i){R.callback=null,P=R.priorityLevel;var l=i(R.expirationTime<=n);n=t.unstable_now(),"function"==typeof l?R.callback=l:R===S(T)&&_(T),D(n)}else _(T);R=S(T)}if(null!==R)var u=!0;else{var s=S(C);null!==s&&r(A,s.startTime-n),u=!1}return u}finally{R=null,P=o,O=!1}}var z=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){M||O||(M=!0,n(I))},t.unstable_getCurrentPriorityLevel=function(){return P},t.unstable_getFirstCallbackNode=function(){return S(T)},t.unstable_next=function(e){switch(P){case 1:case 2:case 3:var t=3;break;default:t=P}var n=P;P=t;try{return e()}finally{P=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=z,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=P;P=e;try{return t()}finally{P=n}},t.unstable_scheduleCallback=function(e,o,i){var l=t.unstable_now();switch("object"==typeof i&&null!==i?i="number"==typeof(i=i.delay)&&0l?(e.sortIndex=i,k(C,e),null===S(T)&&e===S(C)&&(L?a():L=!0,r(A,i-l))):(e.sortIndex=u,k(T,e),M||O||(M=!0,n(I))),e},t.unstable_wrapCallback=function(e){var t=P;return function(){var n=P;P=t;try{return e.apply(this,arguments)}finally{P=n}}}})); +n((function(e,t){}));var l=n((function(e){e.exports=u})),c=n((function(e,t){var n,r,i,o;if("object"==typeof performance&&"function"==typeof performance.now){var a=performance;t.unstable_now=function(){return a.now()}}else{var s=Date,u=s.now();t.unstable_now=function(){return s.now()-u}}if("undefined"==typeof window||"function"!=typeof MessageChannel){var l=null,c=null,f=function(){if(null!==l)try{var e=t.unstable_now();l(!0,e),l=null}catch(e){throw setTimeout(f,0),e}};n=function(e){null!==l?setTimeout(n,0,e):(l=e,setTimeout(f,0))},r=function(e,t){c=setTimeout(e,t)},i=function(){clearTimeout(c)},t.unstable_shouldYield=function(){return!1},o=t.unstable_forceFrameRate=function(){}}else{var d=window.setTimeout,p=window.clearTimeout;if("undefined"!=typeof console){var h=window.cancelAnimationFrame;"function"!=typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills"),"function"!=typeof h&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://reactjs.org/link/react-polyfills")}var v=!1,y=null,m=-1,g=5,b=0;t.unstable_shouldYield=function(){return t.unstable_now()>=b},o=function(){},t.unstable_forceFrameRate=function(e){0>e||125>>1,i=e[r];if(!(void 0!==i&&0O(a,n))void 0!==u&&0>O(u,a)?(e[r]=u,e[s]=n,r=s):(e[r]=a,e[o]=n,r=o);else{if(!(void 0!==u&&0>O(u,n)))break e;e[r]=u,e[s]=n,r=s}}}return t}return null}function O(e,t){var n=e.sortIndex-t.sortIndex;return 0!==n?n:e.id-t.id}var x=[],T=[],N=1,C=null,R=3,P=!1,I=!1,D=!1;function A(e){for(var t=S(T);null!==t;){if(null===t.callback)_(T);else{if(!(t.startTime<=e))break;_(T),t.sortIndex=t.expirationTime,k(x,t)}t=S(T)}}function M(e){if(D=!1,A(e),!I)if(null!==S(x))I=!0,n(L);else{var t=S(T);null!==t&&r(M,t.startTime-e)}}function L(e,n){I=!1,D&&(D=!1,i()),P=!0;var o=R;try{for(A(n),C=S(x);null!==C&&(!(C.expirationTime>n)||e&&!t.unstable_shouldYield());){var a=C.callback;if("function"==typeof a){C.callback=null,R=C.priorityLevel;var s=a(C.expirationTime<=n);n=t.unstable_now(),"function"==typeof s?C.callback=s:C===S(x)&&_(x),A(n)}else _(x);C=S(x)}if(null!==C)var u=!0;else{var l=S(T);null!==l&&r(M,l.startTime-n),u=!1}return u}finally{C=null,R=o,P=!1}}var F=o;t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(e){e.callback=null},t.unstable_continueExecution=function(){I||P||(I=!0,n(L))},t.unstable_getCurrentPriorityLevel=function(){return R},t.unstable_getFirstCallbackNode=function(){return S(x)},t.unstable_next=function(e){switch(R){case 1:case 2:case 3:var t=3;break;default:t=R}var n=R;R=t;try{return e()}finally{R=n}},t.unstable_pauseExecution=function(){},t.unstable_requestPaint=F,t.unstable_runWithPriority=function(e,t){switch(e){case 1:case 2:case 3:case 4:case 5:break;default:e=3}var n=R;R=e;try{return t()}finally{R=n}},t.unstable_scheduleCallback=function(e,o,a){var s=t.unstable_now();switch("object"==typeof a&&null!==a?a="number"==typeof(a=a.delay)&&0s?(e.sortIndex=a,k(T,e),null===S(x)&&e===S(T)&&(D?i():D=!0,r(M,a-s))):(e.sortIndex=u,k(x,e),I||P||(I=!0,n(L))),e},t.unstable_wrapCallback=function(e){var t=R;return function(){var n=R;R=t;try{return e.apply(this,arguments)}finally{R=n}}}})); /** @license React v0.20.1 * scheduler.production.min.js * @@ -37,7 +37,7 @@ n((function(e,t){}));var s=n((function(e){e.exports=u})),c=n((function(e,t){var * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -n((function(e,t){}));var d=n((function(e){e.exports=c})); +n((function(e,t){}));var f=n((function(e){e.exports=c})); /** @license React v17.0.1 * react-dom.production.min.js * @@ -45,7 +45,7 @@ n((function(e,t){}));var d=n((function(e){e.exports=c})); * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */function f(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n