Skip to content

Commit

Permalink
Merge pull request #1057 from openkfw/fix-frontent-hot-reloading
Browse files Browse the repository at this point in the history
ui: fix hot reloading for docker and bare metal
  • Loading branch information
daniel-arnauer committed Mar 30, 2022
2 parents 9e1a6d7 + ca01236 commit b180002
Show file tree
Hide file tree
Showing 21 changed files with 4,320 additions and 4,780 deletions.
8,962 changes: 4,244 additions & 4,718 deletions api/package-lock.json

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"fastify-swagger": "^4.12.4",
"joi": "^14.3.1",
"jsonwebtoken": "^8.5.0",
"lodash": "^4.17.21",
"lodash.isequal": "^4.5.0",
"module-alias": "^2.2.2",
"raw-body": "^2.3.3",
Expand All @@ -100,8 +101,8 @@
"@types/pino": "^6.3.11",
"@types/uuid": "^3.4.3",
"@types/verror": "^1.10.3",
"@typescript-eslint/eslint-plugin": "4.28.5",
"@typescript-eslint/parser": "4.28.5",
"@typescript-eslint/eslint-plugin": "5.16.0",
"@typescript-eslint/parser": "5.16.0",
"chai": "^4.1.2",
"colors": "^1.4.0",
"coveralls": "^3.0.3",
Expand All @@ -123,7 +124,7 @@
"ts-node-dev": "^1.1.8",
"tsconfig-paths": "^3.11.0",
"tslint": "*",
"typescript": "^4.0.2"
"typescript": "^4.6.2"
},
"_moduleAliases": {
"lib": "dist/lib"
Expand Down
4 changes: 2 additions & 2 deletions api/src/service/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export class RpcMultichainClient implements MultichainClient {
object: any,
): Promise<TxId> {
const data = objectToHex(object);
return await this.rpcClient.invokePublish(streamId, key, data);
return this.rpcClient.invokePublish(streamId, key, data);
}

public async isValidAddress(address: string): Promise<boolean> {
Expand All @@ -130,7 +130,7 @@ export class RpcMultichainClient implements MultichainClient {
}

public async getInfo(): Promise<any> {
return await this.rpcClient.invoke("getinfo");
return this.rpcClient.invoke("getinfo");
}

public async getValues(
Expand Down
2 changes: 1 addition & 1 deletion api/src/service/RpcClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ export class RpcClient {

public async retrieveItems(streamName: string, start: number, count: number): Promise<Item[]> {
const verbose: boolean = false;
return await this.invoke("liststreamitems", streamName, verbose, count, start);
return this.invoke("liststreamitems", streamName, verbose, count, start);
}

private async convertToReadableItems(items: StreamItem[]): Promise<Result.Type<StreamItem>[]> {
Expand Down
1 change: 1 addition & 0 deletions api/src/service/cache2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ export async function withCache<T>(
await updateCache(ctx, conn);
}

// eslint-disable-next-line @typescript-eslint/return-await
return transaction(cacheInstance);
} finally {
releaseWriteLock(cache);
Expand Down
2 changes: 1 addition & 1 deletion api/src/service/document_get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export async function getDocuments(
conn: ConnToken,
ctx: Ctx,
): Promise<Result.Type<DocumentUploaded.Document[]>> {
return await Cache.withCache(conn, ctx, async (cache) =>
return Cache.withCache(conn, ctx, async (cache) =>
DocumentGet.getAllDocumentInfos(ctx, {
getDocumentsEvents: async () => {
return cache.getDocumentUploadedEvents();
Expand Down
4 changes: 2 additions & 2 deletions api/src/service/global_permission_grant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export async function grantGlobalPermission(
permission,
{
getGlobalPermissions: async () => getGlobalPermissions(conn, ctx, serviceUser),
isGroup: async (granteeId) => await GroupQuery.groupExists(conn, ctx, serviceUser, granteeId),
getUser: async (userId) => await UserQuery.getUser(conn, ctx, serviceUser, userId),
isGroup: async (granteeId) => GroupQuery.groupExists(conn, ctx, serviceUser, granteeId),
getUser: async (userId) => UserQuery.getUser(conn, ctx, serviceUser, userId),
},
);
if (Result.isErr(result)) return new VError(result, "failed to grant global permission");
Expand Down
4 changes: 2 additions & 2 deletions api/src/service/global_permission_revoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export async function revokeGlobalPermission(
permission,
{
getGlobalPermissions: async () => getGlobalPermissions(conn, ctx, serviceUser),
isGroup: async (revokeeId) => await GroupQuery.groupExists(conn, ctx, serviceUser, revokeeId),
getUser: async (userId) => await UserQuery.getUser(conn, ctx, serviceUser, userId),
isGroup: async (revokeeId) => GroupQuery.groupExists(conn, ctx, serviceUser, revokeeId),
getUser: async (userId) => UserQuery.getUser(conn, ctx, serviceUser, userId),
},
);
if (Result.isErr(result)) return new VError(result, "failed to revoke global permission");
Expand Down
15 changes: 6 additions & 9 deletions api/src/service/global_permissions_get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@ export async function getGlobalPermissions(
serviceUser: ServiceUser,
): Promise<Result.Type<GlobalPermissions.GlobalPermissions>> {
logger.debug("Getting Global Permissions");
return Cache.withCache(
conn,
ctx,
async (cache) =>
await GlobalPermissionsGet.getGlobalPermissions(ctx, serviceUser, {
getGlobalPermissionsEvents: async () => {
return cache.getGlobalEvents();
},
}),
return Cache.withCache(conn, ctx, async (cache) =>
GlobalPermissionsGet.getGlobalPermissions(ctx, serviceUser, {
getGlobalPermissionsEvents: async () => {
return cache.getGlobalEvents();
},
}),
);
}
2 changes: 1 addition & 1 deletion api/src/service/notification_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export async function getNotificationsForUser(
): Promise<Result.Type<Notification.Notification[]>> {
logger.debug({ user }, "Getting notifications for user");

return await Cache.withCache(conn, ctx, (cache) =>
return Cache.withCache(conn, ctx, (cache) =>
NotificationList.getUserNotifications(ctx, user, {
getUserNotificationEvents: async (userId: UserRecord.Id) => {
return cache.getNotificationEvents(userId);
Expand Down
2 changes: 1 addition & 1 deletion api/src/service/public_key_get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function getPublicKey(
): Promise<Result.Type<PublicKeyBase64>> {
logger.debug("Getting public key");

return await Cache.withCache(conn, ctx, async (cache) =>
return Cache.withCache(conn, ctx, async (cache) =>
PublicKeyGet.getPublicKey(ctx, organization, {
getPublicKeysEvents: async () => cache.getPublicKeyEvents(),
}),
Expand Down
2 changes: 1 addition & 1 deletion api/src/service/subproject_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function listSubprojects(
const visibleSubprojectsResult = await Cache.withCache(conn, ctx, async (cache) =>
SubprojectList.getAllVisible(ctx, serviceUser, {
getAllSubprojects: async () => {
return await cache.getSubprojects(projectId);
return cache.getSubprojects(projectId);
},
}),
);
Expand Down
35 changes: 13 additions & 22 deletions api/src/service/user_assignments_get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,19 @@ export async function getUserAssignments(
): Promise<Result.Type<UserAssignments.UserAssignments>> {
logger.debug({ req: requestData }, "Get user assignments");

const userAssignmentResult = await Cache.withCache(
conn,
ctx,
async (cache) =>
await UserAssignmentsGet.getUserAssignments(
ctx,
requestData.userId,
issuer,
issuerOrganization,
{
getAllProjects: async () => {
return cache.getProjects();
},
getSubprojects: async (pId) => {
return cache.getSubprojects(pId);
},
getWorkflowitems: async (pId, spId) => {
return cache.getWorkflowitems(pId, spId);
},
getUser: () => UserQuery.getUser(conn, ctx, issuer, requestData.userId),
},
),
const userAssignmentResult = await Cache.withCache(conn, ctx, async (cache) =>
UserAssignmentsGet.getUserAssignments(ctx, requestData.userId, issuer, issuerOrganization, {
getAllProjects: async () => {
return cache.getProjects();
},
getSubprojects: async (pId) => {
return cache.getSubprojects(pId);
},
getWorkflowitems: async (pId, spId) => {
return cache.getWorkflowitems(pId, spId);
},
getUser: () => UserQuery.getUser(conn, ctx, issuer, requestData.userId),
}),
);
return Result.mapErr(
userAssignmentResult,
Expand Down
2 changes: 1 addition & 1 deletion api/src/service/workflowitem_permission_grant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export async function grantWorkflowitemPermission(
intent,
{
getWorkflowitem: async (pId, spId, wId) => {
return await cache.getWorkflowitem(pId, spId, wId);
return cache.getWorkflowitem(pId, spId, wId);
},
userExists: async (user) => UserQuery.userExists(conn, ctx, serviceUser, user),
getUser: async (user) => UserQuery.getUser(conn, ctx, serviceUser, user),
Expand Down
2 changes: 1 addition & 1 deletion api/src/service/workflowitem_permission_revoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export async function revokeWorkflowitemPermission(
intent,
{
getWorkflowitem: async (pId, spId, wId) => {
return await cache.getWorkflowitem(pId, spId, wId);
return cache.getWorkflowitem(pId, spId, wId);
},
},
),
Expand Down
2 changes: 1 addition & 1 deletion api/src/service/workflowitem_permissions_list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export async function listWorkflowitemPermissions(
const permissionsResult = await Cache.withCache(conn, ctx, async (cache) =>
WorkflowitemPermissionsList.getAll(ctx, serviceUser, projectId, subprojectId, workflowitemId, {
getWorkflowitem: async (pId, spId, wId) => {
return await cache.getWorkflowitem(pId, spId, wId);
return cache.getWorkflowitem(pId, spId, wId);
},
}),
);
Expand Down
2 changes: 1 addition & 1 deletion api/src/system/getVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const multichainVersionMetaData = async (

const storageServiceMetaData = async (
storageServiceClient: StorageServiceClient,
): Promise<Version> => await storageServiceClient.getVersion();
): Promise<Version> => storageServiceClient.getVersion();

export const getVersion = async (
multichainHost: string,
Expand Down
18 changes: 6 additions & 12 deletions e2e-test/cypress/integration/documents_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,15 @@ let projectId;
let subprojectId;
let workflowitemId;
let baseUrl, apiRoute;
let isExternalStorageEnabled = false;

// Actual file in fixture folder
const fileName = "documents_test.json";

describe("Attaching a document to a workflowitem.", function () {
describe("Attaching a document to a workflowitem.", function() {
before(() => {
baseUrl = Cypress.env("API_BASE_URL") || `${Cypress.config("baseUrl")}/test`;
apiRoute = baseUrl.toLowerCase().includes("test") ? "/test/api" : "/api";
cy.login();
cy.getVersion().then(data => {
if (data.storage && data.storage.release) {
isExternalStorageEnabled = true;
}
});
cy.createProject("documents test project", "workflowitem documents test", [])
.then(({ id }) => {
projectId = id;
Expand All @@ -34,7 +28,7 @@ describe("Attaching a document to a workflowitem.", function () {
});
});

beforeEach(function () {
beforeEach(function() {
cy.login();
cy.visit(`/projects/${projectId}/${subprojectId}`);
});
Expand All @@ -60,7 +54,7 @@ describe("Attaching a document to a workflowitem.", function () {
return cy.get("[data-test=workflowitemDocumentFileName]").should("contain", fileName);
};

it("A document can be validated.", function () {
it("A document can be validated.", function() {
cy.intercept(apiRoute + "/workflowitem.update*").as("update");
cy.intercept(apiRoute + "/subproject.viewDetails*").as("viewDetails");
cy.intercept(apiRoute + "/workflowitem.validate*").as("validate");
Expand Down Expand Up @@ -97,7 +91,7 @@ describe("Attaching a document to a workflowitem.", function () {
.should("contain", "Identical");
});

it("Validation of wrong document fails.", function () {
it("Validation of wrong document fails.", function() {
cy.intercept(apiRoute + "/workflowitem.update*").as("update");
cy.intercept(apiRoute + "/subproject.viewDetails*").as("viewDetails");
cy.intercept(apiRoute + "/workflowitem.validate*").as("validate");
Expand Down Expand Up @@ -135,7 +129,7 @@ describe("Attaching a document to a workflowitem.", function () {
.should("contain", "Different");
});

it("The filename and document name are shown correctly", function () {
it("The filename and document name are shown correctly", function() {
cy.intercept(apiRoute + "/workflowitem.update*").as("update");
cy.intercept(apiRoute + "/subproject.viewDetails*").as("viewDetails");
cy.intercept(apiRoute + "/workflowitem.validate*").as("validate");
Expand All @@ -161,7 +155,7 @@ describe("Attaching a document to a workflowitem.", function () {
// Check document name
cy.get("[data-test=workflowitemDocumentFileName]")
.should("be.visible")
.first()
.contains(fileName);

});
});
7 changes: 7 additions & 0 deletions frontend/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ FROM node:13.12.0-alpine
ARG API_HOST=localhost
ARG API_PORT=8080

# Try to make sure auto reload is enabled on code change
ARG CHOKIDAR_USEPOLLING=true
ARG CHOKIDAR_INTERVAL=2000

# If you have low performing Hardware, enable this for hot reload without fast refresh:
#ARG FAST_REFRESH=false

# set working directory
WORKDIR /app

Expand Down
22 changes: 22 additions & 0 deletions frontend/hotReloadSetup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copied from https://github.com/facebook/create-react-app/issues/11879
// This is obsolete when this issue has been resolved

const fs = require("fs");
const path = require("path");

if (process.env.NODE_ENV === "development") {
const webPackConfigFile = path.resolve("./node_modules/react-scripts/config/webpack.config.js");
let webPackConfigFileText = fs.readFileSync(webPackConfigFile, "utf8");

if (!webPackConfigFileText.includes("watchOptions")) {
if (webPackConfigFileText.includes("performance: false,")) {
webPackConfigFileText = webPackConfigFileText.replace(
"performance: false,",
"performance: false,\n\t\twatchOptions: { aggregateTimeout: 200, poll: 1000, ignored: '**/node_modules', },"
);
fs.writeFileSync(webPackConfigFile, webPackConfigFileText, "utf8");
} else {
throw new Error(`Failed to inject watchOptions`);
}
}
}
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@
"typescript": "^3.7.2"
},
"scripts": {
"start": "react-app-rewired start | printf '\n\nThe Prod/Test environements will be removed in the next major release of TruBudget. That means /prod/api and /test/api will be routed to /api.\nFor further information see https://github.com/openkfw/TruBudget/pull/971\n\n\n'",
"start": "npm run info && node ./hotReloadSetup && react-app-rewired start",
"info": "printf '\n\nThe Prod/Test environments will be removed in the next major release of TruBudget. That means /prod/api and /test/api will be routed to /api.\nFor further information see https://github.com/openkfw/TruBudget/pull/971\n\n\n'",
"audit": "better-npm-audit audit",
"build": "react-app-rewired build",
"test": "npm run check-translations",
Expand Down

0 comments on commit b180002

Please sign in to comment.