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

ui: fix hot reloading for docker and bare metal #1057

Merged
merged 3 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
laurenzhonauer marked this conversation as resolved.
Show resolved Hide resolved
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