refactor(frontend): remove deprecated types

This commit is contained in:
Alex Kaminskii 2022-12-12 17:52:02 +01:00
parent d081873ca5
commit cbbe26a3d5
12 changed files with 1 additions and 1037 deletions

View file

@ -7,12 +7,8 @@ import issues from './issues';
import assignments from './assignments';
import target from './target';
import targetCustom from './targetCustom';
import runs from './runs';
import filters from './filters';
import funnelFilters from './funnelFilters';
import tests from './tests';
import steps from './steps';
import schedules from './schedules';
import events from './events';
import environments from './environments';
import variables from './variables';
@ -46,12 +42,9 @@ export default combineReducers({
assignments,
target,
targetCustom,
runs,
filters,
funnelFilters,
tests,
steps,
schedules,
events,
environments,
variables,

View file

@ -1,7 +0,0 @@
import Run from 'Types/run';
import crudDuckGenerator from './tools/crudDuck';
const crudDuck = crudDuckGenerator('run', Run);
export const { fetchList, fetch, init, edit, save, remove } = crudDuck.actions;
export default crudDuck.reducer;

View file

@ -1,14 +0,0 @@
import Schedule from 'Types/schedule';
import crudDuckGenerator from './tools/crudDuck';
const crudDuck = crudDuckGenerator('scheduler', Schedule);
export const { fetchList, fetch, init, edit, remove } = crudDuck.actions;
export function save(instance) { // TODO: fix the crudDuckGenerator
return {
types: crudDuck.actionTypes.SAVE.toArray(),
call: client => client.post(`/schedulers${!!instance.schedulerId ? '/' + instance.schedulerId : '' }`, instance),
};
}
export default crudDuck.reducer;

View file

@ -1,77 +0,0 @@
import { List, Map } from 'immutable';
import { RequestTypes } from 'Duck/requestStateCreator';
import Step from 'Types/step';
import Event from 'Types/filter/event';
import { getRE } from 'App/utils';
import Test from 'Types/appTest';
import { countries } from 'App/constants';
import { KEYS } from 'Types/filter/customFilter';
const countryOptions = Object.keys(countries).map(c => ({filterKey: KEYS.USER_COUNTRY, label: KEYS.USER_COUNTRY, type: KEYS.USER_COUNTRY, value: c, actualValue: countries[c], isFilter: true }));
const INIT = 'steps/INIT';
const EDIT = 'steps/EDIT';
const SET_TEST = 'steps/SET_TEST';
const FETCH_LIST = new RequestTypes('steps/FETCH_LIST');
const initialState = Map({
list: List(),
test: Test(),
instance: Step(),
editingIndex: null,
});
const reducer = (state = initialState, action = {}) => {
switch (action.type) {
case FETCH_LIST.SUCCESS: {
return state.set('list', List(action.data).map(i => {
const type = i.type === 'navigate' ? i.type : 'location';
return {...i, type: type.toUpperCase()}
}))
}
case INIT:
return state
.set('instance', Step(action.instance))
.set('editingIndex', action.index)
.set('test', Test());
case EDIT:
return state.mergeIn([ 'instance' ], action.instance);
case SET_TEST:
return state.set('test', Test(action.test));
}
return state;
};
export default reducer;
export function init(instance, index) {
return {
type: INIT,
instance,
index,
};
}
export function edit(instance) {
return {
type: EDIT,
instance,
};
}
export function setTest(test) {
return {
type: SET_TEST,
test,
};
}
export function fetchList(params) {
return {
types: FETCH_LIST.toArray(),
call: client => client.get('/tests/steps/search', params),
params,
};
}

File diff suppressed because one or more lines are too long

View file

@ -1,118 +0,0 @@
import { Map } from 'immutable';
import Test from 'Types/appTest';
import Run, { RUNNING, STOPPED } from 'Types/run';
import requestDuckGenerator, { RequestTypes } from 'Duck/tools/requestDuck';
import { reduceDucks } from 'Duck/tools';
const GEN_TEST = new RequestTypes('tests/GEN_TEST');
const RUN_TEST = new RequestTypes('tests/RUN_TEST');
const STOP_RUN = new RequestTypes('tests/STOP_RUN');
const STOP_ALL_RUNS = new RequestTypes('tests/STOP_ALL_RUNS');
const CHECK_RUN = new RequestTypes('tests/CHECK_RUN');
const RESET_ERRORS = 'tests/RESET_ERRORS';
const updateRunInTest = run => (test) => {
const runIndex = test.runHistory
.findLastIndex(({ runId }) => run.runId === runId);
return runIndex === -1
? test.update('runHistory', list => list.push(run))
: test.mergeIn([ 'runHistory', runIndex ], run);
};
const updateRun = (state, testId, run) => {
const testIndex = state.get('list').findIndex(test => test.testId === testId);
if (testIndex === -1) return state;
const updater = updateRunInTest(run);
return state
.updateIn([ 'list', testIndex ], updater)
.updateIn([ 'instance' ], test => (test.testId === testId
? updater(test)
: test));
};
const initialState = Map({});
const reducer = (state = initialState, action = {}) => {
switch (action.type) {
case GEN_TEST.SUCCESS:
return state.set('instance', Test(action.data).set('generated', true));
case RUN_TEST.SUCCESS: {
const test = state.get('list').find(({ testId }) => testId === action.testId);
const run = Run({
runId: action.data.id, state: RUNNING, testId: action.testId, name: test.name
});
return updateRun(state, action.testId, run);
}
case STOP_RUN.SUCCESS: {
const { testId, runId } = action;
return updateRun(state, testId, { runId, state: STOPPED });
}
case STOP_ALL_RUNS.SUCCESS:
return state.update('list', list => list.map(test => {
test.runHistory.map(run => run.state === RUNNING ? run.set('state', STOPPED) : run.state);
return test;
})).setIn(['runRequest', 'errors'], null);
case CHECK_RUN.SUCCESS:
return updateRun(state, action.testId, Run(action.data));
case RESET_ERRORS:
return state.setIn(['runRequest', 'errors'], null);
}
return state;
};
const requestDuck = requestDuckGenerator({
runRequest: RUN_TEST,
stopRunRequest: STOP_RUN,
stopAllRunsRequest: STOP_ALL_RUNS,
genTestRequest: GEN_TEST,
});
export default reduceDucks({ reducer, initialState }, requestDuck);
export function generateTest(sessionId, params) {
return {
types: GEN_TEST.toArray(),
call: client => client.post(`/sessions/${ sessionId }/gentest`, params),
};
}
export function runTest(testId, params) {
return {
testId,
types: RUN_TEST.toArray(),
call: client => client.post(`/tests/${ testId }/execute`, params),
};
}
export function stopRun(testId, runId) {
return {
runId,
testId,
types: STOP_RUN.toArray(),
call: client => client.get(`/runs/${ runId }/stop`),
};
}
export function stopAllRuns() {
return {
types: STOP_ALL_RUNS.toArray(),
call: client => client.get(`/runs/all/stop`),
};
}
export function resetErrors() {
return {
type: RESET_ERRORS,
}
}
export function checkRun(testId, runId) {
return {
runId,
testId,
types: CHECK_RUN.toArray(),
call: client => client.get(`/runs/${ runId }`),
};
}

View file

@ -1,4 +0,0 @@
import fromJS from './run';
export * from './run';
export default fromJS;

View file

@ -1,183 +0,0 @@
import { Record, List, Map } from 'immutable';
import { DateTime } from 'luxon';
import Environment from 'Types/environment';
import stepFromJS from './step';
import seleniumStepFromJS from './seleniumStep';
import Resource from '../session/resource';
export const NOT_FETCHED = undefined;
export const QUEUED = 'queued';
export const INITIALIZING = 'initializing';
export const RUNNING = 'running';
export const COMPLETED = 'completed';
export const PASSED = 'passed';
export const FAILED = 'failed';
export const STOPPED = 'stopped';
export const CRASHED = 'crashed';
export const EXPIRED = 'expired';
export const STATUS = {
NOT_FETCHED,
QUEUED,
INITIALIZING,
RUNNING,
COMPLETED,
PASSED,
FAILED,
STOPPED,
CRASHED,
EXPIRED,
}
class Run extends Record({
runId: undefined,
testId: undefined,
name: '',
tags: List(),
environment: Environment(),
scheduled: false,
schedulerId: undefined,
browser: undefined,
sessionId: undefined,
startedAt: undefined,
url_video: undefined,
finishedAt: undefined,
steps: List(),
resources: [],
seleniumSteps: List(),
url_browser_logs: undefined,
url_logs: undefined,
url_selenium_project: undefined,
sourceCode: undefined,
screenshotUrl: undefined,
clientId: undefined,
state: NOT_FETCHED,
baseRunId: undefined,
lastExecutedString: undefined,
durationString: undefined,
hour: undefined, // TODO: fine API
day: undefined,
location: undefined,
deviceType: undefined,
advancedOptions: undefined,
harfile: undefined,
lighthouseHtmlFile: undefined,
resultsFile: undefined,
lighthouseJsonFile: undefined,
totalStepsCount: undefined,
auditsPerformance: Map(),
auditsAd: Map(),
transferredSize: undefined,
resourcesSize: undefined,
domBuildingTime: undefined,
domContentLoadedTime: undefined,
loadTime: undefined,
starter: undefined,
// {
// "id": '',
// "title": '',
// "description": '',
// "score": 0,
// "scoreDisplayMode": '',
// "numericValue": 0,
// "numericUnit": '',
// "displayValue": ''
// }
}) {
idKey = 'runId';
isRunning() {
return this.state === RUNNING;
}
isQueued() {
return this.state === QUEUED;
}
isPassed() {
return this.state === PASSED;
}
}
// eslint-disable-next-line complexity
function fromJS(run = {}) {
if (run instanceof Run) return run;
const startedAt = run.startedAt && DateTime.fromMillis(run.startedAt);
const finishedAt = run.finishedAt && DateTime.fromMillis(run.finishedAt);
let durationString;
let lastExecutedString;
if (run.state === 'running') {
durationString = 'Running...';
lastExecutedString = 'Now';
} else if (startedAt && finishedAt) {
const _duration = Math.floor(finishedAt - startedAt);
if (_duration > 10000) {
const min = Math.floor(_duration / 60000);
durationString = `${ min < 1 ? 1 : min } min`;
} else {
durationString = `${ Math.floor(_duration / 1000) } secs`;
}
const diff = startedAt.diffNow([ 'days', 'hours', 'minutes', 'seconds' ]).negate();
if (diff.days > 0) {
lastExecutedString = `${ Math.round(diff.days) } day${ diff.days > 1 ? 's' : '' } ago`;
} else if (diff.hours > 0) {
lastExecutedString = `${ Math.round(diff.hours) } hrs ago`;
} else if (diff.minutes > 0) {
lastExecutedString = `${ Math.round(diff.minutes) } min ago`;
} else {
lastExecutedString = `${ Math.round(diff.seconds) } sec ago`;
}
}
const steps = List(run.steps).map(stepFromJS);
const seleniumSteps = List(run.seleniumSteps).map(seleniumStepFromJS);
const tags = List(run.tags);
const environment = Environment(run.environment);
let resources = List(run.network)
.map(i => Resource({
...i,
// success: 1,
// time: i.timestamp,
// type: 'xhr',
// headerSize: 1200,
// timings: {},
}));
const firstResourceTime = resources.map(r => r.time).reduce((a,b)=>Math.min(a,b), Number.MAX_SAFE_INTEGER);
resources = resources
.map(r => r.set("time", r.time - firstResourceTime))
.sort((r1, r2) => r1.time - r2.time).toArray()
const screenshotUrl = run.screenshot_url ||
seleniumSteps.find(({ screenshotUrl }) => !!screenshotUrl, null, {}).screenshotUrl;
const state = run.state === 'completed' ? PASSED : run.state;
const networkOverview = run.networkOverview || {};
return new Run({
...run,
startedAt,
finishedAt,
durationString,
lastExecutedString,
steps,
resources,
seleniumSteps,
tags,
environment,
screenshotUrl,
state,
deviceType: run.device || run.deviceType,
auditsPerformance: run.lighthouseJson && run.lighthouseJson.performance,
auditsAd: run.lighthouseJson && run.lighthouseJson.ad,
transferredSize: networkOverview.transferredSize,
resourcesSize: networkOverview.resourcesSize,
domBuildingTime: networkOverview.domBuildingTime,
domContentLoadedTime: networkOverview.domContentLoadedTime,
loadTime: networkOverview.loadTime,
});
}
Run.prototype.exists = function () {
return this.runId !== undefined;
};
export default fromJS;

View file

@ -1,29 +0,0 @@
import { Record, List } from 'immutable';
import { DateTime, Duration } from 'luxon';
const Step = Record({
duration: undefined,
startedAt: undefined,
label: undefined,
input: undefined,
info: undefined,
order: undefined,
screenshotUrl: undefined,
steps: List(),
});
function fromJS(step = {}) {
const startedAt = step.startedAt && DateTime.fromMillis(step.startedAt * 1000);
const duration = step.executionTime && Duration.fromMillis(step.executionTime);
const steps = List(step.steps).map(Step);
const screenshotUrl = step.screenshot_url;
return new Step({
...step,
steps,
startedAt,
duration,
screenshotUrl,
});
};
export default fromJS;

View file

@ -1,31 +0,0 @@
import { Record, List } from 'immutable';
import { DateTime, Duration } from 'luxon';
const Step = Record({
duration: undefined,
startedAt: undefined,
label: undefined,
input: undefined,
info: undefined,
order: undefined,
status: undefined,
title: undefined,
screenshotUrl: undefined,
steps: List(),
});
function fromJS(step = {}) {
const startedAt = step.startedAt && DateTime.fromMillis(step.startedAt);
const duration = step.executionTime && Duration.fromMillis(step.executionTime);
const steps = List(step.steps).map(Step);
const screenshotUrl = step.screenshot;
return new Step({
...step,
steps,
startedAt,
duration,
screenshotUrl,
});
};
export default fromJS;

View file

@ -1,228 +0,0 @@
import { Record, List, Map } from 'immutable';
import { DateTime } from 'luxon';
import {
CHANNEL,
DAYS,
HOURS,
EMAIL,
SLACK,
WEBHOOK
} from 'App/constants/schedule';
// import runFromJS from './run';
import { validateEmail } from 'App/validate';
export const DEFAULT_ENV_VALUE = '_';
const Schedule = Record({
minutes: 30,
hour: 0,
day: -2,
testId: '',
sourceCode: '',
name: '',
nextExecutionTime: undefined,
numberOFExecutions: undefined,
schedulerId: undefined,
environmentId: DEFAULT_ENV_VALUE,
device: 'desktop',
locations: [],
advancedOptions: false,
headers: [{}],
cookies: [{}],
basicAuth: {},
network: 'wifi',
bypassCSP: false,
slack: false,
slackInput: [],
webhook: false,
webhookInput: [],
email: false,
emailInput: [],
hasNotification: false,
options: Map({ message: [], device: 'desktop' }),
extraCaps: {},
validateEvery() {
if (this.day > -2) return true;
return this.minutes >= 5 && this.minutes <= 1440;
},
validateWebhookEmail() {
if (this.channel !== EMAIL) return true;
return validateEmail(this.webhookEmail);
},
validateWebhook() {
if (this.channel !== WEBHOOK) return true;
return this.webhookId !== '';
}
});
function fromJS(schedule = {}) {
if (schedule instanceof Schedule) return schedule;
const options = schedule.options || { message: [] };
const extraCaps = options.extraCaps || { };
let channel = '';
if (schedule.webhookEmail) {
channel = EMAIL;
} else if (schedule.webhookId && schedule.webhook) {
channel = schedule.webhook.type === 'slack' ? SLACK : WEBHOOK;
}
const nextExecutionTime = schedule.nextExecutionTime ?
DateTime.fromMillis(schedule.nextExecutionTime) : undefined;
let { day, minutes } = schedule;
let hour;
if (day !== -2) {
const utcOffset = new Date().getTimezoneOffset();
minutes = minutes - utcOffset
minutes = minutes >= 1440 ? (minutes - 1440) : minutes;
hour = Math.floor(minutes / 60);
}
// if (day !== -2) {
// const utcOffset = new Date().getTimezoneOffset();
// const hourOffset = Math.floor(utcOffset / 60);
// const minuteOffset = utcOffset - 60*hourOffset;
// minutes -= minuteOffset;
// hour -= hourOffset;
// if (day !== -1) {
// const dayOffset = Math.floor(hour/24); // +/-1
// day = (day + dayOffset + 7) % 7;
// }
// hour = (hour + 24) % 24;
// }
const slack = List(options.message).filter(i => i.type === 'slack');
const email = List(options.message).filter(i => i.type === 'email');
const webhook = List(options.message).filter(i => i.type === 'webhook');
const headers = extraCaps.headers ? Object.keys(extraCaps.headers).map(k => ({ name: k, value: extraCaps.headers[k] })) : [{}];
const cookies = extraCaps.cookies ? Object.keys(extraCaps.cookies).map(k => ({ name: k, value: extraCaps.cookies[k] })) : [{}];
return new Schedule({
...schedule,
day,
minutes,
hour,
channel,
nextExecutionTime,
device: options.device,
options,
advancedOptions: !!options.extraCaps,
bypassCSP: options.bypassCSP,
network: options.network,
headers,
cookies,
basicAuth: extraCaps.basicAuth,
slack: slack.size > 0,
slackInput: slack.map(i => parseInt(i.value)).toJS(),
email: email.size > 0,
emailInput: email.map(i => i.value).toJS(),
webhook: webhook.size > 0,
webhookInput: webhook.map(i => parseInt(i.value)).toJS(),
hasNotification: !!slack || !!email || !!webhook
});
}
function getObjetctFromArr(arr) {
const obj = {}
for (var i = 0; i < arr.length; i++) {
const temp = arr[i];
obj[temp.name] = temp.value
}
return obj;
}
Schedule.prototype.toData = function toData() {
const {
name, schedulerId, environmentId, device, options, bypassCSP, network, headers, cookies, basicAuth
} = this;
const js = this.toJS();
options.device = device;
options.bypassCSP = bypassCSP;
options.network = network;
options.extraCaps = {
headers: getObjetctFromArr(headers),
cookies: getObjetctFromArr(cookies),
basicAuth
};
if (js.slack && js.slackInput)
options.message = js.slackInput.map(i => ({ type: 'slack', value: i }))
if (js.email && js.emailInput)
options.message = options.message.concat(js.emailInput.map(i => ({ type: 'email', value: i })))
if (js.webhook && js.webhookInput)
options.message = options.message.concat(js.webhookInput.map(i => ({ type: 'webhook', value: i })))
let day = this.day;
let hour = undefined;
let minutes = this.minutes;
if (day !== -2) {
const utcOffset = new Date().getTimezoneOffset();
minutes = (this.hour * 60) + utcOffset;
// minutes += utcOffset;
minutes = minutes < 0 ? minutes + 1440 : minutes;
}
// if (day !== -2) {
// const utcOffset = new Date().getTimezoneOffset();
// const hourOffset = Math.floor(utcOffset / 60);
// const minuteOffset = utcOffset - 60*hourOffset;
// minutes = minuteOffset;
// hour = this.hour + hourOffset;
// if (day !== -1) {
// const dayOffset = Math.floor(hour/24); // +/-1
// day = (day + dayOffset + 7) % 7;
// }
// hour = (hour + 24) % 24;
// }
delete js.slack;
delete js.webhook;
delete js.email;
delete js.slackInput;
delete js.webhookInput;
delete js.emailInput;
delete js.hasNotification;
delete js.headers;
delete js.cookies;
delete js.device;
delete js.extraCaps;
// return {
// day, hour, name, minutes, schedulerId, environment,
// };
return { ...js, day, hour, name, minutes, schedulerId, environmentId, options: options };
};
Schedule.prototype.exists = function exists() {
return this.schedulerId !== undefined;
};
Schedule.prototype.valid = function validate() {
return this.validateEvery;
};
Schedule.prototype.getInterval = function getInterval() {
const DAY = List(DAYS).filter(item => item.value === this.day).first();
if (DAY.value === -2) {
return DAY.text + ' ' + this.minutes + ' Minutes'; // Every 30 minutes
}
const HOUR = List(HOURS).filter(item => item.value === this.hour).first();
return DAY.text + ' ' + HOUR.text; // Everyday/Sunday 2 AM;
};
export default fromJS;

View file

@ -1,152 +0,0 @@
import { Record, List, Set, isImmutable } from 'immutable';
import { TYPES as EVENT_TYPES } from 'Types/session/event';
export const CUSTOM = 'custom';
export const CLICK = 'click';
export const INPUT = 'input';
export const NAVIGATE = 'navigate';
export const TEST = 'test';
export const TYPES = {
CLICK,
INPUT,
CUSTOM,
NAVIGATE,
TEST,
};
const Step = defaultValues => class extends Record({
key: undefined,
name: '',
imported: false,
isDisabled: false,
importTestId: undefined,
...defaultValues,
}) {
hasTarget() {
return this.type === CLICK || this.type === INPUT;
}
isTest() {
return this.type === TEST;
}
getEventType() {
switch (this.type) {
case INPUT:
return EVENT_TYPES.INPUT;
case CLICK:
return EVENT_TYPES.CLICK;
case NAVIGATE:
return EVENT_TYPES.LOCATION;
default:
return null;
}
}
validate() {
const selectorsOK = this.selectors && this.selectors.size > 0;
const valueOK = this.value && this.value.trim().length > 0;
switch (this.type) {
case INPUT:
return selectorsOK;
case CLICK:
return selectorsOK;
case NAVIGATE:
return valueOK;
case CUSTOM:
// if (this.name.length === 0) return false;
/* if (window.JSHINT) {
window.JSHINT(this.code, { esversion: 6 });
const noErrors = window.JSHINT.errors.every(({ code }) => code && code.startsWith('W'));
return noErrors;
} */
return this.code && this.code.length > 0;
default:
return true;
}
}
toData() {
const {
value,
...step
} = this.toJS();
delete step.key;
return {
values: value && [ value ],
...step,
};
}
};
const Custom = Step({
type: CUSTOM,
code: '',
framework: 'any',
template: '',
});
const Click = Step({
type: CLICK,
selectors: List(),
customSelector: true,
});
const Input = Step({
type: INPUT,
selectors: List(),
value: '',
customSelector: true,
});
const Navigate = Step({
type: NAVIGATE,
value: '',
});
const TestAsStep = Step({
type: TEST,
testId: '',
name: '',
stepsCount: '',
steps: List(),
});
const EmptyStep = Step();
let uniqueKey = 0xff;
function nextKey() {
uniqueKey += 1;
return `${ uniqueKey }`;
}
function fromJS(initStep = {}) {
// TODO: more clear
if (initStep.importTestId) return new TestAsStep(initStep).set('steps', List(initStep.steps ? initStep.steps : initStep.test.steps).map(fromJS));
// todo: ?
if (isImmutable(initStep)) return initStep.set('key', nextKey());
const values = initStep.values && initStep.values.length > 0 && initStep.values[ 0 ];
// bad code
const step = {
...initStep,
selectors: Set(initStep.selectors).toList(), // to List not nrcrssary. TODO: check
value: initStep.value ? [initStep.value] : values,
key: nextKey(),
isDisabled: initStep.disabled
};
// bad code
if (step.type === CUSTOM) return new Custom(step);
if (step.type === CLICK) return new Click(step);
if (step.type === INPUT) return new Input(step);
if (step.type === NAVIGATE) return new Navigate(step);
return new EmptyStep();
// throw new Error(`Unknown step type: ${step.type}`);
}
export default fromJS;