Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added account setting screens #4119

Merged
merged 18 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func getInvitation(service services.ApplicationService, member entities.MemberIn
func ListInvitations(service services.ApplicationService) gin.HandlerFunc {
return func(c *gin.Context) {
uID := c.MustGet("uid").(string)
invitationState := c.Param("invitation-state")
invitationState := c.Param("invitation_state")
var response []entities.ListInvitationResponse
projects, err := service.ListInvitations(uID, entities.Invitation(invitationState))
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion chaoscenter/authentication/api/routes/project_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func ProjectRouter(router *gin.Engine, service services.ApplicationService) {
router.GET("/get_project_role/:project_id", rest.GetProjectRole(service))
router.GET("/list_projects", rest.GetProjectsByUserID(service))
router.GET("/get_projects_stats", rest.GetProjectStats(service))
router.GET("/list_invitations_with_filters/:invitation-state", rest.ListInvitations(service))
router.GET("/list_invitations_with_filters/:invitation_state", rest.ListInvitations(service))
router.POST("/create_project", rest.CreateProject(service))
router.POST("/send_invitation", rest.SendInvitation(service))
router.POST("/accept_invitation", rest.AcceptInvitation(service))
Expand Down
52 changes: 40 additions & 12 deletions chaoscenter/authentication/pkg/project/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"context"
"errors"
"log"
"strconv"
"time"

"github.com/litmuschaos/litmus/chaoscenter/authentication/pkg/entities"
Expand Down Expand Up @@ -88,6 +87,9 @@
{"$elemMatch", bson.D{
{"user_id", userID},
{"$and", bson.A{
bson.D{{"invitation", bson.D{
{"$ne", entities.PendingInvitation},
}}},
bson.D{{"invitation", bson.D{
{"$ne", entities.DeclinedInvitation},
}}},
Expand Down Expand Up @@ -241,7 +243,7 @@
update = bson.D{
{"$set", bson.D{
{"members.$[elem].invitation", invitation},
{"members.$[elem].joined_at", strconv.FormatInt(time.Now().Unix(), 10)},
{"members.$[elem].joined_at", time.Now().Unix()},
}}}
case entities.ExitedProject:
update = bson.D{
Expand Down Expand Up @@ -276,7 +278,7 @@

// GetAggregateProjects takes a mongo pipeline to retrieve the project details from the database
func (r repository) GetAggregateProjects(pipeline mongo.Pipeline, opts *options.AggregateOptions) (*mongo.Cursor, error) {
results, err := r.Collection.Aggregate(context.TODO(), pipeline, opts)

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -345,6 +347,13 @@
pipeline := mongo.Pipeline{
bson.D{{"$match", filter}},
bson.D{{"$project", bson.D{
{"name", 1},
{"state", 1},
{"created_at", 1},
{"updated_at", 1},
{"created_by", 1},
{"updated_by", 1},
{"is_removed", 1},
{"members", bson.D{
{"$filter", bson.D{
{"input", "$members"},
Expand Down Expand Up @@ -471,17 +480,36 @@
func (r repository) ListInvitations(userID string, invitationState entities.Invitation) ([]*entities.Project, error) {

var pipeline mongo.Pipeline
filter := bson.D{
{"$match", bson.D{
{"members", bson.D{
{"$elemMatch", bson.D{
{"user_id", userID},
{"invitation", bson.D{
{"$eq", invitationState},
var filter bson.D
if invitationState == entities.PendingInvitation {
filter = bson.D{
{"$match", bson.D{
{"members", bson.D{
{"$elemMatch", bson.D{
{"user_id", userID},
{"invitation", bson.D{
{"$eq", invitationState},
}},
}},
}},
}}},
},
}}},
},
}
} else if invitationState == entities.AcceptedInvitation {
filter = bson.D{
{"$match", bson.D{
{"members", bson.D{
{"$elemMatch", bson.D{
{"user_id", userID},
{"role", bson.D{
{"$ne", entities.RoleOwner},
}},
{"invitation", bson.D{
{"$eq", invitationState},
}},
}},
}}},
},
}
}
pipeline = append(pipeline, filter)

Expand Down
970 changes: 970 additions & 0 deletions chaoscenter/graphql/server/go.sum

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions chaoscenter/web/config/oats.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { defineConfig } from '@harnessio/oats-cli';
import reactQueryPlugin from '@harnessio/oats-plugin-react-query';
import { mapKeys, omit } from 'lodash-es';

export default defineConfig({
services: {
auth: {
url: 'https://raw.githubusercontent.com/litmuschaos/litmus/master/mkdocs/docs/auth/v3.0.0/auth-api.json',
SahilKr24 marked this conversation as resolved.
Show resolved Hide resolved
output: 'src/api/auth/index.ts',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
output: 'src/api/auth/index.ts',
output: 'src/api/auth',

transformer(spec) {
return {
...spec,
components: {
...spec.components,
schemas: omit(spec.components?.schemas, ['OauthSettings'])
},
paths: mapKeys(spec.paths, (_val, key) => `/auth${key}`)
SahilKr24 marked this conversation as resolved.
Show resolved Hide resolved
};
},
genOnlyUsed: true,
plugins: [
reactQueryPlugin({
customFetcher: 'services/fetcher',
overrides: {}
})
]
}
}
});
9 changes: 7 additions & 2 deletions chaoscenter/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"test:watch": "yarn test --watch",
"test:coverage": "jest --coverage --colors --maxWorkers=2",
"prepare": "cd ../../ && husky install chaoscenter/web/.husky",
"services": "node scripts/services.mjs",
"strings:check": "node scripts/strings/yamlStringsCheck.js",
"strings:sort": "yaml-sort -i src/strings/strings.en.yaml",
"typecheck": "tsc",
Expand Down Expand Up @@ -59,8 +60,11 @@
"@blueprintjs/select": "3.12.3",
"@harnessio/design-system": "^1.6.0-beta.1",
"@harnessio/icons": "^2.0.0-beta.2",
"@harnessio/oats-cli": "^2.1.0",
"@harnessio/oats-plugin-react-query": "^2.1.0",
"@harnessio/uicore": "^4.0.0-beta.1",
"@popperjs/core": "^2.11.5",
"@tanstack/react-query": "4.20.4",
"@types/d3-array": "^3.0.3",
"@types/react-timeago": "^4.1.3",
"@visx/axis": "^2.10.0",
Expand Down Expand Up @@ -94,6 +98,7 @@
"masonry-layout": "^4.2.2",
"moment": "^2.25.3",
"normalize.css": "^8.0.1",
"prompts": "^2.4.2",
"qs": "^6.9.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand All @@ -106,13 +111,13 @@
"react-table": "^7.1.0",
"react-timeago": "^7.1.0",
"react-to-print": "^2.14.12",
"restful-react": "15.6.0",
"subscriptions-transport-ws": "^0.11.0",
"swr": "^1.3.0",
"uuid": "^8.3.2",
"yaml": "^2.1.0",
"yaml-sort": "^1.2.1",
"yup": "^0.32.11"
"yup": "^0.32.11",
"zx": "^5.3.0"
},
"devDependencies": {
"@apollo/react-testing": "^4.0.0",
Expand Down
27 changes: 27 additions & 0 deletions chaoscenter/web/scripts/services.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import prompts from 'prompts';
import { $ } from 'zx';

(async () => {
const services = ['auth'];

services.sort();

const response = await prompts({
type: 'multiselect',
name: 'services',
message: 'Please select the services you want to generate',
choices: services.map(title => ({ title }))
});

if (!response.services || response.services.length === 0) {
console.log('No services selected. Exiting...');
process.exit(0);
}

for (const index of response.services) {
const service = services[index];
await $`npx oats import --config config/oats.config.ts --service ${service} --clean`;
}

await $`npx prettier --write \"src/services/**/*.{ts,tsx,json,scss}\"`;
})();
20 changes: 20 additions & 0 deletions chaoscenter/web/scripts/swagger-custom-generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { camel } from 'case';

export default ({ componentName, verb, route, description, genericsTypes, paramsInPath, paramsTypes }, basePath) => {
const propsType = type =>
`${type}UsingFetchProps<${genericsTypes}>${paramsInPath.length ? ` & {${paramsTypes}}` : ''}`;

if (verb === 'get') {
return `${description}export const ${camel(componentName)}Promise = (${
paramsInPath.length ? `{${paramsInPath.join(', ')}, ...props}` : 'props'
}: ${propsType(
'Get'
)}, signal?: RequestInit["signal"]) => getUsingFetch<${genericsTypes}>(${basePath}, \`${route}\`, props, signal);\n\n`;
} else {
return `${description}export const ${camel(componentName)}Promise = (${
paramsInPath.length ? `{${paramsInPath.join(', ')}, ...props}` : 'props'
}: ${propsType(
'Mutate'
)}, signal?: RequestInit["signal"]) => mutateUsingFetch<${genericsTypes}>("${verb.toUpperCase()}", ${basePath}, \`${route}\`, props, signal);\n\n`;
}
};
SahilKr24 marked this conversation as resolved.
Show resolved Hide resolved
45 changes: 45 additions & 0 deletions chaoscenter/web/scripts/swagger-transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { existsSync, readFileSync } from 'fs';
SahilKr24 marked this conversation as resolved.
Show resolved Hide resolved
import { join, resolve } from 'path';
import { pick, forIn, has, set } from 'lodash';
import { load } from 'js-yaml';
import stringify from 'fast-json-stable-stringify';

export default inputSchema => {
const argv = process.argv.slice(2);
const config = argv[0];

if (config) {
const overridesFile = join('src/services', config, 'overrides.yaml');
const transformFile = join('src/services', config, 'transform.js');

let paths = inputSchema.paths;

if (existsSync(overridesFile)) {
const data = readFileSync(overridesFile, 'utf8');
const { allowpaths, operationIdOverrides } = load(data);

if (!allowpaths.includes('*')) {
paths = pick(paths, ...allowpaths);
}

forIn(operationIdOverrides, (value, key) => {
const [path, method] = key.split('.');

if (path && method && has(paths, path) && has(paths[path], method)) {
set(paths, [path, method, 'operationId'], value);
}
});
}

inputSchema.paths = paths;

if (existsSync(transformFile)) {
const transform = require(resolve(process.cwd(), transformFile));

inputSchema = transform(inputSchema);
}
}

// stringify and parse json to get a stable object
return JSON.parse(stringify(inputSchema));
};
76 changes: 24 additions & 52 deletions chaoscenter/web/src/api/LitmusAPIProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import axios from 'axios';
import {
ApolloClient,
ApolloLink,
Expand All @@ -8,17 +7,13 @@ import {
HttpLink,
InMemoryCache,
NormalizedCacheObject,
Operation,
RequestHandler,
split
RequestHandler
} from '@apollo/client';
import { WebSocketLink } from '@apollo/client/link/ws';
import { getMainDefinition } from '@apollo/client/utilities';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

export interface APIConfig {
gqlEndpoints: {
chaosManagerUri: string;
sockURL: string;
};
restEndpoints: {
authUri: string;
Expand All @@ -38,27 +33,13 @@ function createApolloClient({
if (!config.gqlEndpoints) return undefined;

const httpLinkUri = config.gqlEndpoints.chaosManagerUri;
const wsLinkUri = config.gqlEndpoints.sockURL;

if (!httpLinkUri && !wsLinkUri) return undefined;
if (!httpLinkUri) return undefined;

let httpLink: HttpLink | null = null;
if (httpLinkUri) {
httpLink = new HttpLink({
uri: httpLinkUri
});
}

let wsLink: WebSocketLink | null = null;
if (wsLinkUri) {
wsLink = new WebSocketLink({
uri: wsLinkUri,
options: {
reconnect: true,
timeout: 30000
}
});
}
httpLink = new HttpLink({
uri: httpLinkUri
});

const authLink = new ApolloLink((operation, forward) => {
// add the authorization to the headers
Expand All @@ -73,26 +54,7 @@ function createApolloClient({
});

const links: (ApolloLink | RequestHandler)[] = [authLink];

// The split function takes three parameters:
//
// * A function that's called for each operation to execute
// * The Link to use for an operation if the function returns a "truthy" value
// * The Link to use for an operation if the function returns a "falsy" value
const splitOperation = ({ query }: Operation): boolean => {
const definition = getMainDefinition(query);
return definition.kind === 'OperationDefinition' && definition.operation === 'subscription';
};

if (httpLink && !wsLink) {
links.push(httpLink);
} else if (!httpLink && wsLink) {
const splitLink = split(splitOperation, wsLink);
links.push(splitLink);
} else if (httpLink && wsLink) {
const splitLink = split(splitOperation, wsLink, httpLink);
links.push(splitLink);
}
links.push(httpLink);

const client = new ApolloClient({
link: from(links),
Expand All @@ -107,13 +69,23 @@ export const LitmusAPIProvider: React.FC<LitmusAPIProviderProps> = ({
token,
children
}): React.ReactElement => {
if (config.restEndpoints) {
axios.defaults.baseURL = config.restEndpoints.authUri;
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
}

// const scope = getScope();
const apolloClient = createApolloClient({ config, token });
const reactQueryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false
},
mutations: {
retry: false
}
}
});

return apolloClient ? <ApolloProvider client={apolloClient}>{children}</ApolloProvider> : <></>;
return apolloClient ? (
<QueryClientProvider client={reactQueryClient}>
<ApolloProvider client={apolloClient}>{children}</ApolloProvider>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apollo client check should wrap this

</QueryClientProvider>
) : (
<></>
);
SahilKr24 marked this conversation as resolved.
Show resolved Hide resolved
};
Loading
Loading