-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: improved data fetching for execution details page (#131)
* refactor: integrate react-query for execution data fetching (#123) * refactor: using react-query to load top level Execution * refactor: upgrading react-query and fixing execution termination * refactor: handle 401s on queries and do auth flow * refactor: adding conditional refresh for execution status * refactor: cleanup broken files after context refactor * chore: docs * refactor: Remove ExecutionDataCache in favor of react-query (#126) * refactor: first step of using queries for NE table * refactor: removing data cache from first layer of NE table * refactor: removing remaining execution data cache usage * refactor: rename QueryKey type and remove bug workaround * refactor: fixing remaining consumers of NEs * test: adds setup for mock-service-worker (#127) * test: add msw and basic handlers for a few types * test: add mock data for a basic workflow execution * test: fixing/removing tests after adding msw * test: throw on unexpected requests to msw * fix: upgrade TS to fix error and cleanup resulting errors * Migrate from TSLint to ESLint (#128) * ci: move from tslint->eslint * fix: addressing eslint errors * fix: remove passing of unused variable * ci: remove unnecessary prettier config * refactor: clean up mock fixtures and re-enable tests for executions (#130) * test: adding test data for node executions * test: mocks and refactoring to re-enable NodeExecutionDetails tests * chore: lint error * test: getting first test for NE table working again * test: mocks and a couple of tests for NE table * refactor: msw handlers to use a backing map and return 404s * test: more tests for NE table * test: adding fixture for dynamic external workflow * test: using mock fixture for sub workflow tests * test: move remaining mocks to fixtures and fix tests * test: re-enabling more execution tests * fix: removing global query handlers for caching entitiesq * test: re-enable ExecutionNodeViews tests * fix: typo in import path * fix: show DataError by default for failed queries * chore: documentation * chore: pr feedback * test: fixing storybook rendering for NE table * refactor: queries and loading states for (Task)ExecutionDetails * chore: cleanup unused code * fix: adds mock support for launch plans * test: update LoadingSpinner tests * fix: handle error case for NE children * chore: remove todo * fix: typo
- Loading branch information
Showing
140 changed files
with
7,539 additions
and
5,073 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
src/generated/ | ||
.dist/ | ||
dist/ | ||
node_modules/ | ||
.vscode/ | ||
tsd/ | ||
package.json | ||
webpack.config.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,27 @@ | ||
// We are using eslint with the typescript parser plugin only to validate things | ||
// which are not supported in tslint, such as react hooks | ||
module.exports = { | ||
parser: '@typescript-eslint/parser', | ||
parserOptions: { | ||
jsx: true, | ||
sourceType: 'module' | ||
root: true, | ||
env: { | ||
browser: true, | ||
es6: true, | ||
node: true | ||
}, | ||
plugins: ['react-hooks'], | ||
parser: '@typescript-eslint/parser', | ||
plugins: ['@typescript-eslint', 'react-hooks', 'jest'], | ||
extends: [ | ||
'eslint:recommended', | ||
'plugin:@typescript-eslint/recommended', | ||
'plugin:react-hooks/recommended', | ||
'plugin:jest/recommended', | ||
'prettier', | ||
'prettier/@typescript-eslint' | ||
], | ||
rules: { | ||
'react-hooks/rules-of-hooks': 'error' | ||
'no-case-declarations': 'warn', | ||
'jest/no-mocks-import': 'off', | ||
'jest/valid-title': 'off', | ||
'@typescript-eslint/no-var-requires': 'off', | ||
'@typescript-eslint/ban-types': 'warn', | ||
'@typescript-eslint/no-empty-function': 'warn', | ||
'@typescript-eslint/explicit-module-boundary-types': 'off' | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
module.exports = { | ||
stories: ['../src/components/**/*.stories.tsx'], | ||
addons: ['@storybook/addon-knobs'] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import '../src/protobuf'; | ||
import { withKnobs } from '@storybook/addon-knobs'; | ||
import { addDecorator } from '@storybook/react'; | ||
import * as React from 'react'; | ||
import StoryRouter from 'storybook-react-router'; | ||
import { StorybookContainer } from './StorybookContainer'; | ||
|
||
addDecorator(withKnobs); | ||
addDecorator(StoryRouter()); | ||
addDecorator(Story => <StorybookContainer><Story /></StorybookContainer>); | ||
|
||
// Storybook executes this module in both bootstap phase (Node) | ||
// and a story's runtime (browser). However, cannot call `setupWorker` | ||
// in Node environment, so need to check if we're in a browser. | ||
if (typeof global.process === 'undefined') { | ||
const { worker } = require('./worker'); | ||
|
||
// Start the mocking when each story is loaded. | ||
// Repetitive calls to the `.start()` method will check for an existing | ||
// worker and reuse it. | ||
worker.start(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
/** | ||
* Mock Service Worker. | ||
* @see https://github.com/mswjs/msw | ||
* - Please do NOT modify this file. | ||
* - Please do NOT serve this file on production. | ||
*/ | ||
/* eslint-disable */ | ||
/* tslint:disable */ | ||
|
||
const INTEGRITY_CHECKSUM = '65d33ca82955e1c5928aed19d1bdf3f9' | ||
const bypassHeaderName = 'x-msw-bypass' | ||
|
||
let clients = {} | ||
|
||
self.addEventListener('install', function () { | ||
return self.skipWaiting() | ||
}) | ||
|
||
self.addEventListener('activate', async function (event) { | ||
return self.clients.claim() | ||
}) | ||
|
||
self.addEventListener('message', async function (event) { | ||
const clientId = event.source.id | ||
const client = await event.currentTarget.clients.get(clientId) | ||
const allClients = await self.clients.matchAll() | ||
const allClientIds = allClients.map((client) => client.id) | ||
|
||
switch (event.data) { | ||
case 'KEEPALIVE_REQUEST': { | ||
sendToClient(client, { | ||
type: 'KEEPALIVE_RESPONSE', | ||
}) | ||
break | ||
} | ||
|
||
case 'INTEGRITY_CHECK_REQUEST': { | ||
sendToClient(client, { | ||
type: 'INTEGRITY_CHECK_RESPONSE', | ||
payload: INTEGRITY_CHECKSUM, | ||
}) | ||
break | ||
} | ||
|
||
case 'MOCK_ACTIVATE': { | ||
clients = ensureKeys(allClientIds, clients) | ||
clients[clientId] = true | ||
|
||
sendToClient(client, { | ||
type: 'MOCKING_ENABLED', | ||
payload: true, | ||
}) | ||
break | ||
} | ||
|
||
case 'MOCK_DEACTIVATE': { | ||
clients = ensureKeys(allClientIds, clients) | ||
clients[clientId] = false | ||
break | ||
} | ||
|
||
case 'CLIENT_CLOSED': { | ||
const remainingClients = allClients.filter((client) => { | ||
return client.id !== clientId | ||
}) | ||
|
||
// Unregister itself when there are no more clients | ||
if (remainingClients.length === 0) { | ||
self.registration.unregister() | ||
} | ||
|
||
break | ||
} | ||
} | ||
}) | ||
|
||
self.addEventListener('fetch', function (event) { | ||
const { clientId, request } = event | ||
const requestClone = request.clone() | ||
const getOriginalResponse = () => fetch(requestClone) | ||
|
||
// Bypass navigation requests. | ||
if (request.mode === 'navigate') { | ||
return | ||
} | ||
|
||
// Bypass mocking if the current client isn't present in the internal clients map | ||
// (i.e. has the mocking disabled). | ||
if (!clients[clientId]) { | ||
return | ||
} | ||
|
||
// Opening the DevTools triggers the "only-if-cached" request | ||
// that cannot be handled by the worker. Bypass such requests. | ||
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { | ||
return | ||
} | ||
|
||
event.respondWith( | ||
new Promise(async (resolve, reject) => { | ||
const client = await event.target.clients.get(clientId) | ||
|
||
// Bypass mocking when the request client is not active. | ||
if (!client) { | ||
return resolve(getOriginalResponse()) | ||
} | ||
|
||
// Bypass requests with the explicit bypass header | ||
if (requestClone.headers.get(bypassHeaderName) === 'true') { | ||
const modifiedHeaders = serializeHeaders(requestClone.headers) | ||
|
||
// Remove the bypass header to comply with the CORS preflight check | ||
delete modifiedHeaders[bypassHeaderName] | ||
|
||
const originalRequest = new Request(requestClone, { | ||
headers: new Headers(modifiedHeaders), | ||
}) | ||
|
||
return resolve(fetch(originalRequest)) | ||
} | ||
|
||
const reqHeaders = serializeHeaders(request.headers) | ||
const body = await request.text() | ||
|
||
const rawClientMessage = await sendToClient(client, { | ||
type: 'REQUEST', | ||
payload: { | ||
url: request.url, | ||
method: request.method, | ||
headers: reqHeaders, | ||
cache: request.cache, | ||
mode: request.mode, | ||
credentials: request.credentials, | ||
destination: request.destination, | ||
integrity: request.integrity, | ||
redirect: request.redirect, | ||
referrer: request.referrer, | ||
referrerPolicy: request.referrerPolicy, | ||
body, | ||
bodyUsed: request.bodyUsed, | ||
keepalive: request.keepalive, | ||
}, | ||
}) | ||
|
||
const clientMessage = rawClientMessage | ||
|
||
switch (clientMessage.type) { | ||
case 'MOCK_SUCCESS': { | ||
setTimeout( | ||
resolve.bind(this, createResponse(clientMessage)), | ||
clientMessage.payload.delay, | ||
) | ||
break | ||
} | ||
|
||
case 'MOCK_NOT_FOUND': { | ||
return resolve(getOriginalResponse()) | ||
} | ||
|
||
case 'NETWORK_ERROR': { | ||
const { name, message } = clientMessage.payload | ||
const networkError = new Error(message) | ||
networkError.name = name | ||
|
||
// Rejecting a request Promise emulates a network error. | ||
return reject(networkError) | ||
} | ||
|
||
case 'INTERNAL_ERROR': { | ||
const parsedBody = JSON.parse(clientMessage.payload.body) | ||
|
||
console.error( | ||
`\ | ||
[MSW] Request handler function for "%s %s" has thrown the following exception: | ||
${parsedBody.errorType}: ${parsedBody.message} | ||
(see more detailed error stack trace in the mocked response body) | ||
This exception has been gracefully handled as a 500 response, however, it's strongly recommended to resolve this error. | ||
If you wish to mock an error response, please refer to this guide: https://mswjs.io/docs/recipes/mocking-error-responses\ | ||
`, | ||
request.method, | ||
request.url, | ||
) | ||
|
||
return resolve(createResponse(clientMessage)) | ||
} | ||
} | ||
}).catch((error) => { | ||
console.error( | ||
'[MSW] Failed to mock a "%s" request to "%s": %s', | ||
request.method, | ||
request.url, | ||
error, | ||
) | ||
}), | ||
) | ||
}) | ||
|
||
function serializeHeaders(headers) { | ||
const reqHeaders = {} | ||
headers.forEach((value, name) => { | ||
reqHeaders[name] = reqHeaders[name] | ||
? [].concat(reqHeaders[name]).concat(value) | ||
: value | ||
}) | ||
return reqHeaders | ||
} | ||
|
||
function sendToClient(client, message) { | ||
return new Promise((resolve, reject) => { | ||
const channel = new MessageChannel() | ||
|
||
channel.port1.onmessage = (event) => { | ||
if (event.data && event.data.error) { | ||
reject(event.data.error) | ||
} else { | ||
resolve(event.data) | ||
} | ||
} | ||
|
||
client.postMessage(JSON.stringify(message), [channel.port2]) | ||
}) | ||
} | ||
|
||
function createResponse(clientMessage) { | ||
return new Response(clientMessage.payload.body, { | ||
...clientMessage.payload, | ||
headers: clientMessage.payload.headers, | ||
}) | ||
} | ||
|
||
function ensureKeys(keys, obj) { | ||
return Object.keys(obj).reduce((acc, key) => { | ||
if (keys.includes(key)) { | ||
acc[key] = obj[key] | ||
} | ||
|
||
return acc | ||
}, {}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { setupWorker, SetupWorkerApi } from 'msw'; | ||
import { AdminServer, createAdminServer } from '../src/mocks/createAdminServer'; | ||
import { basicPythonWorkflow } from '../src/mocks/data/fixtures/basicPythonWorkflow'; | ||
import { dynamicExternalSubWorkflow } from '../src/mocks/data/fixtures/dynamicExternalSubworkflow'; | ||
import { dynamicPythonNodeExecutionWorkflow } from '../src/mocks/data/fixtures/dynamicPythonWorkflow'; | ||
import { oneFailedTaskWorkflow } from '../src/mocks/data/fixtures/oneFailedTaskWorkflow'; | ||
import { insertFixture } from '../src/mocks/data/insertFixture'; | ||
import { insertDefaultData } from '../src/mocks/insertDefaultData'; | ||
|
||
const { handlers, server } = createAdminServer(); | ||
export type MockServer = SetupWorkerApi & AdminServer; | ||
const worker: MockServer = { ...setupWorker(...handlers), ...server }; | ||
insertDefaultData(worker); | ||
insertFixture(worker, basicPythonWorkflow.generate()); | ||
insertFixture(worker, dynamicExternalSubWorkflow.generate()); | ||
insertFixture(worker, dynamicPythonNodeExecutionWorkflow.generate()); | ||
insertFixture(worker, oneFailedTaskWorkflow.generate()); | ||
|
||
export { worker }; |
Oops, something went wrong.