Compare commits
28 Commits
AUT-1252
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1f93f3b262 | ||
![]() |
894afe8f92 | ||
![]() |
115394ac8c | ||
![]() |
de42eda65f | ||
![]() |
0b7591edce | ||
![]() |
a043a044ca | ||
![]() |
b1f2727beb | ||
![]() |
d6e78a48a0 | ||
![]() |
589fe0f5f3 | ||
![]() |
244eeeb816 | ||
![]() |
4d5fc50f1a | ||
![]() |
dc0273148c | ||
![]() |
5e6f4bfb88 | ||
![]() |
bc0e18d074 | ||
![]() |
24d09fda4c | ||
![]() |
5e20ac07d1 | ||
![]() |
37c78e6bbd | ||
![]() |
7dcfb1081b | ||
![]() |
01407cf040 | ||
![]() |
eb814c2fb0 | ||
![]() |
d3caadf4af | ||
![]() |
5769c82fca | ||
![]() |
3754783ce2 | ||
![]() |
55ebe2cc0b | ||
![]() |
23c1a42163 | ||
![]() |
c879ffa768 | ||
![]() |
32f7bbfbab | ||
![]() |
84d5b3b158 |
@@ -23,8 +23,6 @@
|
||||
"dependencies": {
|
||||
"@bull-board/express": "^3.10.1",
|
||||
"@casl/ability": "^6.5.0",
|
||||
"@graphql-tools/graphql-file-loader": "^7.3.4",
|
||||
"@graphql-tools/load": "^7.5.2",
|
||||
"@node-saml/passport-saml": "^4.0.4",
|
||||
"@rudderstack/rudder-sdk-node": "^1.1.2",
|
||||
"@sentry/node": "^7.42.0",
|
||||
@@ -38,14 +36,10 @@
|
||||
"crypto-js": "^4.1.1",
|
||||
"debug": "~2.6.9",
|
||||
"dotenv": "^10.0.0",
|
||||
"express": "~4.18.2",
|
||||
"express": "~4.20.0",
|
||||
"express-async-errors": "^3.1.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"express-graphql": "^0.12.0",
|
||||
"fast-xml-parser": "^4.0.11",
|
||||
"graphql-middleware": "^6.1.15",
|
||||
"graphql-shield": "^7.5.0",
|
||||
"graphql-tools": "^8.2.0",
|
||||
"handlebars": "^4.7.7",
|
||||
"http-errors": "~1.6.3",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
|
@@ -169,7 +169,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => {
|
||||
dynamicDataKey: 'listRepos',
|
||||
parameters: {},
|
||||
})
|
||||
.expect(200);
|
||||
.expect(422);
|
||||
|
||||
expect(response.body.errors).toEqual(errors);
|
||||
});
|
||||
|
@@ -1,20 +0,0 @@
|
||||
// Converted mutations
|
||||
import executeFlow from './mutations/execute-flow.js';
|
||||
import verifyConnection from './mutations/verify-connection.js';
|
||||
import updateCurrentUser from './mutations/update-current-user.js';
|
||||
import generateAuthUrl from './mutations/generate-auth-url.js';
|
||||
import createConnection from './mutations/create-connection.js';
|
||||
import resetConnection from './mutations/reset-connection.js';
|
||||
import updateConnection from './mutations/update-connection.js';
|
||||
|
||||
const mutationResolvers = {
|
||||
createConnection,
|
||||
executeFlow,
|
||||
generateAuthUrl,
|
||||
resetConnection,
|
||||
updateConnection,
|
||||
updateCurrentUser,
|
||||
verifyConnection,
|
||||
};
|
||||
|
||||
export default mutationResolvers;
|
@@ -1,48 +0,0 @@
|
||||
import App from '../../models/app.js';
|
||||
import AppConfig from '../../models/app-config.js';
|
||||
|
||||
const createConnection = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
const { key, appAuthClientId } = params.input;
|
||||
|
||||
const app = await App.findOneByKey(key);
|
||||
|
||||
const appConfig = await AppConfig.query().findOne({ key });
|
||||
|
||||
let formattedData = params.input.formattedData;
|
||||
if (appConfig) {
|
||||
if (appConfig.disabled)
|
||||
throw new Error(
|
||||
'This application has been disabled for new connections!'
|
||||
);
|
||||
|
||||
if (!appConfig.allowCustomConnection && formattedData)
|
||||
throw new Error(`Custom connections cannot be created for ${app.name}!`);
|
||||
|
||||
if (appConfig.shared && !formattedData) {
|
||||
const authClient = await appConfig
|
||||
.$relatedQuery('appAuthClients')
|
||||
.findById(appAuthClientId)
|
||||
.where({
|
||||
active: true,
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
formattedData = authClient.formattedAuthDefaults;
|
||||
}
|
||||
}
|
||||
|
||||
const createdConnection = await context.currentUser
|
||||
.$relatedQuery('connections')
|
||||
.insert({
|
||||
key,
|
||||
appAuthClientId,
|
||||
formattedData,
|
||||
verified: false,
|
||||
});
|
||||
|
||||
return createdConnection;
|
||||
};
|
||||
|
||||
export default createConnection;
|
@@ -1,16 +0,0 @@
|
||||
import AppAuthClient from '../../models/app-auth-client';
|
||||
|
||||
const deleteAppAuthClient = async (_parent, params, context) => {
|
||||
context.currentUser.can('delete', 'App');
|
||||
|
||||
await AppAuthClient.query()
|
||||
.delete()
|
||||
.findOne({
|
||||
id: params.input.id,
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
export default deleteAppAuthClient;
|
@@ -1,28 +0,0 @@
|
||||
import testRun from '../../services/test-run.js';
|
||||
import Step from '../../models/step.js';
|
||||
|
||||
const executeFlow = async (_parent, params, context) => {
|
||||
const conditions = context.currentUser.can('update', 'Flow');
|
||||
const isCreator = conditions.isCreator;
|
||||
const allSteps = Step.query();
|
||||
const userSteps = context.currentUser.$relatedQuery('steps');
|
||||
const baseQuery = isCreator ? userSteps : allSteps;
|
||||
|
||||
const { stepId } = params.input;
|
||||
|
||||
const untilStep = await baseQuery.clone().findById(stepId).throwIfNotFound();
|
||||
|
||||
const { executionStep } = await testRun({ stepId });
|
||||
|
||||
if (executionStep.isFailed) {
|
||||
throw new Error(JSON.stringify(executionStep.errorDetails));
|
||||
}
|
||||
|
||||
await untilStep.$query().patch({
|
||||
status: 'completed',
|
||||
});
|
||||
|
||||
return { data: executionStep.dataOut, step: untilStep };
|
||||
};
|
||||
|
||||
export default executeFlow;
|
@@ -1,30 +0,0 @@
|
||||
import globalVariable from '../../helpers/global-variable.js';
|
||||
import App from '../../models/app.js';
|
||||
|
||||
const generateAuthUrl = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
const connection = await context.currentUser
|
||||
.$relatedQuery('connections')
|
||||
.findOne({
|
||||
id: params.input.id,
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
if (!connection.formattedData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const authInstance = (
|
||||
await import(`../../apps/${connection.key}/auth/index.js`)
|
||||
).default;
|
||||
|
||||
const app = await App.findOneByKey(connection.key);
|
||||
|
||||
const $ = await globalVariable({ connection, app });
|
||||
await authInstance.generateAuthUrl($);
|
||||
|
||||
return connection.formattedData;
|
||||
};
|
||||
|
||||
export default generateAuthUrl;
|
@@ -1,22 +0,0 @@
|
||||
const resetConnection = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
let connection = await context.currentUser
|
||||
.$relatedQuery('connections')
|
||||
.findOne({
|
||||
id: params.input.id,
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
if (!connection.formattedData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
connection = await connection.$query().patchAndFetch({
|
||||
formattedData: { screenName: connection.formattedData.screenName },
|
||||
});
|
||||
|
||||
return connection;
|
||||
};
|
||||
|
||||
export default resetConnection;
|
@@ -1,33 +0,0 @@
|
||||
import AppAuthClient from '../../models/app-auth-client.js';
|
||||
|
||||
const updateConnection = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
let connection = await context.currentUser
|
||||
.$relatedQuery('connections')
|
||||
.findOne({
|
||||
id: params.input.id,
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
let formattedData = params.input.formattedData;
|
||||
|
||||
if (params.input.appAuthClientId) {
|
||||
const appAuthClient = await AppAuthClient.query()
|
||||
.findById(params.input.appAuthClientId)
|
||||
.throwIfNotFound();
|
||||
|
||||
formattedData = appAuthClient.formattedAuthDefaults;
|
||||
}
|
||||
|
||||
connection = await connection.$query().patchAndFetch({
|
||||
formattedData: {
|
||||
...connection.formattedData,
|
||||
...formattedData,
|
||||
},
|
||||
});
|
||||
|
||||
return connection;
|
||||
};
|
||||
|
||||
export default updateConnection;
|
@@ -1,11 +0,0 @@
|
||||
const updateCurrentUser = async (_parent, params, context) => {
|
||||
const user = await context.currentUser.$query().patchAndFetch({
|
||||
email: params.input.email,
|
||||
password: params.input.password,
|
||||
fullName: params.input.fullName,
|
||||
});
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
export default updateCurrentUser;
|
@@ -1,18 +0,0 @@
|
||||
const updateFlow = async (_parent, params, context) => {
|
||||
context.currentUser.can('update', 'Flow');
|
||||
|
||||
let flow = await context.currentUser
|
||||
.$relatedQuery('flows')
|
||||
.findOne({
|
||||
id: params.input.id,
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
flow = await flow.$query().patchAndFetch({
|
||||
name: params.input.name,
|
||||
});
|
||||
|
||||
return flow;
|
||||
};
|
||||
|
||||
export default updateFlow;
|
@@ -1,62 +0,0 @@
|
||||
import Role from '../../models/role.js';
|
||||
import Permission from '../../models/permission.js';
|
||||
import permissionCatalog from '../../helpers/permission-catalog.ee.js';
|
||||
|
||||
const updateRole = async (_parent, params, context) => {
|
||||
context.currentUser.can('update', 'Role');
|
||||
|
||||
const { id, name, description, permissions } = params.input;
|
||||
|
||||
const role = await Role.query().findById(id).throwIfNotFound();
|
||||
|
||||
try {
|
||||
const updatedRole = await Role.transaction(async (trx) => {
|
||||
await role.$relatedQuery('permissions', trx).delete();
|
||||
|
||||
if (permissions?.length) {
|
||||
const sanitizedPermissions = permissions
|
||||
.filter((permission) => {
|
||||
const { action, subject, conditions } = permission;
|
||||
|
||||
const relevantAction = permissionCatalog.actions.find(
|
||||
(actionCatalogItem) => actionCatalogItem.key === action
|
||||
);
|
||||
const validSubject = relevantAction.subjects.includes(subject);
|
||||
const validConditions = conditions.every((condition) => {
|
||||
return !!permissionCatalog.conditions.find(
|
||||
(conditionCatalogItem) => conditionCatalogItem.key === condition
|
||||
);
|
||||
});
|
||||
|
||||
return validSubject && validConditions;
|
||||
})
|
||||
.map((permission) => ({
|
||||
...permission,
|
||||
roleId: role.id,
|
||||
}));
|
||||
|
||||
await Permission.query().insert(sanitizedPermissions);
|
||||
}
|
||||
|
||||
await role.$query(trx).patch({
|
||||
name,
|
||||
description,
|
||||
});
|
||||
|
||||
return await Role.query(trx)
|
||||
.leftJoinRelated({
|
||||
permissions: true,
|
||||
})
|
||||
.withGraphFetched({
|
||||
permissions: true,
|
||||
})
|
||||
.findById(id);
|
||||
});
|
||||
|
||||
return updatedRole;
|
||||
} catch (err) {
|
||||
throw new Error('The role could not be updated!');
|
||||
}
|
||||
};
|
||||
|
||||
export default updateRole;
|
@@ -1,29 +0,0 @@
|
||||
import App from '../../models/app.js';
|
||||
import globalVariable from '../../helpers/global-variable.js';
|
||||
|
||||
const verifyConnection = async (_parent, params, context) => {
|
||||
context.currentUser.can('create', 'Connection');
|
||||
|
||||
let connection = await context.currentUser
|
||||
.$relatedQuery('connections')
|
||||
.findOne({
|
||||
id: params.input.id,
|
||||
})
|
||||
.throwIfNotFound();
|
||||
|
||||
const app = await App.findOneByKey(connection.key);
|
||||
const $ = await globalVariable({ connection, app });
|
||||
await app.auth.verifyCredentials($);
|
||||
|
||||
connection = await connection.$query().patchAndFetch({
|
||||
verified: true,
|
||||
draft: false,
|
||||
});
|
||||
|
||||
return {
|
||||
...connection,
|
||||
app,
|
||||
};
|
||||
};
|
||||
|
||||
export default verifyConnection;
|
@@ -1,7 +0,0 @@
|
||||
import mutationResolvers from './mutation-resolvers.js';
|
||||
|
||||
const resolvers = {
|
||||
Mutation: mutationResolvers,
|
||||
};
|
||||
|
||||
export default resolvers;
|
@@ -1,382 +0,0 @@
|
||||
type Query {
|
||||
placeholderQuery(name: String): Boolean
|
||||
}
|
||||
type Mutation {
|
||||
createConnection(input: CreateConnectionInput): Connection
|
||||
executeFlow(input: ExecuteFlowInput): executeFlowType
|
||||
generateAuthUrl(input: GenerateAuthUrlInput): AuthLink
|
||||
resetConnection(input: ResetConnectionInput): Connection
|
||||
updateConnection(input: UpdateConnectionInput): Connection
|
||||
updateCurrentUser(input: UpdateCurrentUserInput): User
|
||||
verifyConnection(input: VerifyConnectionInput): Connection
|
||||
}
|
||||
|
||||
"""
|
||||
Exposes a URL that specifies the behaviour of this scalar.
|
||||
"""
|
||||
directive @specifiedBy(
|
||||
"""
|
||||
The URL that specifies the behaviour of this scalar.
|
||||
"""
|
||||
url: String!
|
||||
) on SCALAR
|
||||
|
||||
type Trigger {
|
||||
name: String
|
||||
key: String
|
||||
description: String
|
||||
showWebhookUrl: Boolean
|
||||
pollInterval: Int
|
||||
type: String
|
||||
substeps: [Substep]
|
||||
}
|
||||
|
||||
type Action {
|
||||
name: String
|
||||
key: String
|
||||
description: String
|
||||
substeps: [Substep]
|
||||
}
|
||||
|
||||
type Substep {
|
||||
key: String
|
||||
name: String
|
||||
arguments: [SubstepArgument]
|
||||
}
|
||||
|
||||
type SubstepArgument {
|
||||
label: String
|
||||
key: String
|
||||
type: String
|
||||
description: String
|
||||
required: Boolean
|
||||
variables: Boolean
|
||||
options: [SubstepArgumentOption]
|
||||
source: SubstepArgumentSource
|
||||
additionalFields: SubstepArgumentAdditionalFields
|
||||
dependsOn: [String]
|
||||
fields: [SubstepArgument]
|
||||
value: JSONObject
|
||||
}
|
||||
|
||||
type SubstepArgumentOption {
|
||||
label: String
|
||||
value: JSONObject
|
||||
}
|
||||
|
||||
type SubstepArgumentSource {
|
||||
type: String
|
||||
name: String
|
||||
arguments: [SubstepArgumentSourceArgument]
|
||||
}
|
||||
|
||||
type SubstepArgumentSourceArgument {
|
||||
name: String
|
||||
value: String
|
||||
}
|
||||
|
||||
type SubstepArgumentAdditionalFields {
|
||||
type: String
|
||||
name: String
|
||||
arguments: [SubstepArgumentAdditionalFieldsArgument]
|
||||
}
|
||||
|
||||
type SubstepArgumentAdditionalFieldsArgument {
|
||||
name: String
|
||||
value: String
|
||||
}
|
||||
|
||||
type App {
|
||||
name: String
|
||||
key: String
|
||||
connectionCount: Int
|
||||
flowCount: Int
|
||||
iconUrl: String
|
||||
docUrl: String
|
||||
authDocUrl: String
|
||||
primaryColor: String
|
||||
supportsConnections: Boolean
|
||||
auth: AppAuth
|
||||
triggers: [Trigger]
|
||||
actions: [Action]
|
||||
connections: [Connection]
|
||||
}
|
||||
|
||||
type AppAuth {
|
||||
fields: [Field]
|
||||
authenticationSteps: [AuthenticationStep]
|
||||
sharedAuthenticationSteps: [AuthenticationStep]
|
||||
reconnectionSteps: [ReconnectionStep]
|
||||
sharedReconnectionSteps: [ReconnectionStep]
|
||||
}
|
||||
|
||||
enum ArgumentEnumType {
|
||||
integer
|
||||
string
|
||||
}
|
||||
|
||||
type AuthenticationStep {
|
||||
type: String
|
||||
name: String
|
||||
arguments: [AuthenticationStepArgument]
|
||||
}
|
||||
|
||||
type AuthenticationStepArgument {
|
||||
name: String
|
||||
value: String
|
||||
type: ArgumentEnumType
|
||||
properties: [AuthenticationStepProperty]
|
||||
}
|
||||
|
||||
type AuthenticationStepProperty {
|
||||
name: String
|
||||
value: String
|
||||
}
|
||||
|
||||
type AuthLink {
|
||||
url: String
|
||||
}
|
||||
|
||||
type Connection {
|
||||
id: String
|
||||
key: String
|
||||
reconnectable: Boolean
|
||||
appAuthClientId: String
|
||||
formattedData: ConnectionData
|
||||
verified: Boolean
|
||||
app: App
|
||||
createdAt: String
|
||||
flowCount: Int
|
||||
}
|
||||
|
||||
type ConnectionData {
|
||||
screenName: String
|
||||
}
|
||||
|
||||
type executeFlowType {
|
||||
data: JSONObject
|
||||
step: Step
|
||||
}
|
||||
|
||||
type ExecutionStep {
|
||||
id: String
|
||||
executionId: String
|
||||
stepId: String
|
||||
step: Step
|
||||
status: String
|
||||
dataIn: JSONObject
|
||||
dataOut: JSONObject
|
||||
errorDetails: JSONObject
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
}
|
||||
|
||||
type Field {
|
||||
key: String
|
||||
label: String
|
||||
type: String
|
||||
required: Boolean
|
||||
readOnly: Boolean
|
||||
value: String
|
||||
placeholder: String
|
||||
description: String
|
||||
docUrl: String
|
||||
clickToCopy: Boolean
|
||||
options: [SubstepArgumentOption]
|
||||
}
|
||||
|
||||
enum FlowStatus {
|
||||
paused
|
||||
published
|
||||
draft
|
||||
}
|
||||
|
||||
type Flow {
|
||||
id: String
|
||||
name: String
|
||||
active: Boolean
|
||||
steps: [Step]
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
status: FlowStatus
|
||||
}
|
||||
|
||||
type SamlAuthProvidersRoleMapping {
|
||||
id: String
|
||||
samlAuthProviderId: String
|
||||
roleId: String
|
||||
remoteRoleName: String
|
||||
}
|
||||
|
||||
input CreateConnectionInput {
|
||||
key: String!
|
||||
appAuthClientId: String
|
||||
formattedData: JSONObject
|
||||
}
|
||||
|
||||
input GenerateAuthUrlInput {
|
||||
id: String!
|
||||
}
|
||||
|
||||
input UpdateConnectionInput {
|
||||
id: String!
|
||||
formattedData: JSONObject
|
||||
appAuthClientId: String
|
||||
}
|
||||
|
||||
input ResetConnectionInput {
|
||||
id: String!
|
||||
}
|
||||
|
||||
input VerifyConnectionInput {
|
||||
id: String!
|
||||
}
|
||||
|
||||
input ExecuteFlowInput {
|
||||
stepId: String!
|
||||
}
|
||||
|
||||
input UserRoleInput {
|
||||
id: String
|
||||
}
|
||||
|
||||
input UpdateCurrentUserInput {
|
||||
email: String
|
||||
password: String
|
||||
fullName: String
|
||||
}
|
||||
|
||||
"""
|
||||
The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
|
||||
"""
|
||||
scalar JSONObject
|
||||
|
||||
input PreviousStepInput {
|
||||
id: String
|
||||
}
|
||||
|
||||
type ReconnectionStep {
|
||||
type: String
|
||||
name: String
|
||||
arguments: [ReconnectionStepArgument]
|
||||
}
|
||||
|
||||
type ReconnectionStepArgument {
|
||||
name: String
|
||||
value: String
|
||||
type: ArgumentEnumType
|
||||
properties: [ReconnectionStepProperty]
|
||||
}
|
||||
|
||||
type ReconnectionStepProperty {
|
||||
name: String
|
||||
value: String
|
||||
}
|
||||
|
||||
type Step {
|
||||
id: String
|
||||
previousStepId: String
|
||||
key: String
|
||||
appKey: String
|
||||
iconUrl: String
|
||||
webhookUrl: String
|
||||
type: StepEnumType
|
||||
parameters: JSONObject
|
||||
connection: Connection
|
||||
flow: Flow
|
||||
position: Int
|
||||
status: String
|
||||
executionSteps: [ExecutionStep]
|
||||
}
|
||||
|
||||
input StepConnectionInput {
|
||||
id: String
|
||||
}
|
||||
|
||||
enum StepEnumType {
|
||||
trigger
|
||||
action
|
||||
}
|
||||
|
||||
input StepFlowInput {
|
||||
id: String
|
||||
}
|
||||
|
||||
input StepInput {
|
||||
id: String
|
||||
previousStepId: String
|
||||
key: String
|
||||
appKey: String
|
||||
connection: StepConnectionInput
|
||||
flow: StepFlowInput
|
||||
parameters: JSONObject
|
||||
previousStep: PreviousStepInput
|
||||
}
|
||||
|
||||
type User {
|
||||
id: String
|
||||
fullName: String
|
||||
email: String
|
||||
role: Role
|
||||
permissions: [Permission]
|
||||
createdAt: String
|
||||
updatedAt: String
|
||||
}
|
||||
|
||||
type Role {
|
||||
id: String
|
||||
name: String
|
||||
key: String
|
||||
description: String
|
||||
isAdmin: Boolean
|
||||
permissions: [Permission]
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
currentPage: Int!
|
||||
totalPages: Int!
|
||||
}
|
||||
|
||||
type ExecutionStepEdge {
|
||||
node: ExecutionStep
|
||||
}
|
||||
|
||||
type ExecutionStepConnection {
|
||||
edges: [ExecutionStepEdge]
|
||||
pageInfo: PageInfo
|
||||
}
|
||||
|
||||
type License {
|
||||
id: String
|
||||
name: String
|
||||
expireAt: String
|
||||
verified: Boolean
|
||||
}
|
||||
|
||||
type Permission {
|
||||
id: String
|
||||
action: String
|
||||
subject: String
|
||||
conditions: [String]
|
||||
}
|
||||
|
||||
type Action {
|
||||
label: String
|
||||
key: String
|
||||
subjects: [String]
|
||||
}
|
||||
|
||||
type Condition {
|
||||
key: String
|
||||
label: String
|
||||
}
|
||||
|
||||
type Subject {
|
||||
label: String
|
||||
key: String
|
||||
}
|
||||
|
||||
schema {
|
||||
query: Query
|
||||
mutation: Mutation
|
||||
}
|
@@ -27,12 +27,7 @@ const authenticationStepsWithoutAuthUrl = [
|
||||
{
|
||||
type: 'mutation',
|
||||
name: 'verifyConnection',
|
||||
arguments: [
|
||||
{
|
||||
name: 'id',
|
||||
value: '{createConnection.id}',
|
||||
},
|
||||
],
|
||||
arguments: [],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -54,12 +49,7 @@ const authenticationStepsWithAuthUrl = [
|
||||
{
|
||||
type: 'mutation',
|
||||
name: 'generateAuthUrl',
|
||||
arguments: [
|
||||
{
|
||||
name: 'id',
|
||||
value: '{createConnection.id}',
|
||||
},
|
||||
],
|
||||
arguments: [],
|
||||
},
|
||||
{
|
||||
type: 'openWithPopup',
|
||||
@@ -75,10 +65,6 @@ const authenticationStepsWithAuthUrl = [
|
||||
type: 'mutation',
|
||||
name: 'updateConnection',
|
||||
arguments: [
|
||||
{
|
||||
name: 'id',
|
||||
value: '{createConnection.id}',
|
||||
},
|
||||
{
|
||||
name: 'formattedData',
|
||||
value: '{openAuthPopup.all}',
|
||||
@@ -88,12 +74,7 @@ const authenticationStepsWithAuthUrl = [
|
||||
{
|
||||
type: 'mutation',
|
||||
name: 'verifyConnection',
|
||||
arguments: [
|
||||
{
|
||||
name: 'id',
|
||||
value: '{createConnection.id}',
|
||||
},
|
||||
],
|
||||
arguments: [],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -115,12 +96,7 @@ const sharedAuthenticationStepsWithAuthUrl = [
|
||||
{
|
||||
type: 'mutation',
|
||||
name: 'generateAuthUrl',
|
||||
arguments: [
|
||||
{
|
||||
name: 'id',
|
||||
value: '{createConnection.id}',
|
||||
},
|
||||
],
|
||||
arguments: [],
|
||||
},
|
||||
{
|
||||
type: 'openWithPopup',
|
||||
@@ -136,10 +112,6 @@ const sharedAuthenticationStepsWithAuthUrl = [
|
||||
type: 'mutation',
|
||||
name: 'updateConnection',
|
||||
arguments: [
|
||||
{
|
||||
name: 'id',
|
||||
value: '{createConnection.id}',
|
||||
},
|
||||
{
|
||||
name: 'formattedData',
|
||||
value: '{openAuthPopup.all}',
|
||||
@@ -149,12 +121,7 @@ const sharedAuthenticationStepsWithAuthUrl = [
|
||||
{
|
||||
type: 'mutation',
|
||||
name: 'verifyConnection',
|
||||
arguments: [
|
||||
{
|
||||
name: 'id',
|
||||
value: '{createConnection.id}',
|
||||
},
|
||||
],
|
||||
arguments: [],
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -1,54 +1,23 @@
|
||||
import cloneDeep from 'lodash/cloneDeep.js';
|
||||
|
||||
const connectionIdArgument = {
|
||||
name: 'id',
|
||||
value: '{connection.id}',
|
||||
};
|
||||
|
||||
const resetConnectionStep = {
|
||||
type: 'mutation',
|
||||
name: 'resetConnection',
|
||||
arguments: [connectionIdArgument],
|
||||
arguments: [],
|
||||
};
|
||||
|
||||
function replaceCreateConnection(string) {
|
||||
return string.replace('{createConnection.id}', '{connection.id}');
|
||||
}
|
||||
|
||||
function removeAppKeyArgument(args) {
|
||||
return args.filter((argument) => argument.name !== 'key');
|
||||
}
|
||||
|
||||
function addConnectionId(step) {
|
||||
step.arguments = step.arguments.map((argument) => {
|
||||
if (typeof argument.value === 'string') {
|
||||
argument.value = replaceCreateConnection(argument.value);
|
||||
}
|
||||
|
||||
if (argument.properties) {
|
||||
argument.properties = argument.properties.map((property) => {
|
||||
return {
|
||||
name: property.name,
|
||||
value: replaceCreateConnection(property.value),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
return argument;
|
||||
});
|
||||
|
||||
return step;
|
||||
}
|
||||
|
||||
function replaceCreateConnectionsWithUpdate(steps) {
|
||||
const updatedSteps = cloneDeep(steps);
|
||||
return updatedSteps.map((step) => {
|
||||
const updatedStep = addConnectionId(step);
|
||||
const updatedStep = { ...step };
|
||||
|
||||
if (step.name === 'createConnection') {
|
||||
updatedStep.name = 'updateConnection';
|
||||
updatedStep.arguments = removeAppKeyArgument(updatedStep.arguments);
|
||||
updatedStep.arguments.unshift(connectionIdArgument);
|
||||
|
||||
return updatedStep;
|
||||
}
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import { rule, shield } from 'graphql-shield';
|
||||
import User from '../models/user.js';
|
||||
import AccessToken from '../models/access-token.js';
|
||||
|
||||
export const isAuthenticated = async (_parent, _args, req) => {
|
||||
export const isAuthenticated = async (req) => {
|
||||
const token = req.headers['authorization'];
|
||||
|
||||
if (token == null) return false;
|
||||
@@ -41,25 +40,9 @@ export const isAuthenticated = async (_parent, _args, req) => {
|
||||
};
|
||||
|
||||
export const authenticateUser = async (request, response, next) => {
|
||||
if (await isAuthenticated(null, null, request)) {
|
||||
if (await isAuthenticated(request)) {
|
||||
next();
|
||||
} else {
|
||||
return response.status(401).end();
|
||||
}
|
||||
};
|
||||
|
||||
const isAuthenticatedRule = rule()(isAuthenticated);
|
||||
|
||||
export const authenticationRules = {
|
||||
Mutation: {
|
||||
'*': isAuthenticatedRule,
|
||||
},
|
||||
};
|
||||
|
||||
const authenticationOptions = {
|
||||
allowExternalErrors: true,
|
||||
};
|
||||
|
||||
const authentication = shield(authenticationRules, authenticationOptions);
|
||||
|
||||
export default authentication;
|
||||
|
@@ -1,18 +1,17 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { allow } from 'graphql-shield';
|
||||
import { isAuthenticated, authenticationRules } from './authentication.js';
|
||||
import { isAuthenticated } from './authentication.js';
|
||||
import { createUser } from '../../test/factories/user.js';
|
||||
import createAuthTokenByUserId from '../helpers/create-auth-token-by-user-id.js';
|
||||
|
||||
describe('isAuthenticated', () => {
|
||||
it('should return false if no token is provided', async () => {
|
||||
const req = { headers: {} };
|
||||
expect(await isAuthenticated(null, null, req)).toBe(false);
|
||||
expect(await isAuthenticated(req)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if token is invalid', async () => {
|
||||
const req = { headers: { authorization: 'invalidToken' } };
|
||||
expect(await isAuthenticated(null, null, req)).toBe(false);
|
||||
expect(await isAuthenticated(req)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true if token is valid and there is a user', async () => {
|
||||
@@ -20,7 +19,7 @@ describe('isAuthenticated', () => {
|
||||
const token = await createAuthTokenByUserId(user.id);
|
||||
|
||||
const req = { headers: { authorization: token } };
|
||||
expect(await isAuthenticated(null, null, req)).toBe(true);
|
||||
expect(await isAuthenticated(req)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if token is valid and but there is no user', async () => {
|
||||
@@ -29,46 +28,6 @@ describe('isAuthenticated', () => {
|
||||
await user.$query().delete();
|
||||
|
||||
const req = { headers: { authorization: token } };
|
||||
expect(await isAuthenticated(null, null, req)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('authentication rules', () => {
|
||||
const getQueryAndMutationNames = (rules) => {
|
||||
const queries = Object.keys(rules.Query || {});
|
||||
const mutations = Object.keys(rules.Mutation || {});
|
||||
return { queries, mutations };
|
||||
};
|
||||
|
||||
const { queries, mutations } = getQueryAndMutationNames(authenticationRules);
|
||||
|
||||
if (queries.length) {
|
||||
describe('for queries', () => {
|
||||
queries.forEach((query) => {
|
||||
it(`should apply correct rule for query: ${query}`, () => {
|
||||
const ruleApplied = authenticationRules.Query[query];
|
||||
|
||||
if (query === '*') {
|
||||
expect(ruleApplied.func).toBe(isAuthenticated);
|
||||
} else {
|
||||
expect(ruleApplied).toEqual(allow);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('for mutations', () => {
|
||||
mutations.forEach((mutation) => {
|
||||
it(`should apply correct rule for mutation: ${mutation}`, () => {
|
||||
const ruleApplied = authenticationRules.Mutation[mutation];
|
||||
|
||||
if (mutation === '*') {
|
||||
expect(ruleApplied.func).toBe(isAuthenticated);
|
||||
} else {
|
||||
expect(ruleApplied).toBe(allow);
|
||||
}
|
||||
});
|
||||
});
|
||||
expect(await isAuthenticated(req)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@@ -50,7 +50,7 @@ const errorHandler = (error, request, response, next) => {
|
||||
},
|
||||
};
|
||||
|
||||
response.status(200).json(httpErrorPayload);
|
||||
response.status(422).json(httpErrorPayload);
|
||||
}
|
||||
|
||||
if (error instanceof NotAuthorizedError) {
|
||||
|
@@ -1,53 +0,0 @@
|
||||
import path, { join } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { graphqlHTTP } from 'express-graphql';
|
||||
import { loadSchemaSync } from '@graphql-tools/load';
|
||||
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
|
||||
import { addResolversToSchema } from '@graphql-tools/schema';
|
||||
import { applyMiddleware } from 'graphql-middleware';
|
||||
|
||||
import appConfig from '../config/app.js';
|
||||
import logger from './logger.js';
|
||||
import authentication from './authentication.js';
|
||||
import * as Sentry from './sentry.ee.js';
|
||||
import resolvers from '../graphql/resolvers.js';
|
||||
import HttpError from '../errors/http.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const schema = loadSchemaSync(join(__dirname, '../graphql/schema.graphql'), {
|
||||
loaders: [new GraphQLFileLoader()],
|
||||
});
|
||||
|
||||
const schemaWithResolvers = addResolversToSchema({
|
||||
schema,
|
||||
resolvers,
|
||||
});
|
||||
|
||||
const graphQLInstance = graphqlHTTP({
|
||||
schema: applyMiddleware(
|
||||
schemaWithResolvers,
|
||||
authentication.generate(schemaWithResolvers)
|
||||
),
|
||||
graphiql: appConfig.isDev,
|
||||
customFormatErrorFn: (error) => {
|
||||
logger.error(error.path + ' : ' + error.message + '\n' + error.stack);
|
||||
|
||||
if (error.originalError instanceof HttpError) {
|
||||
delete error.originalError.response;
|
||||
}
|
||||
|
||||
Sentry.captureException(error, {
|
||||
tags: { graphql: true },
|
||||
extra: {
|
||||
source: error.source?.body,
|
||||
positions: error.positions,
|
||||
path: error.path,
|
||||
},
|
||||
});
|
||||
|
||||
return error;
|
||||
},
|
||||
});
|
||||
|
||||
export default graphQLInstance;
|
@@ -6,18 +6,8 @@ const stream = {
|
||||
logger.http(message.substring(0, message.lastIndexOf('\n'))),
|
||||
};
|
||||
|
||||
const registerGraphQLToken = () => {
|
||||
morgan.token('graphql-query', (req) => {
|
||||
if (req.body.query) {
|
||||
return `\n GraphQL ${req.body.query}`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
registerGraphQLToken();
|
||||
|
||||
const morganMiddleware = morgan(
|
||||
':method :url :status :res[content-length] - :response-time ms :graphql-query',
|
||||
':method :url :status :res[content-length] - :response-time ms',
|
||||
{ stream }
|
||||
);
|
||||
|
||||
|
@@ -17,7 +17,6 @@ export function init(app) {
|
||||
integrations: [
|
||||
app && new Sentry.Integrations.Http({ tracing: true }),
|
||||
app && new Tracing.Integrations.Express({ app }),
|
||||
app && new Tracing.Integrations.GraphQL(),
|
||||
].filter(Boolean),
|
||||
tracesSampleRate: 1.0,
|
||||
});
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Router } from 'express';
|
||||
import graphQLInstance from '../helpers/graphql-instance.js';
|
||||
import webhooksRouter from './webhooks.js';
|
||||
import paddleRouter from './paddle.ee.js';
|
||||
import healthcheckRouter from './healthcheck.js';
|
||||
@@ -23,7 +22,6 @@ import installationUsersRouter from './api/v1/installation/users.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.use('/graphql', graphQLInstance);
|
||||
router.use('/webhooks', webhooksRouter);
|
||||
router.use('/paddle', paddleRouter);
|
||||
router.use('/healthcheck', healthcheckRouter);
|
||||
|
@@ -8,6 +8,7 @@ export class AuthenticatedPage extends BasePage {
|
||||
super(page);
|
||||
|
||||
this.profileMenuButton = this.page.getByTestId('profile-menu-button');
|
||||
this.logoutMenuItem = this.page.getByTestId('logout-item');
|
||||
this.adminMenuItem = this.page.getByRole('menuitem', { name: 'Admin' });
|
||||
this.userInterfaceDrawerItem = this.page.getByTestId(
|
||||
'user-interface-drawer-link'
|
||||
@@ -18,4 +19,9 @@ export class AuthenticatedPage extends BasePage {
|
||||
this.typographyLogo = this.page.getByTestId('typography-logo');
|
||||
this.customLogo = this.page.getByTestId('custom-logo');
|
||||
}
|
||||
|
||||
async logout() {
|
||||
await this.profileMenuButton.click();
|
||||
await this.logoutMenuItem.click();
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ exports.test = test.extend({
|
||||
userInterfacePage: async ({ page }, use) => {
|
||||
await use(new UserInterfacePage(page));
|
||||
},
|
||||
...adminFixtures
|
||||
...adminFixtures,
|
||||
});
|
||||
|
||||
exports.publicTest = test.extend({
|
||||
@@ -49,21 +49,18 @@ exports.publicTest = test.extend({
|
||||
|
||||
await use(loginPage);
|
||||
},
|
||||
|
||||
acceptInvitationPage: async ({ page }, use) => {
|
||||
const acceptInvitationPage = new AcceptInvitation(page);
|
||||
await use(acceptInvitationPage);
|
||||
},
|
||||
|
||||
adminSetupPage: async ({ page }, use) => {
|
||||
const adminSetupPage = new AdminSetupPage(page);
|
||||
await use(adminSetupPage);
|
||||
},
|
||||
|
||||
adminCreateUserPage: async ({page}, use) => {
|
||||
adminCreateUserPage: async ({ page }, use) => {
|
||||
const adminCreateUserPage = new AdminCreateUserPage(page);
|
||||
await use(adminCreateUserPage);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
expect.extend({
|
||||
|
23
packages/e2e-tests/fixtures/my-profile-page.js
Normal file
23
packages/e2e-tests/fixtures/my-profile-page.js
Normal file
@@ -0,0 +1,23 @@
|
||||
const { AuthenticatedPage } = require('./authenticated-page');
|
||||
|
||||
export class MyProfilePage extends AuthenticatedPage {
|
||||
constructor(page) {
|
||||
super(page);
|
||||
|
||||
this.fullName = this.page.locator('[name="fullName"]');
|
||||
this.email = this.page.locator('[name="email"]');
|
||||
this.currentPassword = this.page.locator('[name="currentPassword"]');
|
||||
this.newPassword = this.page.locator('[name="password"]');
|
||||
this.passwordConfirmation = this.page.locator('[name="confirmPassword"]');
|
||||
this.updateProfileButton = this.page.getByTestId('update-profile-button');
|
||||
this.updatePasswordButton = this.page.getByTestId('update-password-button');
|
||||
this.settingsMenuItem = this.page.getByRole('menuitem', {
|
||||
name: 'Settings',
|
||||
});
|
||||
}
|
||||
|
||||
async navigateTo() {
|
||||
await this.profileMenuButton.click();
|
||||
await this.settingsMenuItem.click();
|
||||
}
|
||||
}
|
187
packages/e2e-tests/tests/my-profile/profile-updates.spec.js
Normal file
187
packages/e2e-tests/tests/my-profile/profile-updates.spec.js
Normal file
@@ -0,0 +1,187 @@
|
||||
const { publicTest, expect } = require('../../fixtures/index');
|
||||
const { AdminUsersPage } = require('../../fixtures/admin/users-page');
|
||||
const { MyProfilePage } = require('../../fixtures/my-profile-page');
|
||||
const { LoginPage } = require('../../fixtures/login-page');
|
||||
|
||||
publicTest.describe('My Profile', () => {
|
||||
let testUser;
|
||||
|
||||
publicTest.beforeEach(
|
||||
async ({ acceptInvitationPage, adminCreateUserPage, loginPage, page }) => {
|
||||
let acceptInvitationLink;
|
||||
|
||||
adminCreateUserPage.seed(
|
||||
Math.ceil(Math.random() * Number.MAX_SAFE_INTEGER)
|
||||
);
|
||||
testUser = adminCreateUserPage.generateUser();
|
||||
|
||||
const adminUsersPage = new AdminUsersPage(page);
|
||||
const myProfilePage = new MyProfilePage(page);
|
||||
|
||||
await publicTest.step('login as Admin', async () => {
|
||||
await loginPage.login();
|
||||
await expect(loginPage.page).toHaveURL('/flows');
|
||||
});
|
||||
|
||||
await publicTest.step('create new user', async () => {
|
||||
await adminUsersPage.navigateTo();
|
||||
await adminUsersPage.createUserButton.click();
|
||||
await adminCreateUserPage.fullNameInput.fill(testUser.fullName);
|
||||
await adminCreateUserPage.emailInput.fill(testUser.email);
|
||||
await adminCreateUserPage.roleInput.click();
|
||||
await adminCreateUserPage.page
|
||||
.getByRole('option', { name: 'Admin' })
|
||||
.click();
|
||||
await adminCreateUserPage.createButton.click();
|
||||
const snackbar = await adminUsersPage.getSnackbarData(
|
||||
'snackbar-create-user-success'
|
||||
);
|
||||
await expect(snackbar.variant).toBe('success');
|
||||
});
|
||||
|
||||
await publicTest.step('copy invitation link', async () => {
|
||||
const invitationMessage =
|
||||
await adminCreateUserPage.acceptInvitationLink;
|
||||
acceptInvitationLink = await invitationMessage.getAttribute('href');
|
||||
});
|
||||
|
||||
await publicTest.step('logout', async () => {
|
||||
await myProfilePage.logout();
|
||||
});
|
||||
|
||||
await publicTest.step('accept invitation', async () => {
|
||||
await page.goto(acceptInvitationLink);
|
||||
await acceptInvitationPage.acceptInvitation(LoginPage.defaultPassword);
|
||||
});
|
||||
|
||||
await publicTest.step('login as new Admin', async () => {
|
||||
await loginPage.login(testUser.email, LoginPage.defaultPassword);
|
||||
await expect(loginPage.loginButton).not.toBeVisible();
|
||||
await expect(page).toHaveURL('/flows');
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
publicTest('user should be able to change own data', async ({ page }) => {
|
||||
const myProfilePage = new MyProfilePage(page);
|
||||
|
||||
await publicTest.step('change own data', async () => {
|
||||
await myProfilePage.navigateTo();
|
||||
|
||||
await myProfilePage.fullName.fill('abecadło');
|
||||
await myProfilePage.email.fill('a' + testUser.email);
|
||||
await myProfilePage.updateProfileButton.click();
|
||||
});
|
||||
|
||||
await publicTest.step('verify changed data', async () => {
|
||||
await expect(myProfilePage.fullName).toHaveValue('abecadło');
|
||||
await expect(myProfilePage.email).toHaveValue('a' + testUser.email);
|
||||
|
||||
await page.reload();
|
||||
|
||||
await expect(myProfilePage.fullName).toHaveValue('abecadło');
|
||||
await expect(myProfilePage.email).toHaveValue('a' + testUser.email);
|
||||
});
|
||||
});
|
||||
|
||||
publicTest(
|
||||
'user should not be able to change email to already existing one',
|
||||
async ({ page }) => {
|
||||
const myProfilePage = new MyProfilePage(page);
|
||||
|
||||
await publicTest.step('change email to existing one', async () => {
|
||||
await myProfilePage.navigateTo();
|
||||
|
||||
await myProfilePage.email.fill(LoginPage.defaultEmail);
|
||||
await myProfilePage.updateProfileButton.click();
|
||||
});
|
||||
|
||||
await publicTest.step('verify error message', async () => {
|
||||
const snackbar = await myProfilePage.getSnackbarData(
|
||||
'snackbar-update-profile-settings-error'
|
||||
);
|
||||
await expect(snackbar.variant).toBe('error');
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
publicTest(
|
||||
'user should be able to change own password',
|
||||
async ({ loginPage, page }) => {
|
||||
const myProfilePage = new MyProfilePage(page);
|
||||
|
||||
await publicTest.step('change own password', async () => {
|
||||
await myProfilePage.navigateTo();
|
||||
|
||||
await myProfilePage.currentPassword.fill(LoginPage.defaultPassword);
|
||||
await myProfilePage.newPassword.fill(
|
||||
LoginPage.defaultPassword + LoginPage.defaultPassword
|
||||
);
|
||||
await myProfilePage.passwordConfirmation.fill(
|
||||
LoginPage.defaultPassword + LoginPage.defaultPassword
|
||||
);
|
||||
await myProfilePage.updatePasswordButton.click();
|
||||
});
|
||||
|
||||
await publicTest.step('logout', async () => {
|
||||
await myProfilePage.logout();
|
||||
});
|
||||
|
||||
await publicTest.step('login with new credentials', async () => {
|
||||
await loginPage.login(
|
||||
testUser.email,
|
||||
LoginPage.defaultPassword + LoginPage.defaultPassword
|
||||
);
|
||||
await expect(loginPage.loginButton).not.toBeVisible();
|
||||
await expect(page).toHaveURL('/flows');
|
||||
});
|
||||
|
||||
await publicTest.step('verify if user is the same', async () => {
|
||||
await myProfilePage.navigateTo();
|
||||
await expect(myProfilePage.email).toHaveValue(testUser.email);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
publicTest(
|
||||
'user should not be able to change own password if current one is incorrect',
|
||||
async ({ loginPage, page }) => {
|
||||
const myProfilePage = new MyProfilePage(page);
|
||||
|
||||
await publicTest.step('change own password', async () => {
|
||||
await myProfilePage.navigateTo();
|
||||
|
||||
await myProfilePage.currentPassword.fill('wrongpassword');
|
||||
await myProfilePage.newPassword.fill(
|
||||
LoginPage.defaultPassword + LoginPage.defaultPassword
|
||||
);
|
||||
await myProfilePage.passwordConfirmation.fill(
|
||||
LoginPage.defaultPassword + LoginPage.defaultPassword
|
||||
);
|
||||
await myProfilePage.updatePasswordButton.click();
|
||||
});
|
||||
|
||||
await publicTest.step('verify error message', async () => {
|
||||
const snackbar = await myProfilePage.getSnackbarData(
|
||||
'snackbar-update-password-error'
|
||||
);
|
||||
await expect(snackbar.variant).toBe('error');
|
||||
});
|
||||
|
||||
await publicTest.step('logout', async () => {
|
||||
await myProfilePage.logout();
|
||||
});
|
||||
|
||||
await publicTest.step('login with old credentials', async () => {
|
||||
await loginPage.login(testUser.email, LoginPage.defaultPassword);
|
||||
await expect(loginPage.loginButton).not.toBeVisible();
|
||||
await expect(page).toHaveURL('/flows');
|
||||
});
|
||||
|
||||
await publicTest.step('verify if user is the same', async () => {
|
||||
await myProfilePage.navigateTo();
|
||||
await expect(myProfilePage.email).toHaveValue(testUser.email);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
@@ -4,7 +4,6 @@
|
||||
"license": "See LICENSE file",
|
||||
"description": "The open source Zapier alternative. Build workflow automation without spending time and money.",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.6.9",
|
||||
"@casl/ability": "^6.5.0",
|
||||
"@casl/react": "^3.1.0",
|
||||
"@dagrejs/dagre": "^1.1.2",
|
||||
@@ -21,7 +20,6 @@
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
"clipboard-copy": "^4.0.1",
|
||||
"compare-versions": "^4.1.3",
|
||||
"graphql": "^15.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^2.3.1",
|
||||
"mui-color-input": "^2.0.0",
|
||||
|
@@ -86,7 +86,6 @@ export default function ResetPasswordForm() {
|
||||
: ''
|
||||
}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label={formatMessage(
|
||||
'acceptInvitationForm.confirmPasswordFieldLabel',
|
||||
@@ -111,7 +110,7 @@ export default function ResetPasswordForm() {
|
||||
|
||||
{acceptInvitation.isError && (
|
||||
<Alert
|
||||
data-test='accept-invitation-form-error'
|
||||
data-test="accept-invitation-form-error"
|
||||
severity="error"
|
||||
sx={{ mt: 1, fontWeight: 500 }}
|
||||
>
|
||||
|
@@ -6,11 +6,11 @@ import Menu from '@mui/material/Menu';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import Can from 'components/Can';
|
||||
import apolloClient from 'graphql/client';
|
||||
import * as URLS from 'config/urls';
|
||||
import useAuthentication from 'hooks/useAuthentication';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import useRevokeAccessToken from 'hooks/useRevokeAccessToken';
|
||||
|
||||
function AccountDropdownMenu(props) {
|
||||
const formatMessage = useFormatMessage();
|
||||
const authentication = useAuthentication();
|
||||
@@ -23,7 +23,6 @@ function AccountDropdownMenu(props) {
|
||||
await revokeAccessTokenMutation.mutateAsync();
|
||||
|
||||
authentication.removeToken();
|
||||
await apolloClient.clearStore();
|
||||
onClose();
|
||||
navigate(URLS.LOGIN);
|
||||
};
|
||||
|
@@ -26,7 +26,8 @@ function AddAppConnection(props) {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const formatMessage = useFormatMessage();
|
||||
const [error, setError] = React.useState(null);
|
||||
const [errorMessage, setErrorMessage] = React.useState(null);
|
||||
const [errorDetails, setErrorDetails] = React.useState(null);
|
||||
const [inProgress, setInProgress] = React.useState(false);
|
||||
const hasConnection = Boolean(connectionId);
|
||||
const useShared = searchParams.get('shared') === 'true';
|
||||
@@ -76,7 +77,8 @@ function AddAppConnection(props) {
|
||||
async (data) => {
|
||||
if (!authenticate) return;
|
||||
setInProgress(true);
|
||||
setError(null);
|
||||
setErrorMessage(null);
|
||||
setErrorDetails(null);
|
||||
try {
|
||||
const response = await authenticate({
|
||||
fields: data,
|
||||
@@ -85,21 +87,19 @@ function AddAppConnection(props) {
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['apps', key, 'connections'],
|
||||
});
|
||||
|
||||
onClose(response);
|
||||
} catch (err) {
|
||||
const error = err;
|
||||
console.log(error);
|
||||
|
||||
if (error.message) {
|
||||
setError(error);
|
||||
} else {
|
||||
setError(error.graphQLErrors?.[0]);
|
||||
}
|
||||
setErrorMessage(error.message);
|
||||
setErrorDetails(error?.response?.data?.errors);
|
||||
} finally {
|
||||
setInProgress(false);
|
||||
}
|
||||
},
|
||||
[authenticate],
|
||||
[authenticate, key, onClose, queryClient],
|
||||
);
|
||||
|
||||
if (useShared)
|
||||
@@ -134,16 +134,16 @@ function AddAppConnection(props) {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
{(errorMessage || errorDetails) && (
|
||||
<Alert
|
||||
data-test="add-connection-error"
|
||||
severity="error"
|
||||
sx={{ mt: 1, fontWeight: 500, wordBreak: 'break-all' }}
|
||||
>
|
||||
{error.message}
|
||||
{error.details && (
|
||||
{!errorDetails && errorMessage}
|
||||
{errorDetails && (
|
||||
<pre style={{ whiteSpace: 'pre-wrap' }}>
|
||||
{JSON.stringify(error.details, null, 2)}
|
||||
{JSON.stringify(errorDetails, null, 2)}
|
||||
</pre>
|
||||
)}
|
||||
</Alert>
|
||||
|
@@ -7,7 +7,6 @@ import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogContentText from '@mui/material/DialogContentText';
|
||||
import DialogTitle from '@mui/material/DialogTitle';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import { ApolloError } from '@apollo/client';
|
||||
|
||||
import { FieldPropType } from 'propTypes/propTypes';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
@@ -89,7 +88,9 @@ function AdminApplicationAuthClientDialog(props) {
|
||||
}
|
||||
|
||||
AdminApplicationAuthClientDialog.propTypes = {
|
||||
error: PropTypes.instanceOf(ApolloError),
|
||||
error: PropTypes.shape({
|
||||
message: PropTypes.string,
|
||||
}),
|
||||
onClose: PropTypes.func.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
loading: PropTypes.bool.isRequired,
|
||||
|
@@ -1,34 +0,0 @@
|
||||
import { ApolloProvider as BaseApolloProvider } from '@apollo/client';
|
||||
import * as React from 'react';
|
||||
|
||||
import { mutateAndGetClient } from 'graphql/client';
|
||||
import useAuthentication from 'hooks/useAuthentication';
|
||||
import useEnqueueSnackbar from 'hooks/useEnqueueSnackbar';
|
||||
|
||||
const ApolloProvider = (props) => {
|
||||
const enqueueSnackbar = useEnqueueSnackbar();
|
||||
const authentication = useAuthentication();
|
||||
|
||||
const onError = React.useCallback(
|
||||
(message) => {
|
||||
enqueueSnackbar(message, {
|
||||
variant: 'error',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-error',
|
||||
},
|
||||
});
|
||||
},
|
||||
[enqueueSnackbar],
|
||||
);
|
||||
|
||||
const client = React.useMemo(() => {
|
||||
return mutateAndGetClient({
|
||||
onError,
|
||||
token: authentication.token,
|
||||
});
|
||||
}, [onError, authentication]);
|
||||
|
||||
return <BaseApolloProvider client={client} {...props} />;
|
||||
};
|
||||
|
||||
export default ApolloProvider;
|
@@ -4,7 +4,6 @@ import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import * as URLS from 'config/urls';
|
||||
import ConfirmationDialog from 'components/ConfirmationDialog';
|
||||
import apolloClient from 'graphql/client';
|
||||
import useAuthentication from 'hooks/useAuthentication';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import useCurrentUser from 'hooks/useCurrentUser';
|
||||
@@ -27,8 +26,6 @@ function DeleteAccountDialog(props) {
|
||||
|
||||
authentication.removeToken();
|
||||
|
||||
await apolloClient.clearStore();
|
||||
|
||||
navigate(URLS.LOGIN);
|
||||
}, [deleteCurrentUser, authentication, navigate]);
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { useEffect, useCallback, createContext, useRef, useState } from 'react';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { FlowPropType } from 'propTypes/propTypes';
|
||||
import ReactFlow, { useNodesState, useEdgesState } from 'reactflow';
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import LoadingButton from '@mui/lab/LoadingButton';
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import * as React from 'react';
|
||||
import { useMutation } from '@apollo/client';
|
||||
import Box from '@mui/material/Box';
|
||||
import Collapse from '@mui/material/Collapse';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
@@ -10,37 +9,19 @@ import LoadingButton from '@mui/lab/LoadingButton';
|
||||
|
||||
import { EditorContext } from 'contexts/Editor';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import { EXECUTE_FLOW } from 'graphql/mutations/execute-flow';
|
||||
import useTestStep from 'hooks/useTestStep';
|
||||
import JSONViewer from 'components/JSONViewer';
|
||||
import WebhookUrlInfo from 'components/WebhookUrlInfo';
|
||||
import FlowSubstepTitle from 'components/FlowSubstepTitle';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { StepPropType, SubstepPropType } from 'propTypes/propTypes';
|
||||
|
||||
function serializeErrors(graphQLErrors) {
|
||||
return graphQLErrors?.map((error) => {
|
||||
try {
|
||||
return {
|
||||
...error,
|
||||
message: (
|
||||
<pre style={{ margin: 0, whiteSpace: 'pre-wrap' }}>
|
||||
{JSON.stringify(JSON.parse(error.message), null, 2)}
|
||||
</pre>
|
||||
),
|
||||
};
|
||||
} catch {
|
||||
return error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function TestSubstep(props) {
|
||||
const {
|
||||
substep,
|
||||
expanded = false,
|
||||
onExpand,
|
||||
onCollapse,
|
||||
onSubmit,
|
||||
onContinue,
|
||||
step,
|
||||
showWebhookUrl = false,
|
||||
@@ -48,15 +29,21 @@ function TestSubstep(props) {
|
||||
} = props;
|
||||
const formatMessage = useFormatMessage();
|
||||
const editorContext = React.useContext(EditorContext);
|
||||
const [executeFlow, { data, error, loading, called, reset }] = useMutation(
|
||||
EXECUTE_FLOW,
|
||||
{
|
||||
context: { autoSnackbar: false },
|
||||
},
|
||||
);
|
||||
const response = data?.executeFlow?.data;
|
||||
const isCompleted = !error && called && !loading;
|
||||
const hasNoOutput = !response && isCompleted;
|
||||
const {
|
||||
mutateAsync: testStep,
|
||||
isPending: isTestStepPending,
|
||||
data,
|
||||
isSuccess: isCompleted,
|
||||
reset,
|
||||
} = useTestStep(step.id);
|
||||
const loading = isTestStepPending;
|
||||
const lastExecutionStep = data?.data.lastExecutionStep;
|
||||
const dataOut = lastExecutionStep?.dataOut;
|
||||
const errorDetails = lastExecutionStep?.errorDetails;
|
||||
const hasError = errorDetails && Object.values(errorDetails).length > 0;
|
||||
const hasNoOutput = !hasError && isCompleted && !dataOut;
|
||||
const hasOutput =
|
||||
!hasError && isCompleted && dataOut && Object.values(dataOut).length > 0;
|
||||
const { name } = substep;
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -75,18 +62,12 @@ function TestSubstep(props) {
|
||||
return;
|
||||
}
|
||||
|
||||
await executeFlow({
|
||||
variables: {
|
||||
input: {
|
||||
stepId: step.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
await testStep();
|
||||
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['flows', flowId],
|
||||
});
|
||||
}, [onSubmit, onContinue, isCompleted, queryClient, flowId]);
|
||||
}, [testStep, onContinue, isCompleted, queryClient, flowId]);
|
||||
|
||||
const onToggle = expanded ? onCollapse : onExpand;
|
||||
|
||||
@@ -102,14 +83,14 @@ function TestSubstep(props) {
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
{!!error?.graphQLErrors?.length && (
|
||||
{hasError && (
|
||||
<Alert
|
||||
severity="error"
|
||||
sx={{ mb: 2, fontWeight: 500, width: '100%' }}
|
||||
>
|
||||
{serializeErrors(error.graphQLErrors).map((error, i) => (
|
||||
<div key={i}>{error.message}</div>
|
||||
))}
|
||||
<pre style={{ margin: 0, whiteSpace: 'pre-wrap' }}>
|
||||
{JSON.stringify(errorDetails, null, 2)}
|
||||
</pre>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
@@ -133,12 +114,12 @@ function TestSubstep(props) {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{response && (
|
||||
{hasOutput && (
|
||||
<Box
|
||||
sx={{ maxHeight: 400, overflowY: 'auto', width: '100%' }}
|
||||
data-test="flow-test-substep-output"
|
||||
>
|
||||
<JSONViewer data={response} />
|
||||
<JSONViewer data={dataOut} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
|
@@ -16,7 +16,6 @@ const computeUrl = (url, backendUrl) => {
|
||||
|
||||
const config = {
|
||||
baseUrl: process.env.REACT_APP_BASE_URL,
|
||||
graphqlUrl: computeUrl('/graphql', backendUrl),
|
||||
restApiUrl: computeUrl('/api', backendUrl),
|
||||
supportEmailAddress: 'support@automatisch.io',
|
||||
};
|
||||
|
@@ -1,42 +0,0 @@
|
||||
import { InMemoryCache } from '@apollo/client';
|
||||
const cache = new InMemoryCache({
|
||||
typePolicies: {
|
||||
App: {
|
||||
keyFields: ['key'],
|
||||
},
|
||||
Mutation: {
|
||||
mutationType: true,
|
||||
fields: {
|
||||
verifyConnection: {
|
||||
merge(existing, verifiedConnection, { readField, cache }) {
|
||||
const appKey = readField('key', verifiedConnection);
|
||||
const appCacheId = cache.identify({
|
||||
__typename: 'App',
|
||||
key: appKey,
|
||||
});
|
||||
cache.modify({
|
||||
id: appCacheId,
|
||||
fields: {
|
||||
connections: (existingConnections) => {
|
||||
const existingConnectionIndex = existingConnections.findIndex(
|
||||
(connection) => {
|
||||
return connection.__ref === verifiedConnection.__ref;
|
||||
}
|
||||
);
|
||||
const connectionExists = existingConnectionIndex !== -1;
|
||||
// newly created and verified connection
|
||||
if (!connectionExists) {
|
||||
return [verifiedConnection, ...existingConnections];
|
||||
}
|
||||
return existingConnections;
|
||||
},
|
||||
},
|
||||
});
|
||||
return verifiedConnection;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
export default cache;
|
@@ -1,31 +0,0 @@
|
||||
import { ApolloClient } from '@apollo/client';
|
||||
|
||||
import cache from './cache';
|
||||
import createLink from './link';
|
||||
import appConfig from 'config/app';
|
||||
|
||||
const client = new ApolloClient({
|
||||
cache,
|
||||
link: createLink({ uri: appConfig.graphqlUrl }),
|
||||
defaultOptions: {
|
||||
watchQuery: {
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function mutateAndGetClient(options) {
|
||||
const { onError, token } = options;
|
||||
|
||||
const link = createLink({
|
||||
uri: appConfig.graphqlUrl,
|
||||
token,
|
||||
onError,
|
||||
});
|
||||
|
||||
client.setLink(link);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
export default client;
|
@@ -1,46 +0,0 @@
|
||||
import { HttpLink, from } from '@apollo/client';
|
||||
import { onError } from '@apollo/client/link/error';
|
||||
import { setItem } from 'helpers/storage';
|
||||
import * as URLS from 'config/urls';
|
||||
const createHttpLink = (options) => {
|
||||
const { uri, token } = options;
|
||||
const headers = {
|
||||
authorization: token,
|
||||
};
|
||||
return new HttpLink({ uri, headers });
|
||||
};
|
||||
const NOT_AUTHORISED = 'Not Authorised!';
|
||||
const createErrorLink = (callback) =>
|
||||
onError(({ graphQLErrors, networkError, operation }) => {
|
||||
const context = operation.getContext();
|
||||
const autoSnackbar = context.autoSnackbar ?? true;
|
||||
if (graphQLErrors)
|
||||
graphQLErrors.forEach(({ message, locations, path }) => {
|
||||
if (autoSnackbar) {
|
||||
callback?.(message);
|
||||
}
|
||||
console.error(
|
||||
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
|
||||
);
|
||||
if (message === NOT_AUTHORISED) {
|
||||
setItem('token', '');
|
||||
if (window.location.pathname !== URLS.LOGIN) {
|
||||
window.location.href = URLS.LOGIN;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (networkError) {
|
||||
if (autoSnackbar) {
|
||||
callback?.(networkError.toString());
|
||||
}
|
||||
console.error(`[Network error]: ${networkError}`);
|
||||
}
|
||||
});
|
||||
|
||||
const noop = () => {};
|
||||
const createLink = (options) => {
|
||||
const { uri, onError = noop, token } = options;
|
||||
const httpOptions = { uri, token };
|
||||
return from([createErrorLink(onError), createHttpLink(httpOptions)]);
|
||||
};
|
||||
export default createLink;
|
@@ -1,13 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const CREATE_CONNECTION = gql`
|
||||
mutation CreateConnection($input: CreateConnectionInput) {
|
||||
createConnection(input: $input) {
|
||||
id
|
||||
key
|
||||
verified
|
||||
formattedData {
|
||||
screenName
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,12 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const EXECUTE_FLOW = gql`
|
||||
mutation ExecuteFlow($input: ExecuteFlowInput) {
|
||||
executeFlow(input: $input) {
|
||||
step {
|
||||
id
|
||||
status
|
||||
}
|
||||
data
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,8 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const GENERATE_AUTH_URL = gql`
|
||||
mutation generateAuthUrl($input: GenerateAuthUrlInput) {
|
||||
generateAuthUrl(input: $input) {
|
||||
url
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,13 +0,0 @@
|
||||
import { CREATE_CONNECTION } from './create-connection';
|
||||
import { UPDATE_CONNECTION } from './update-connection';
|
||||
import { VERIFY_CONNECTION } from './verify-connection';
|
||||
import { RESET_CONNECTION } from './reset-connection';
|
||||
import { GENERATE_AUTH_URL } from './generate-auth-url';
|
||||
const mutations = {
|
||||
createConnection: CREATE_CONNECTION,
|
||||
updateConnection: UPDATE_CONNECTION,
|
||||
verifyConnection: VERIFY_CONNECTION,
|
||||
resetConnection: RESET_CONNECTION,
|
||||
generateAuthUrl: GENERATE_AUTH_URL,
|
||||
};
|
||||
export default mutations;
|
@@ -1,8 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const RESET_CONNECTION = gql`
|
||||
mutation ResetConnection($input: ResetConnectionInput) {
|
||||
resetConnection(input: $input) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,13 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const UPDATE_CONNECTION = gql`
|
||||
mutation UpdateConnection($input: UpdateConnectionInput) {
|
||||
updateConnection(input: $input) {
|
||||
id
|
||||
key
|
||||
verified
|
||||
formattedData {
|
||||
screenName
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,10 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const UPDATE_CURRENT_USER = gql`
|
||||
mutation UpdateCurrentUser($input: UpdateCurrentUserInput) {
|
||||
updateCurrentUser(input: $input) {
|
||||
id
|
||||
fullName
|
||||
email
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,17 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const VERIFY_CONNECTION = gql`
|
||||
mutation VerifyConnection($input: VerifyConnectionInput) {
|
||||
verifyConnection(input: $input) {
|
||||
id
|
||||
key
|
||||
verified
|
||||
formattedData {
|
||||
screenName
|
||||
}
|
||||
createdAt
|
||||
app {
|
||||
key
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,32 +0,0 @@
|
||||
const makeEmptyData = () => {
|
||||
return {
|
||||
edges: [],
|
||||
pageInfo: {
|
||||
currentPage: 1,
|
||||
totalPages: 1,
|
||||
},
|
||||
};
|
||||
};
|
||||
function offsetLimitPagination(keyArgs = false) {
|
||||
return {
|
||||
keyArgs,
|
||||
merge(existing, incoming, { args }) {
|
||||
if (!existing) {
|
||||
existing = makeEmptyData();
|
||||
}
|
||||
if (!incoming || incoming === null) return existing;
|
||||
const existingEdges = existing?.edges || [];
|
||||
const incomingEdges = incoming.edges || [];
|
||||
if (args) {
|
||||
const newEdges = [...existingEdges, ...incomingEdges];
|
||||
return {
|
||||
pageInfo: incoming.pageInfo,
|
||||
edges: newEdges,
|
||||
};
|
||||
} else {
|
||||
return existing;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
export default offsetLimitPagination;
|
@@ -1,69 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export const GET_DYNAMIC_FIELDS = gql`
|
||||
query GetDynamicFields(
|
||||
$stepId: String!
|
||||
$key: String!
|
||||
$parameters: JSONObject
|
||||
) {
|
||||
getDynamicFields(stepId: $stepId, key: $key, parameters: $parameters) {
|
||||
label
|
||||
key
|
||||
type
|
||||
required
|
||||
description
|
||||
variables
|
||||
dependsOn
|
||||
value
|
||||
options {
|
||||
label
|
||||
value
|
||||
}
|
||||
source {
|
||||
type
|
||||
name
|
||||
arguments {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
additionalFields {
|
||||
type
|
||||
name
|
||||
arguments {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
fields {
|
||||
label
|
||||
key
|
||||
type
|
||||
required
|
||||
description
|
||||
variables
|
||||
value
|
||||
dependsOn
|
||||
options {
|
||||
label
|
||||
value
|
||||
}
|
||||
source {
|
||||
type
|
||||
name
|
||||
arguments {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
additionalFields {
|
||||
type
|
||||
name
|
||||
arguments {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
@@ -1,20 +1,3 @@
|
||||
import apolloClient from 'graphql/client';
|
||||
import MUTATIONS from 'graphql/mutations';
|
||||
|
||||
export const processMutation = async (mutationName, variables) => {
|
||||
const mutation = MUTATIONS[mutationName];
|
||||
const mutationResponse = await apolloClient.mutate({
|
||||
mutation,
|
||||
variables: { input: variables },
|
||||
context: {
|
||||
autoSnackbar: false,
|
||||
},
|
||||
});
|
||||
const responseData = mutationResponse.data[mutationName];
|
||||
|
||||
return responseData;
|
||||
};
|
||||
|
||||
const parseUrlSearchParams = (event) => {
|
||||
const searchParams = new URLSearchParams(event.data.payload.search);
|
||||
const hashParams = new URLSearchParams(event.data.payload.hash.substring(1));
|
||||
|
@@ -1,27 +1,35 @@
|
||||
import template from 'lodash/template';
|
||||
const interpolate = /{([\s\S]+?)}/g;
|
||||
|
||||
const computeAuthStepVariables = (variableSchema, aggregatedData) => {
|
||||
const variables = {};
|
||||
|
||||
for (const variable of variableSchema) {
|
||||
if (variable.properties) {
|
||||
variables[variable.name] = computeAuthStepVariables(
|
||||
variable.properties,
|
||||
aggregatedData
|
||||
aggregatedData,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (variable.value) {
|
||||
if (variable.value.endsWith('.all}')) {
|
||||
const key = variable.value.replace('{', '').replace('.all}', '');
|
||||
variables[variable.name] = aggregatedData[key];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const computedVariable = template(variable.value, { interpolate })(
|
||||
aggregatedData
|
||||
aggregatedData,
|
||||
);
|
||||
|
||||
variables[variable.name] = computedVariable;
|
||||
}
|
||||
}
|
||||
|
||||
return variables;
|
||||
};
|
||||
export default computeAuthStepVariables;
|
||||
|
@@ -1,13 +1,18 @@
|
||||
import * as React from 'react';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import {
|
||||
processMutation,
|
||||
processOpenWithPopup,
|
||||
processPopupMessage,
|
||||
} from 'helpers/authenticationSteps';
|
||||
import computeAuthStepVariables from 'helpers/computeAuthStepVariables';
|
||||
import useAppAuth from './useAppAuth';
|
||||
import useFormatMessage from './useFormatMessage';
|
||||
import useAppAuth from './useAppAuth';
|
||||
import useCreateConnection from './useCreateConnection';
|
||||
import useCreateConnectionAuthUrl from './useCreateConnectionAuthUrl';
|
||||
import useUpdateConnection from './useUpdateConnection';
|
||||
import useResetConnection from './useResetConnection';
|
||||
import useVerifyConnection from './useVerifyConnection';
|
||||
|
||||
function getSteps(auth, hasConnection, useShared) {
|
||||
if (hasConnection) {
|
||||
@@ -27,10 +32,16 @@ function getSteps(auth, hasConnection, useShared) {
|
||||
export default function useAuthenticateApp(payload) {
|
||||
const { appKey, appAuthClientId, connectionId, useShared = false } = payload;
|
||||
const { data: auth } = useAppAuth(appKey);
|
||||
const queryClient = useQueryClient();
|
||||
const { mutateAsync: createConnection } = useCreateConnection(appKey);
|
||||
const { mutateAsync: createConnectionAuthUrl } = useCreateConnectionAuthUrl();
|
||||
const { mutateAsync: updateConnection } = useUpdateConnection();
|
||||
const { mutateAsync: resetConnection } = useResetConnection();
|
||||
const [authenticationInProgress, setAuthenticationInProgress] =
|
||||
React.useState(false);
|
||||
const formatMessage = useFormatMessage();
|
||||
const steps = getSteps(auth?.data, !!connectionId, useShared);
|
||||
const { mutateAsync: verifyConnection } = useVerifyConnection();
|
||||
|
||||
const authenticate = React.useMemo(() => {
|
||||
if (!steps?.length) return;
|
||||
@@ -42,9 +53,7 @@ export default function useAuthenticateApp(payload) {
|
||||
const response = {
|
||||
key: appKey,
|
||||
appAuthClientId: appAuthClientId || payload.appAuthClientId,
|
||||
connection: {
|
||||
id: connectionId,
|
||||
},
|
||||
connectionId,
|
||||
fields,
|
||||
};
|
||||
let stepIndex = 0;
|
||||
@@ -65,8 +74,32 @@ export default function useAuthenticateApp(payload) {
|
||||
}
|
||||
|
||||
if (step.type === 'mutation') {
|
||||
const stepResponse = await processMutation(step.name, variables);
|
||||
response[step.name] = stepResponse;
|
||||
if (step.name === 'createConnection') {
|
||||
const stepResponse = await createConnection(variables);
|
||||
response[step.name] = stepResponse.data;
|
||||
response.connectionId = stepResponse.data.id;
|
||||
} else if (step.name === 'generateAuthUrl') {
|
||||
const stepResponse = await createConnectionAuthUrl(
|
||||
response.connectionId,
|
||||
);
|
||||
response[step.name] = stepResponse.data;
|
||||
} else if (step.name === 'updateConnection') {
|
||||
const stepResponse = await updateConnection({
|
||||
...variables,
|
||||
connectionId: response.connectionId,
|
||||
});
|
||||
|
||||
response[step.name] = stepResponse.data;
|
||||
} else if (step.name === 'resetConnection') {
|
||||
const stepResponse = await resetConnection(response.connectionId);
|
||||
|
||||
response[step.name] = stepResponse.data;
|
||||
} else if (step.name === 'verifyConnection') {
|
||||
const stepResponse = await verifyConnection(
|
||||
response.connectionId,
|
||||
);
|
||||
response[step.name] = stepResponse?.data;
|
||||
}
|
||||
} else if (step.type === 'openWithPopup') {
|
||||
const stepResponse = await processPopupMessage(popup);
|
||||
response[step.name] = stepResponse;
|
||||
@@ -74,17 +107,38 @@ export default function useAuthenticateApp(payload) {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
setAuthenticationInProgress(false);
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['apps', appKey, 'connections'],
|
||||
});
|
||||
|
||||
throw err;
|
||||
}
|
||||
stepIndex++;
|
||||
|
||||
if (stepIndex === steps.length) {
|
||||
return response;
|
||||
}
|
||||
setAuthenticationInProgress(false);
|
||||
stepIndex++;
|
||||
}
|
||||
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['apps', appKey, 'connections'],
|
||||
});
|
||||
|
||||
setAuthenticationInProgress(false);
|
||||
|
||||
return response;
|
||||
};
|
||||
}, [steps, appKey, appAuthClientId, connectionId, formatMessage]);
|
||||
}, [
|
||||
steps,
|
||||
appKey,
|
||||
appAuthClientId,
|
||||
connectionId,
|
||||
queryClient,
|
||||
formatMessage,
|
||||
createConnection,
|
||||
createConnectionAuthUrl,
|
||||
updateConnection,
|
||||
resetConnection,
|
||||
verifyConnection,
|
||||
]);
|
||||
|
||||
return {
|
||||
authenticate,
|
||||
|
18
packages/web/src/hooks/useCreateConnection.js
Normal file
18
packages/web/src/hooks/useCreateConnection.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useCreateConnection(appKey) {
|
||||
const query = useMutation({
|
||||
mutationFn: async ({ appAuthClientId, formattedData }) => {
|
||||
const { data } = await api.post(`/v1/apps/${appKey}/connections`, {
|
||||
appAuthClientId,
|
||||
formattedData,
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
17
packages/web/src/hooks/useCreateConnectionAuthUrl.js
Normal file
17
packages/web/src/hooks/useCreateConnectionAuthUrl.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useCreateConnectionAuthUrl() {
|
||||
const query = useMutation({
|
||||
mutationFn: async (connectionId) => {
|
||||
const { data } = await api.post(
|
||||
`/v1/connections/${connectionId}/auth-url`,
|
||||
);
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
15
packages/web/src/hooks/useResetConnection.js
Normal file
15
packages/web/src/hooks/useResetConnection.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useResetConnection() {
|
||||
const query = useMutation({
|
||||
mutationFn: async (connectionId) => {
|
||||
const { data } = await api.post(`/v1/connections/${connectionId}/reset`);
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
14
packages/web/src/hooks/useTestStep.js
Normal file
14
packages/web/src/hooks/useTestStep.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useTestStep(stepId) {
|
||||
const query = useMutation({
|
||||
mutationFn: async () => {
|
||||
const { data } = await api.post(`/v1/steps/${stepId}/test`);
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
18
packages/web/src/hooks/useUpdateConnection.js
Normal file
18
packages/web/src/hooks/useUpdateConnection.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useUpdateConnection() {
|
||||
const query = useMutation({
|
||||
mutationFn: async ({ connectionId, formattedData, appAuthClientId }) => {
|
||||
const { data } = await api.patch(`/v1/connections/${connectionId}`, {
|
||||
formattedData,
|
||||
appAuthClientId,
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
19
packages/web/src/hooks/useUpdateCurrentUser.js
Normal file
19
packages/web/src/hooks/useUpdateCurrentUser.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useUpdateCurrentUser(userId) {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const query = useMutation({
|
||||
mutationFn: async (payload) => {
|
||||
const { data } = await api.patch(`/v1/users/${userId}`, payload);
|
||||
|
||||
return data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['users', 'me'] });
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
14
packages/web/src/hooks/useUpdateCurrentUserPassword.js
Normal file
14
packages/web/src/hooks/useUpdateCurrentUserPassword.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useUpdateCurrentUserPassword(userId) {
|
||||
const query = useMutation({
|
||||
mutationFn: async (payload) => {
|
||||
const { data } = await api.patch(`/v1/users/${userId}/password`, payload);
|
||||
|
||||
return data;
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
24
packages/web/src/hooks/useVerifyConnection.js
Normal file
24
packages/web/src/hooks/useVerifyConnection.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import api from 'helpers/api';
|
||||
|
||||
export default function useVerifyConnection() {
|
||||
const query = useMutation({
|
||||
mutationFn: async (connectionId) => {
|
||||
try {
|
||||
const { data } = await api.post(
|
||||
`/v1/connections/${connectionId}/verify`,
|
||||
);
|
||||
|
||||
return data;
|
||||
} catch (err) {
|
||||
if (err.response.status === 500) {
|
||||
throw new Error('Failed while verifying connection!');
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return query;
|
||||
}
|
@@ -3,7 +3,6 @@ import { Settings } from 'luxon';
|
||||
|
||||
import ThemeProvider from 'components/ThemeProvider';
|
||||
import IntlProvider from 'components/IntlProvider';
|
||||
import ApolloProvider from 'components/ApolloProvider';
|
||||
import SnackbarProvider from 'components/SnackbarProvider';
|
||||
import MetadataProvider from 'components/MetadataProvider';
|
||||
import { AuthenticationProvider } from 'contexts/Authentication';
|
||||
@@ -23,13 +22,11 @@ root.render(
|
||||
<SnackbarProvider>
|
||||
<AuthenticationProvider>
|
||||
<QueryClientProvider>
|
||||
<ApolloProvider>
|
||||
<IntlProvider>
|
||||
<ThemeProvider>
|
||||
<MetadataProvider>{routes}</MetadataProvider>
|
||||
</ThemeProvider>
|
||||
</IntlProvider>
|
||||
</ApolloProvider>
|
||||
<IntlProvider>
|
||||
<ThemeProvider>
|
||||
<MetadataProvider>{routes}</MetadataProvider>
|
||||
</ThemeProvider>
|
||||
</IntlProvider>
|
||||
</QueryClientProvider>
|
||||
</AuthenticationProvider>
|
||||
</SnackbarProvider>
|
||||
|
@@ -102,7 +102,12 @@
|
||||
"profileSettings.fullName": "Full name",
|
||||
"profileSettings.email": "Email",
|
||||
"profileSettings.updateProfile": "Update your profile",
|
||||
"profileSettings.updatePassword": "Update your password",
|
||||
"profileSettings.updatedProfile": "Your profile has been updated.",
|
||||
"profileSettings.updatedPassword": "Your password has been updated.",
|
||||
"profileSettings.updateProfileError": "Something went wrong while updating your profile.",
|
||||
"profileSettings.updatePasswordError": "Something went wrong while updating your password.",
|
||||
"profileSettings.currentPassword": "Current password",
|
||||
"profileSettings.newPassword": "New password",
|
||||
"profileSettings.confirmNewPassword": "Confirm new password",
|
||||
"profileSettings.deleteMyAccount": "Delete my account",
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import { useMutation } from '@apollo/client';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import Alert from '@mui/material/Alert';
|
||||
import AlertTitle from '@mui/material/AlertTitle';
|
||||
@@ -15,19 +14,26 @@ import DeleteAccountDialog from 'components/DeleteAccountDialog/index.ee';
|
||||
import Form from 'components/Form';
|
||||
import PageTitle from 'components/PageTitle';
|
||||
import TextField from 'components/TextField';
|
||||
import { UPDATE_CURRENT_USER } from 'graphql/mutations/update-current-user';
|
||||
import useCurrentUser from 'hooks/useCurrentUser';
|
||||
import useFormatMessage from 'hooks/useFormatMessage';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import useUpdateCurrentUser from 'hooks/useUpdateCurrentUser';
|
||||
import useUpdateCurrentUserPassword from 'hooks/useUpdateCurrentUserPassword';
|
||||
|
||||
const validationSchema = yup
|
||||
const validationSchemaProfile = yup
|
||||
.object({
|
||||
fullName: yup.string().required(),
|
||||
email: yup.string().email().required(),
|
||||
password: yup.string(),
|
||||
fullName: yup.string().required('Full name is required'),
|
||||
email: yup.string().email().required('Email is required'),
|
||||
})
|
||||
.required();
|
||||
|
||||
const validationSchemaPassword = yup
|
||||
.object({
|
||||
currentPassword: yup.string().required('Current password is required'),
|
||||
password: yup.string().required('New password is required'),
|
||||
confirmPassword: yup
|
||||
.string()
|
||||
.oneOf([yup.ref('password')], 'Passwords must match'),
|
||||
.oneOf([yup.ref('password')], 'Passwords must match')
|
||||
.required('Confirm password is required'),
|
||||
})
|
||||
.required();
|
||||
|
||||
@@ -37,6 +43,24 @@ const StyledForm = styled(Form)`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const getErrorMessage = (error) => {
|
||||
const errors = error?.response?.data?.errors || {};
|
||||
const errorMessages = Object.entries(errors)
|
||||
.map(([key, messages]) => {
|
||||
if (Array.isArray(messages) && messages.length) {
|
||||
return `${key} ${messages.join(', ')}`;
|
||||
}
|
||||
if (typeof messages === 'string') {
|
||||
return `${key} ${messages}`;
|
||||
}
|
||||
return '';
|
||||
})
|
||||
.filter((message) => !!message)
|
||||
.join(' ');
|
||||
|
||||
return errorMessages;
|
||||
};
|
||||
|
||||
function ProfileSettings() {
|
||||
const [showDeleteAccountConfirmation, setShowDeleteAccountConfirmation] =
|
||||
React.useState(false);
|
||||
@@ -44,42 +68,65 @@ function ProfileSettings() {
|
||||
const { data } = useCurrentUser();
|
||||
const currentUser = data?.data;
|
||||
const formatMessage = useFormatMessage();
|
||||
const [updateCurrentUser] = useMutation(UPDATE_CURRENT_USER);
|
||||
const queryClient = useQueryClient();
|
||||
const { mutateAsync: updateCurrentUser } = useUpdateCurrentUser(
|
||||
currentUser?.id,
|
||||
);
|
||||
const { mutateAsync: updateCurrentUserPassword } =
|
||||
useUpdateCurrentUserPassword(currentUser?.id);
|
||||
|
||||
const handleProfileSettingsUpdate = async (data) => {
|
||||
const { fullName, password, email } = data;
|
||||
const mutationInput = {
|
||||
fullName,
|
||||
email,
|
||||
};
|
||||
try {
|
||||
const { fullName, email } = data;
|
||||
|
||||
if (password) {
|
||||
mutationInput.password = password;
|
||||
}
|
||||
await updateCurrentUser({ fullName, email });
|
||||
|
||||
await updateCurrentUser({
|
||||
variables: {
|
||||
input: mutationInput,
|
||||
},
|
||||
optimisticResponse: {
|
||||
updateCurrentUser: {
|
||||
__typename: 'User',
|
||||
id: currentUser.id,
|
||||
fullName,
|
||||
email,
|
||||
enqueueSnackbar(formatMessage('profileSettings.updatedProfile'), {
|
||||
variant: 'success',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-update-profile-settings-success',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
enqueueSnackbar(
|
||||
getErrorMessage(error) ||
|
||||
formatMessage('profileSettings.updateProfileError'),
|
||||
{
|
||||
variant: 'error',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-update-profile-settings-error',
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
await queryClient.invalidateQueries({ queryKey: ['users', 'me'] });
|
||||
const handlePasswordUpdate = async (data) => {
|
||||
try {
|
||||
const { password, currentPassword } = data;
|
||||
|
||||
enqueueSnackbar(formatMessage('profileSettings.updatedProfile'), {
|
||||
variant: 'success',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-update-profile-settings-success',
|
||||
},
|
||||
});
|
||||
await updateCurrentUserPassword({
|
||||
currentPassword,
|
||||
password,
|
||||
});
|
||||
|
||||
enqueueSnackbar(formatMessage('profileSettings.updatedPassword'), {
|
||||
variant: 'success',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-update-password-success',
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
enqueueSnackbar(
|
||||
getErrorMessage(error) ||
|
||||
formatMessage('profileSettings.updatePasswordError'),
|
||||
{
|
||||
variant: 'error',
|
||||
SnackbarProps: {
|
||||
'data-test': 'snackbar-update-password-error',
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -93,11 +140,9 @@ function ProfileSettings() {
|
||||
<StyledForm
|
||||
defaultValues={{
|
||||
...currentUser,
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
}}
|
||||
onSubmit={handleProfileSettingsUpdate}
|
||||
resolver={yupResolver(validationSchema)}
|
||||
resolver={yupResolver(validationSchemaProfile)}
|
||||
mode="onChange"
|
||||
sx={{ mb: 2 }}
|
||||
render={({
|
||||
@@ -117,8 +162,8 @@ function ProfileSettings() {
|
||||
margin="dense"
|
||||
error={touchedFields.fullName && !!errors?.fullName}
|
||||
helperText={errors?.fullName?.message || ' '}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
name="email"
|
||||
@@ -126,6 +171,57 @@ function ProfileSettings() {
|
||||
margin="dense"
|
||||
error={touchedFields.email && !!errors?.email}
|
||||
helperText={errors?.email?.message || ' '}
|
||||
required
|
||||
/>
|
||||
<Button
|
||||
variant="contained"
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid || isSubmitting}
|
||||
data-test="update-profile-button"
|
||||
>
|
||||
{formatMessage('profileSettings.updateProfile')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} justifyContent="flex-end" sx={{ pt: 3 }}>
|
||||
<StyledForm
|
||||
defaultValues={{
|
||||
currentPassword: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
}}
|
||||
onSubmit={handlePasswordUpdate}
|
||||
resolver={yupResolver(validationSchemaPassword)}
|
||||
mode="onChange"
|
||||
sx={{ mb: 2 }}
|
||||
render={({
|
||||
formState: {
|
||||
errors,
|
||||
touchedFields,
|
||||
isDirty,
|
||||
isValid,
|
||||
isSubmitting,
|
||||
},
|
||||
}) => (
|
||||
<>
|
||||
<TextField
|
||||
fullWidth
|
||||
name="currentPassword"
|
||||
label={formatMessage('profileSettings.currentPassword')}
|
||||
margin="dense"
|
||||
type="password"
|
||||
error={
|
||||
touchedFields.currentPassword && !!errors?.currentPassword
|
||||
}
|
||||
helperText={
|
||||
(touchedFields.currentPassword &&
|
||||
errors?.currentPassword?.message) ||
|
||||
' '
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextField
|
||||
@@ -138,8 +234,8 @@ function ProfileSettings() {
|
||||
helperText={
|
||||
(touchedFields.password && errors?.password?.message) || ' '
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
name="confirmPassword"
|
||||
@@ -154,14 +250,15 @@ function ProfileSettings() {
|
||||
errors?.confirmPassword?.message) ||
|
||||
' '
|
||||
}
|
||||
required
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="contained"
|
||||
type="submit"
|
||||
disabled={!isDirty || !isValid || isSubmitting}
|
||||
data-test="update-password-button"
|
||||
>
|
||||
{formatMessage('profileSettings.updateProfile')}
|
||||
{formatMessage('profileSettings.updatePassword')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
575
yarn.lock
575
yarn.lock
@@ -134,42 +134,6 @@
|
||||
jsonpointer "^5.0.0"
|
||||
leven "^3.1.0"
|
||||
|
||||
"@apollo/client@^3.6.9":
|
||||
version "3.6.9"
|
||||
resolved "https://registry.npmjs.org/@apollo/client/-/client-3.6.9.tgz"
|
||||
integrity sha512-Y1yu8qa2YeaCUBVuw08x8NHenFi0sw2I3KCu7Kw9mDSu86HmmtHJkCAifKVrN2iPgDTW/BbP3EpSV8/EQCcxZA==
|
||||
dependencies:
|
||||
"@graphql-typed-document-node/core" "^3.1.1"
|
||||
"@wry/context" "^0.6.0"
|
||||
"@wry/equality" "^0.5.0"
|
||||
"@wry/trie" "^0.3.0"
|
||||
graphql-tag "^2.12.6"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
optimism "^0.16.1"
|
||||
prop-types "^15.7.2"
|
||||
symbol-observable "^4.0.0"
|
||||
ts-invariant "^0.10.3"
|
||||
tslib "^2.3.0"
|
||||
zen-observable-ts "^1.2.5"
|
||||
|
||||
"@apollo/client@~3.2.5 || ~3.3.0 || ~3.4.0":
|
||||
version "3.4.17"
|
||||
resolved "https://registry.npmjs.org/@apollo/client/-/client-3.4.17.tgz"
|
||||
integrity sha512-MDt2rwMX1GqodiVEKJqmDmAz8xr0qJmq5PdWeIt0yDaT4GOkKYWZiWkyfhfv3raTk8PyJvbsNG9q2CqmUrlGfg==
|
||||
dependencies:
|
||||
"@graphql-typed-document-node/core" "^3.0.0"
|
||||
"@wry/context" "^0.6.0"
|
||||
"@wry/equality" "^0.5.0"
|
||||
"@wry/trie" "^0.3.0"
|
||||
graphql-tag "^2.12.3"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
optimism "^0.16.1"
|
||||
prop-types "^15.7.2"
|
||||
symbol-observable "^4.0.0"
|
||||
ts-invariant "^0.9.0"
|
||||
tslib "^2.3.0"
|
||||
zen-observable-ts "~1.1.0"
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.8.3":
|
||||
version "7.16.7"
|
||||
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
|
||||
@@ -1320,13 +1284,6 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.10.5":
|
||||
version "7.17.2"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz"
|
||||
integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.17.8":
|
||||
version "7.17.9"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz"
|
||||
@@ -1871,89 +1828,6 @@
|
||||
resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz"
|
||||
integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==
|
||||
|
||||
"@graphql-tools/batch-execute@^8.3.2":
|
||||
version "8.3.2"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.3.2.tgz"
|
||||
integrity sha512-ICWqM+MvEkIPHm18Q0cmkvm134zeQMomBKmTRxyxMNhL/ouz6Nqld52/brSlaHnzA3fczupeRJzZ0YatruGBcQ==
|
||||
dependencies:
|
||||
"@graphql-tools/utils" "^8.6.2"
|
||||
dataloader "2.0.0"
|
||||
tslib "~2.3.0"
|
||||
value-or-promise "1.0.11"
|
||||
|
||||
"@graphql-tools/delegate@^8.5.1":
|
||||
version "8.5.1"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.5.1.tgz"
|
||||
integrity sha512-/YPmVxitt57F8sH50pnfXASzOOjEfaUDkX48eF5q6f16+JBncej2zeu+Zm2c68q8MbIxhPlEGfpd0QZeqTvAxw==
|
||||
dependencies:
|
||||
"@graphql-tools/batch-execute" "^8.3.2"
|
||||
"@graphql-tools/schema" "^8.3.2"
|
||||
"@graphql-tools/utils" "^8.6.2"
|
||||
dataloader "2.0.0"
|
||||
graphql-executor "0.0.18"
|
||||
tslib "~2.3.0"
|
||||
value-or-promise "1.0.11"
|
||||
|
||||
"@graphql-tools/graphql-file-loader@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.3.4.tgz"
|
||||
integrity sha512-Q0/YtDq0APR6syRclsQMNguWKRlchd8nFTOpLhfc7Xeiy21VhEEi4Ik+quRySfb7ubDfJGhiUq4MQW43FhWJvg==
|
||||
dependencies:
|
||||
"@graphql-tools/import" "^6.6.6"
|
||||
"@graphql-tools/utils" "^8.6.2"
|
||||
globby "^11.0.3"
|
||||
tslib "~2.3.0"
|
||||
unixify "^1.0.0"
|
||||
|
||||
"@graphql-tools/import@^6.6.6":
|
||||
version "6.6.6"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/import/-/import-6.6.6.tgz"
|
||||
integrity sha512-a0aVajxqu1MsL8EwavA44Osw20lBOIhq8IM2ZIHFPP62cPAcOB26P+Sq57DHMsSyX5YQ0ab9XPM2o4e1dQhs0w==
|
||||
dependencies:
|
||||
"@graphql-tools/utils" "8.6.2"
|
||||
resolve-from "5.0.0"
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-tools/load@^7.5.2":
|
||||
version "7.5.2"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/load/-/load-7.5.2.tgz"
|
||||
integrity sha512-URPqVP77mYxdZxT895DzrWf2C23S3yC/oAmXD4D4YlxR5eVVH/fxu0aZR78WcEKF331fWSiFwWy9j7BZWvkj7g==
|
||||
dependencies:
|
||||
"@graphql-tools/schema" "8.3.2"
|
||||
"@graphql-tools/utils" "^8.6.2"
|
||||
p-limit "3.1.0"
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-tools/merge@^8.2.3":
|
||||
version "8.2.3"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.3.tgz"
|
||||
integrity sha512-XCSmL6/Xg8259OTWNp69B57CPWiVL69kB7pposFrufG/zaAlI9BS68dgzrxmmSqZV5ZHU4r/6Tbf6fwnEJGiSw==
|
||||
dependencies:
|
||||
"@graphql-tools/utils" "^8.6.2"
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-tools/schema@8.3.2", "@graphql-tools/schema@^8.2.0", "@graphql-tools/schema@^8.3.2":
|
||||
version "8.3.2"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.2.tgz"
|
||||
integrity sha512-77feSmIuHdoxMXRbRyxE8rEziKesd/AcqKV6fmxe7Zt+PgIQITxNDew2XJJg7qFTMNM43W77Ia6njUSBxNOkwg==
|
||||
dependencies:
|
||||
"@graphql-tools/merge" "^8.2.3"
|
||||
"@graphql-tools/utils" "^8.6.2"
|
||||
tslib "~2.3.0"
|
||||
value-or-promise "1.0.11"
|
||||
|
||||
"@graphql-tools/utils@8.6.2", "@graphql-tools/utils@^8.6.2":
|
||||
version "8.6.2"
|
||||
resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.2.tgz"
|
||||
integrity sha512-x1DG0cJgpJtImUlNE780B/dfp8pxvVxOD6UeykFH5rHes26S4kGokbgU8F1IgrJ1vAPm/OVBHtd2kicTsPfwdA==
|
||||
dependencies:
|
||||
tslib "~2.3.0"
|
||||
|
||||
"@graphql-typed-document-node/core@^3.0.0", "@graphql-typed-document-node/core@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.1.1.tgz"
|
||||
integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==
|
||||
|
||||
"@hookform/resolvers@^2.8.8":
|
||||
version "2.8.8"
|
||||
resolved "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.8.tgz"
|
||||
@@ -4538,16 +4412,6 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@types/yup@0.29.11":
|
||||
version "0.29.11"
|
||||
resolved "https://registry.npmjs.org/@types/yup/-/yup-0.29.11.tgz"
|
||||
integrity sha512-9cwk3c87qQKZrT251EDoibiYRILjCmxBvvcb4meofCmx1vdnNcR9gyildy5vOHASpOKMsn42CugxUvcwK5eu1g==
|
||||
|
||||
"@types/zen-observable@0.8.3":
|
||||
version "0.8.3"
|
||||
resolved "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.3.tgz"
|
||||
integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw==
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^5.5.0":
|
||||
version "5.10.0"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.10.0.tgz"
|
||||
@@ -5088,27 +4952,6 @@
|
||||
"@webassemblyjs/ast" "1.11.1"
|
||||
"@xtuc/long" "4.2.2"
|
||||
|
||||
"@wry/context@^0.6.0":
|
||||
version "0.6.1"
|
||||
resolved "https://registry.npmjs.org/@wry/context/-/context-0.6.1.tgz"
|
||||
integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@wry/equality@^0.5.0":
|
||||
version "0.5.2"
|
||||
resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.5.2.tgz"
|
||||
integrity sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@wry/trie@^0.3.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.npmjs.org/@wry/trie/-/trie-0.3.1.tgz"
|
||||
integrity sha512-WwB53ikYudh9pIorgxrkHKrQZcCqNM/Q/bDzZBffEaGUKGuHrRb3zZUT9Sh2qw9yogC7SsdRmQ1ER0pqvd3bfw==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@xmldom/xmldom@0.8.7":
|
||||
version "0.8.7"
|
||||
resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.7.tgz"
|
||||
@@ -5152,7 +4995,7 @@ abbrev@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf"
|
||||
integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==
|
||||
|
||||
accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8:
|
||||
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz"
|
||||
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
|
||||
@@ -5917,21 +5760,21 @@ body-parser@1.19.2:
|
||||
raw-body "2.4.3"
|
||||
type-is "~1.6.18"
|
||||
|
||||
body-parser@1.20.1:
|
||||
version "1.20.1"
|
||||
resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz"
|
||||
integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
|
||||
body-parser@1.20.3:
|
||||
version "1.20.3"
|
||||
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
|
||||
integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
content-type "~1.0.4"
|
||||
content-type "~1.0.5"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.4.24"
|
||||
on-finished "2.4.1"
|
||||
qs "6.11.0"
|
||||
raw-body "2.5.1"
|
||||
qs "6.13.0"
|
||||
raw-body "2.5.2"
|
||||
type-is "~1.6.18"
|
||||
unpipe "1.0.0"
|
||||
|
||||
@@ -6110,11 +5953,6 @@ bytes@3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
|
||||
|
||||
bytes@3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz"
|
||||
integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==
|
||||
|
||||
bytes@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz"
|
||||
@@ -6188,6 +6026,17 @@ call-bind@^1.0.0, call-bind@^1.0.2:
|
||||
function-bind "^1.1.1"
|
||||
get-intrinsic "^1.0.2"
|
||||
|
||||
call-bind@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
|
||||
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
get-intrinsic "^1.2.4"
|
||||
set-function-length "^1.2.1"
|
||||
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
|
||||
@@ -6718,11 +6567,16 @@ content-disposition@0.5.4:
|
||||
dependencies:
|
||||
safe-buffer "5.2.1"
|
||||
|
||||
content-type@1.0.4, content-type@^1.0.4, content-type@~1.0.4:
|
||||
content-type@1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz"
|
||||
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||
|
||||
content-type@~1.0.4, content-type@~1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
|
||||
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
|
||||
|
||||
conventional-changelog-angular@^5.0.12:
|
||||
version "5.0.13"
|
||||
resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz"
|
||||
@@ -6822,10 +6676,10 @@ cookie@0.4.2, cookie@^0.4.1:
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz"
|
||||
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
|
||||
|
||||
cookie@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
cookie@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
||||
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
||||
|
||||
cookiejar@^2.1.4:
|
||||
version "2.1.4"
|
||||
@@ -7248,11 +7102,6 @@ data-urls@^2.0.0:
|
||||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
|
||||
dataloader@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz"
|
||||
integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ==
|
||||
|
||||
dateformat@^3.0.0:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz"
|
||||
@@ -7384,6 +7233,15 @@ defer-to-connect@^1.0.1:
|
||||
resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz"
|
||||
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
|
||||
|
||||
define-data-property@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
|
||||
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
es-errors "^1.3.0"
|
||||
gopd "^1.0.1"
|
||||
|
||||
define-lazy-prop@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz"
|
||||
@@ -7806,6 +7664,11 @@ encodeurl@~1.0.2:
|
||||
resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz"
|
||||
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
|
||||
|
||||
encodeurl@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
|
||||
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
|
||||
|
||||
encoding@^0.1.12, encoding@^0.1.13:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz"
|
||||
@@ -7893,6 +7756,18 @@ es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.19.1:
|
||||
string.prototype.trimstart "^1.0.4"
|
||||
unbox-primitive "^1.0.1"
|
||||
|
||||
es-define-property@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
|
||||
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
|
||||
dependencies:
|
||||
get-intrinsic "^1.2.4"
|
||||
|
||||
es-errors@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
|
||||
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
|
||||
|
||||
es-module-lexer@^0.9.0:
|
||||
version "0.9.3"
|
||||
resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz"
|
||||
@@ -8563,17 +8438,7 @@ express-basic-auth@^1.2.1:
|
||||
dependencies:
|
||||
basic-auth "^2.0.1"
|
||||
|
||||
express-graphql@^0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.npmjs.org/express-graphql/-/express-graphql-0.12.0.tgz"
|
||||
integrity sha512-DwYaJQy0amdy3pgNtiTDuGGM2BLdj+YO2SgbKoLliCfuHv3VVTt7vNG/ZqK2hRYjtYHE2t2KB705EU94mE64zg==
|
||||
dependencies:
|
||||
accepts "^1.3.7"
|
||||
content-type "^1.0.4"
|
||||
http-errors "1.8.0"
|
||||
raw-body "^2.4.1"
|
||||
|
||||
express@4.17.3, express@^4.17.1:
|
||||
express@4.17.3:
|
||||
version "4.17.3"
|
||||
resolved "https://registry.npmjs.org/express/-/express-4.17.3.tgz"
|
||||
integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==
|
||||
@@ -8609,37 +8474,37 @@ express@4.17.3, express@^4.17.1:
|
||||
utils-merge "1.0.1"
|
||||
vary "~1.1.2"
|
||||
|
||||
express@~4.18.2:
|
||||
version "4.18.2"
|
||||
resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz"
|
||||
integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==
|
||||
express@^4.17.1, express@~4.20.0:
|
||||
version "4.20.0"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.20.0.tgz#f1d08e591fcec770c07be4767af8eb9bcfd67c48"
|
||||
integrity sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==
|
||||
dependencies:
|
||||
accepts "~1.3.8"
|
||||
array-flatten "1.1.1"
|
||||
body-parser "1.20.1"
|
||||
body-parser "1.20.3"
|
||||
content-disposition "0.5.4"
|
||||
content-type "~1.0.4"
|
||||
cookie "0.5.0"
|
||||
cookie "0.6.0"
|
||||
cookie-signature "1.0.6"
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
encodeurl "~1.0.2"
|
||||
encodeurl "~2.0.0"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
finalhandler "1.2.0"
|
||||
fresh "0.5.2"
|
||||
http-errors "2.0.0"
|
||||
merge-descriptors "1.0.1"
|
||||
merge-descriptors "1.0.3"
|
||||
methods "~1.1.2"
|
||||
on-finished "2.4.1"
|
||||
parseurl "~1.3.3"
|
||||
path-to-regexp "0.1.7"
|
||||
path-to-regexp "0.1.10"
|
||||
proxy-addr "~2.0.7"
|
||||
qs "6.11.0"
|
||||
range-parser "~1.2.1"
|
||||
safe-buffer "5.2.1"
|
||||
send "0.18.0"
|
||||
serve-static "1.15.0"
|
||||
send "0.19.0"
|
||||
serve-static "1.16.0"
|
||||
setprototypeof "1.2.0"
|
||||
statuses "2.0.1"
|
||||
type-is "~1.6.18"
|
||||
@@ -9037,6 +8902,11 @@ function-bind@^1.1.1:
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
|
||||
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
|
||||
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
|
||||
|
||||
functional-red-black-tree@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
|
||||
@@ -9104,6 +8974,17 @@ get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
|
||||
has "^1.0.3"
|
||||
has-symbols "^1.0.1"
|
||||
|
||||
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
|
||||
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
|
||||
dependencies:
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
has-proto "^1.0.1"
|
||||
has-symbols "^1.0.3"
|
||||
hasown "^2.0.0"
|
||||
|
||||
get-own-enumerable-property-symbols@^3.0.0:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz"
|
||||
@@ -9315,7 +9196,7 @@ globals@^13.6.0, globals@^13.9.0:
|
||||
dependencies:
|
||||
type-fest "^0.20.2"
|
||||
|
||||
globby@^11.0.1, globby@^11.0.2, globby@^11.0.3, globby@^11.0.4, globby@^11.1.0:
|
||||
globby@^11.0.1, globby@^11.0.2, globby@^11.0.4, globby@^11.1.0:
|
||||
version "11.1.0"
|
||||
resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz"
|
||||
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
|
||||
@@ -9332,6 +9213,13 @@ goober@^2.0.33:
|
||||
resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.13.tgz#e3c06d5578486212a76c9eba860cbc3232ff6d7c"
|
||||
integrity sha512-jFj3BQeleOoy7t93E9rZ2de+ScC4lQICLwiAQmKMg9F6roKGaLSHoCDYKkWlSafg138jejvq/mTdvmnwDQgqoQ==
|
||||
|
||||
gopd@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
|
||||
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
|
||||
dependencies:
|
||||
get-intrinsic "^1.1.3"
|
||||
|
||||
got@^9.6.0:
|
||||
version "9.6.0"
|
||||
resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz"
|
||||
@@ -9354,50 +9242,6 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
|
||||
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"
|
||||
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
|
||||
|
||||
graphql-executor@0.0.18:
|
||||
version "0.0.18"
|
||||
resolved "https://registry.npmjs.org/graphql-executor/-/graphql-executor-0.0.18.tgz"
|
||||
integrity sha512-upUSl7tfZCZ5dWG1XkOvpG70Yk3duZKcCoi/uJso4WxJVT6KIrcK4nZ4+2X/hzx46pL8wAukgYHY6iNmocRN+g==
|
||||
|
||||
graphql-middleware@^6.1.15:
|
||||
version "6.1.15"
|
||||
resolved "https://registry.npmjs.org/graphql-middleware/-/graphql-middleware-6.1.15.tgz"
|
||||
integrity sha512-JiLuIM48EE3QLcr79K0VCCHqMt6c23esLlkZv2Nr9a/yHnv6eU9DKV9eXARl+wV9m4LkT9ZCg4cIamIa9vPidQ==
|
||||
dependencies:
|
||||
"@graphql-tools/delegate" "^8.5.1"
|
||||
"@graphql-tools/schema" "^8.3.2"
|
||||
|
||||
graphql-shield@^7.5.0:
|
||||
version "7.5.0"
|
||||
resolved "https://registry.npmjs.org/graphql-shield/-/graphql-shield-7.5.0.tgz"
|
||||
integrity sha512-T1A6OreOe/dHDk/1Qg3AHCrKLmTkDJ3fPFGYpSOmUbYXyDnjubK4J5ab5FjHdKHK5fWQRZNTvA0SrBObYsyfaw==
|
||||
dependencies:
|
||||
"@types/yup" "0.29.11"
|
||||
object-hash "^2.0.3"
|
||||
yup "^0.31.0"
|
||||
|
||||
graphql-tag@^2.12.3, graphql-tag@^2.12.6:
|
||||
version "2.12.6"
|
||||
resolved "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz"
|
||||
integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
graphql-tools@^8.2.0:
|
||||
version "8.2.0"
|
||||
resolved "https://registry.npmjs.org/graphql-tools/-/graphql-tools-8.2.0.tgz"
|
||||
integrity sha512-9axT/0exEzVCk+vMPykOPannlrA4VQNo6nuWgh25IJ5arPf92OKxvjSHAbm7dQIFmcWxE0hVvyD2rWHjDqZCgQ==
|
||||
dependencies:
|
||||
"@graphql-tools/schema" "^8.2.0"
|
||||
tslib "~2.3.0"
|
||||
optionalDependencies:
|
||||
"@apollo/client" "~3.2.5 || ~3.3.0 || ~3.4.0"
|
||||
|
||||
graphql@^15.6.0:
|
||||
version "15.8.0"
|
||||
resolved "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz"
|
||||
integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw==
|
||||
|
||||
gzip-size@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz"
|
||||
@@ -9460,6 +9304,18 @@ has-flag@^4.0.0:
|
||||
resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
|
||||
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||
|
||||
has-property-descriptors@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
|
||||
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
|
||||
dependencies:
|
||||
es-define-property "^1.0.0"
|
||||
|
||||
has-proto@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
|
||||
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
|
||||
|
||||
has-symbols@^1.0.1, has-symbols@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz"
|
||||
@@ -9494,6 +9350,13 @@ has@^1.0.3:
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
hasown@^2.0.0:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
|
||||
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
he@1.2.0, he@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz"
|
||||
@@ -9617,17 +9480,6 @@ http-errors@1.7.3:
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
|
||||
http-errors@1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz"
|
||||
integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==
|
||||
dependencies:
|
||||
depd "~1.1.2"
|
||||
inherits "2.0.4"
|
||||
setprototypeof "1.2.0"
|
||||
statuses ">= 1.5.0 < 2"
|
||||
toidentifier "1.0.0"
|
||||
|
||||
http-errors@1.8.1:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz"
|
||||
@@ -11239,7 +11091,7 @@ locate-path@^6.0.0:
|
||||
dependencies:
|
||||
p-locate "^5.0.0"
|
||||
|
||||
lodash-es@^4.17.11, lodash-es@^4.17.21:
|
||||
lodash-es@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
|
||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||
@@ -11605,6 +11457,11 @@ merge-descriptors@1.0.1:
|
||||
resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz"
|
||||
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
|
||||
|
||||
merge-descriptors@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
|
||||
integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
|
||||
|
||||
merge-stream@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
|
||||
@@ -12244,13 +12101,6 @@ normalize-package-data@^3.0.0, normalize-package-data@^3.0.2:
|
||||
semver "^7.3.4"
|
||||
validate-npm-package-license "^3.0.1"
|
||||
|
||||
normalize-path@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz"
|
||||
integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
|
||||
dependencies:
|
||||
remove-trailing-separator "^1.0.1"
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
|
||||
@@ -12440,7 +12290,7 @@ object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
|
||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
||||
|
||||
object-hash@^2.0.3, object-hash@^2.2.0:
|
||||
object-hash@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz"
|
||||
integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==
|
||||
@@ -12450,6 +12300,11 @@ object-inspect@^1.11.0:
|
||||
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz"
|
||||
integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
|
||||
|
||||
object-inspect@^1.13.1:
|
||||
version "1.13.2"
|
||||
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff"
|
||||
integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==
|
||||
|
||||
object-inspect@^1.9.0:
|
||||
version "1.12.2"
|
||||
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz"
|
||||
@@ -12591,14 +12446,6 @@ open@^8.0.9, open@^8.4.0:
|
||||
is-docker "^2.1.1"
|
||||
is-wsl "^2.2.0"
|
||||
|
||||
optimism@^0.16.1:
|
||||
version "0.16.1"
|
||||
resolved "https://registry.npmjs.org/optimism/-/optimism-0.16.1.tgz"
|
||||
integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg==
|
||||
dependencies:
|
||||
"@wry/context" "^0.6.0"
|
||||
"@wry/trie" "^0.3.0"
|
||||
|
||||
optionator@^0.8.1:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz"
|
||||
@@ -12651,13 +12498,6 @@ p-finally@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz"
|
||||
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
|
||||
|
||||
p-limit@3.1.0, p-limit@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
|
||||
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
|
||||
dependencies:
|
||||
yocto-queue "^0.1.0"
|
||||
|
||||
p-limit@^1.1.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz"
|
||||
@@ -12672,6 +12512,13 @@ p-limit@^2.0.0, p-limit@^2.2.0:
|
||||
dependencies:
|
||||
p-try "^2.0.0"
|
||||
|
||||
p-limit@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
|
||||
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
|
||||
dependencies:
|
||||
yocto-queue "^0.1.0"
|
||||
|
||||
p-limit@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985"
|
||||
@@ -12937,6 +12784,11 @@ path-scurry@^1.10.2:
|
||||
lru-cache "^10.2.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
path-to-regexp@0.1.10:
|
||||
version "0.1.10"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b"
|
||||
integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==
|
||||
|
||||
path-to-regexp@0.1.7:
|
||||
version "0.1.7"
|
||||
resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz"
|
||||
@@ -13939,13 +13791,20 @@ q@^1.1.2, q@^1.5.1:
|
||||
resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz"
|
||||
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
|
||||
|
||||
qs@6.11.0, qs@^6.11.0, qs@^6.9.4:
|
||||
qs@6.11.0:
|
||||
version "6.11.0"
|
||||
resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz"
|
||||
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
|
||||
dependencies:
|
||||
side-channel "^1.0.4"
|
||||
|
||||
qs@6.13.0, qs@^6.11.0, qs@^6.9.4:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
|
||||
integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
|
||||
dependencies:
|
||||
side-channel "^1.0.6"
|
||||
|
||||
qs@6.9.7:
|
||||
version "6.9.7"
|
||||
resolved "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz"
|
||||
@@ -14020,27 +13879,7 @@ raw-body@2.4.3:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
raw-body@2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz"
|
||||
integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
|
||||
dependencies:
|
||||
bytes "3.1.2"
|
||||
http-errors "2.0.0"
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
raw-body@^2.4.1:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz"
|
||||
integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==
|
||||
dependencies:
|
||||
bytes "3.1.1"
|
||||
http-errors "1.8.1"
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
raw-body@^2.5.2:
|
||||
raw-body@2.5.2, raw-body@^2.5.2:
|
||||
version "2.5.2"
|
||||
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
|
||||
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
|
||||
@@ -14565,11 +14404,6 @@ relateurl@^0.2.7:
|
||||
resolved "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz"
|
||||
integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
|
||||
|
||||
remove-trailing-separator@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz"
|
||||
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
|
||||
|
||||
remove-trailing-slash@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmjs.org/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz"
|
||||
@@ -14634,16 +14468,16 @@ resolve-cwd@^3.0.0:
|
||||
dependencies:
|
||||
resolve-from "^5.0.0"
|
||||
|
||||
resolve-from@5.0.0, resolve-from@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz"
|
||||
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
|
||||
|
||||
resolve-from@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
|
||||
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
|
||||
|
||||
resolve-from@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz"
|
||||
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
|
||||
|
||||
resolve-url-loader@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz"
|
||||
@@ -14993,6 +14827,25 @@ send@0.18.0:
|
||||
range-parser "~1.2.1"
|
||||
statuses "2.0.1"
|
||||
|
||||
send@0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
|
||||
integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
|
||||
dependencies:
|
||||
debug "2.6.9"
|
||||
depd "2.0.0"
|
||||
destroy "1.2.0"
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
etag "~1.8.1"
|
||||
fresh "0.5.2"
|
||||
http-errors "2.0.0"
|
||||
mime "1.6.0"
|
||||
ms "2.1.3"
|
||||
on-finished "2.4.1"
|
||||
range-parser "~1.2.1"
|
||||
statuses "2.0.1"
|
||||
|
||||
serialize-javascript@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz"
|
||||
@@ -15030,10 +14883,10 @@ serve-static@1.14.2:
|
||||
parseurl "~1.3.3"
|
||||
send "0.17.2"
|
||||
|
||||
serve-static@1.15.0:
|
||||
version "1.15.0"
|
||||
resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz"
|
||||
integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
|
||||
serve-static@1.16.0:
|
||||
version "1.16.0"
|
||||
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.0.tgz#2bf4ed49f8af311b519c46f272bf6ac3baf38a92"
|
||||
integrity sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==
|
||||
dependencies:
|
||||
encodeurl "~1.0.2"
|
||||
escape-html "~1.0.3"
|
||||
@@ -15045,6 +14898,18 @@ set-blocking@^2.0.0, set-blocking@~2.0.0:
|
||||
resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz"
|
||||
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
|
||||
|
||||
set-function-length@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
|
||||
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
|
||||
dependencies:
|
||||
define-data-property "^1.1.4"
|
||||
es-errors "^1.3.0"
|
||||
function-bind "^1.1.2"
|
||||
get-intrinsic "^1.2.4"
|
||||
gopd "^1.0.1"
|
||||
has-property-descriptors "^1.0.2"
|
||||
|
||||
setprototypeof@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz"
|
||||
@@ -15109,6 +14974,16 @@ side-channel@^1.0.4:
|
||||
get-intrinsic "^1.0.2"
|
||||
object-inspect "^1.9.0"
|
||||
|
||||
side-channel@^1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
|
||||
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
|
||||
dependencies:
|
||||
call-bind "^1.0.7"
|
||||
es-errors "^1.3.0"
|
||||
get-intrinsic "^1.2.4"
|
||||
object-inspect "^1.13.1"
|
||||
|
||||
siginfo@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30"
|
||||
@@ -15842,11 +15717,6 @@ svgo@^2.7.0:
|
||||
picocolors "^1.0.0"
|
||||
stable "^0.1.8"
|
||||
|
||||
symbol-observable@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz"
|
||||
integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==
|
||||
|
||||
symbol-tree@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
|
||||
@@ -16207,20 +16077,6 @@ ts-api-utils@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.2.1.tgz#f716c7e027494629485b21c0df6180f4d08f5e8b"
|
||||
integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==
|
||||
|
||||
ts-invariant@^0.10.3:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz"
|
||||
integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
ts-invariant@^0.9.0:
|
||||
version "0.9.4"
|
||||
resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.9.4.tgz"
|
||||
integrity sha512-63jtX/ZSwnUNi/WhXjnK8kz4cHHpYS60AnmA6ixz17l7E12a5puCWFlNpkne5Rl0J8TBPVHpGjsj4fxs8ObVLQ==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
tsconfig-paths@^3.12.0:
|
||||
version "3.12.0"
|
||||
resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz"
|
||||
@@ -16236,7 +16092,7 @@ tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
|
||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||
|
||||
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@~2.3.0:
|
||||
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz"
|
||||
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
|
||||
@@ -16442,13 +16298,6 @@ universalify@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz"
|
||||
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
|
||||
|
||||
unixify@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz"
|
||||
integrity sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA=
|
||||
dependencies:
|
||||
normalize-path "^2.1.1"
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
|
||||
@@ -16589,11 +16438,6 @@ validate-npm-package-name@^3.0.0:
|
||||
dependencies:
|
||||
builtins "^1.0.3"
|
||||
|
||||
value-or-promise@1.0.11:
|
||||
version "1.0.11"
|
||||
resolved "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz"
|
||||
integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==
|
||||
|
||||
vary@^1, vary@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
|
||||
@@ -17436,17 +17280,6 @@ yocto-queue@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
|
||||
integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
|
||||
|
||||
yup@^0.31.0:
|
||||
version "0.31.1"
|
||||
resolved "https://registry.npmjs.org/yup/-/yup-0.31.1.tgz"
|
||||
integrity sha512-Lf6648jDYOWR75IlWkVfwesPyW6oj+50NpxlKvsQlpPsB8eI+ndI7b4S1VrwbmeV9hIZDu1MzrlIL4W+gK1jPw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.10.5"
|
||||
lodash "^4.17.20"
|
||||
lodash-es "^4.17.11"
|
||||
property-expr "^2.0.4"
|
||||
toposort "^2.0.2"
|
||||
|
||||
yup@^0.32.11:
|
||||
version "0.32.11"
|
||||
resolved "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz"
|
||||
@@ -17460,26 +17293,6 @@ yup@^0.32.11:
|
||||
property-expr "^2.0.4"
|
||||
toposort "^2.0.2"
|
||||
|
||||
zen-observable-ts@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz"
|
||||
integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==
|
||||
dependencies:
|
||||
zen-observable "0.8.15"
|
||||
|
||||
zen-observable-ts@~1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz"
|
||||
integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA==
|
||||
dependencies:
|
||||
"@types/zen-observable" "0.8.3"
|
||||
zen-observable "0.8.15"
|
||||
|
||||
zen-observable@0.8.15:
|
||||
version "0.8.15"
|
||||
resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz"
|
||||
integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
|
||||
|
||||
zustand@^4.4.1:
|
||||
version "4.5.2"
|
||||
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.2.tgz#fddbe7cac1e71d45413b3682cdb47b48034c3848"
|
||||
|
Reference in New Issue
Block a user