Skip to content

Commit 985f26b

Browse files
authored
Merge pull request #3546 from msupply-foundation/release-1.7
Release 1.7
2 parents 835b11b + 3725fa6 commit 985f26b

File tree

781 files changed

+15887
-6089
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

781 files changed

+15887
-6089
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ assignees: ''
1212

1313
## Expected behaviour 🤔
1414

15-
1615
## How to Reproduce 🔨
1716

1817
Steps to reproduce the behaviour:
@@ -24,11 +23,9 @@ Steps to reproduce the behaviour:
2423

2524
## Your environment 🌱
2625
<!-- e.g. 1.2.3 -->
27-
- Version:
28-
- Platform:
29-
- [ ] android (tablet)
30-
- [ ] browser (extra points if you tell us which one)
31-
- [ ] desktop (windows)
32-
- [ ] desktop (macOS)
33-
- [ ] server (windows)
34-
26+
- Version:
27+
- mSupply version:
28+
<!-- e.g. android, browser (extra points if you tell us which one), desktop (windows), desktop (macOS), server (windows) -->
29+
- Platform:
30+
<!-- PostgreSQL or SQLite3 -->
31+
- Database type:

.github/ISSUE_TEMPLATE/refactor.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
---
2+
name: Refactor Suggestion
3+
about: Suggest a refactor
4+
title: ""
5+
labels: "refactor, needs triage"
6+
assignees: ""
7+
---
8+
9+
## The suggestion
10+
11+
<!-- Provide a clear and concise description of the suggested change E.g. "Add a new helper function to avoid the need to create service providers in test cases", "Upgrade diesel version to allow async database access", "Create a rust macro to automatically map Graphql and Service layer enums". -->
12+
13+
## Example use case
14+
15+
<!-- EXAMPLE:
16+
We have a lot of enum mapping code that looks like this:
17+
18+
```rust
19+
impl ActivityLogNodeType {
20+
pub fn from_domain(from: &ActivityLogType) -> ActivityLogNodeType {
21+
use ActivityLogNodeType as to;
22+
use ActivityLogType as from;
23+
24+
match from {
25+
from::UserLoggedIn => to::UserLoggedIn,
26+
from::InvoiceCreated => to::InvoiceCreated,
27+
...
28+
from::SensorLocationChanged => to::SensorLocationChanged,
29+
}
30+
}
31+
32+
```
33+
34+
To avoid needing to update this every time we add a new variant to the `ActivityLogType` enum, we could create a macro that automatically maps the variants of the `ActivityLogType` enum to the variants of the `ActivityLogNodeType` enum. This would allow us to write the above code like this:
35+
36+
```rust
37+
impl ActivityLogNodeType {
38+
map_std_enum!(ActivityLogType, ActivityLogNodeType);
39+
}
40+
```
41+
-->
42+
43+
### Why should we invest time in this?
44+
45+
<!-- Describe the benefits of this change.
46+
Examples:
47+
"This makes it faster and less annoying to add new activity log types, which is a common activity, I estimate that this will save us 1 hour per month."
48+
"This change makes the code easier to test, reducing the risk of introducing bugs in the future."
49+
"This change will make it easier for new developers to understand the codebase, reducing the time it takes to onboard new developers."
50+
"Code will run faster, reducing the time it takes to run our test suite."
51+
-->
52+
53+
### Are there any risks associated with this change?
54+
55+
<!-- highlight any risks the code changes might introduce
56+
Examples:
57+
"The change would involve rewriting our login infrastructure, we'll need extra testing around the login process, and review all our permission mappings"
58+
"This change is low risk, as we expect it's functionality to be covered by existing tests and these tests don't need to change"
59+
"This change might impact frontend code that won't be covered by our existing tests, we'll need to do a full regression test with QA team"
60+
"Introducing async database access might uncover new race conditions or bugs that our test cases don't currently cover"
61+
-->
62+
63+
### How much effort is required?
64+
65+
<!-- Estimate the amount of effort required to implement this change -->
66+
<!--
67+
Examples:
68+
"This change is trivial, it will take less than 1 hour to implement."
69+
"This change is a lot of work potentially weeks of effort, however it will reduce the overall time needed to implement our current task, and will make future tasks easier."
70+
"This change is a lot of work potentially weeks of effort, however once the pattern is established, we can do the refactor piece by piece as we have time available."
71+
-->
72+
73+
### Agreed Solution
74+
75+
<!-- Describe how you expect to do the refactor, this might be updated as the team discusses the approach more fully -->
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
name: Sync labels from linked issue to PR
2+
on:
3+
pull_request_target:
4+
types: [opened, reopened, edited]
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Sync labels
10+
uses: actions/github-script@v7
11+
with:
12+
script: |
13+
core.debug(`where the PR? ${context.repo.repo} ${context.repo.owner} ${context.issue.number}`);
14+
let x = 1
15+
const pullRequestResult = await github.graphql(`
16+
query($owner: String!, $repo: String!, $number: Int!) {
17+
repository(name: $repo, owner: $owner) {
18+
pullRequest(number: $number) {
19+
id
20+
body
21+
labels (first: 100){
22+
nodes {
23+
id
24+
}
25+
}
26+
closingIssuesReferences(first: 1) {
27+
nodes {
28+
labels(first: 100) {
29+
nodes {
30+
id
31+
}
32+
}
33+
milestone {
34+
id
35+
}
36+
}
37+
}
38+
}
39+
}
40+
}
41+
`, {
42+
owner: context.repo.owner,
43+
repo: context.repo.repo,
44+
number: context.issue.number
45+
})
46+
47+
core.debug(pullRequestResult)
48+
49+
const pullRequest = pullRequestResult.repository.pullRequest
50+
51+
let issue = pullRequest.closingIssuesReferences.nodes[0]
52+
53+
if (!issue) {
54+
const regex = new RegExp(/#(\d+)/);
55+
const issueNumber = Number(pullRequest.body.match(regex)[1])
56+
57+
if (!issueNumber) {
58+
throw new Error('No associated issue found for this pull request. Not even in the body!')
59+
}
60+
61+
const issueResult = await github.graphql(`
62+
query ($repo: String!, $owner: String!, $number: Int!) {
63+
repository(name: $repo, owner: $owner) {
64+
issue(number: $number) {
65+
labels(first: 100) {
66+
nodes {
67+
id
68+
}
69+
}
70+
milestone {
71+
id
72+
}
73+
}
74+
}
75+
}
76+
`, {
77+
owner: context.repo.owner,
78+
repo: context.repo.repo,
79+
number: issueNumber
80+
})
81+
82+
core.debug(issueResult)
83+
issue = issueResult.repository.issue
84+
85+
if (!issue) {
86+
throw new Error('No associated issue found for this pull request. There was a match in the description, but not to an issue: ${issueNumber}')
87+
}
88+
}
89+
90+
core.debug(issue)
91+
92+
core.debug(x++)
93+
const pullRequestId = pullRequest.id
94+
core.debug(x++)
95+
const pullRequestLabelIds = pullRequest.labels.nodes.map(label => label.id)
96+
core.debug(x++)
97+
const issueLabelIds = issue.labels.nodes.map(label => label.id)
98+
core.debug(x++)
99+
const labelIds = issueLabelIds.concat(pullRequestLabelIds)
100+
core.debug(x++)
101+
const milestoneId = issue.milestone && issue.milestone.id // Linked issue might not have a milestone
102+
core.debug(x++)
103+
104+
const mutationResult = await github.graphql(`
105+
mutation($labelIds: [ID!] = "", $pullRequestId: ID!, $milestoneId: ID = "") {
106+
updatePullRequest(
107+
input: {pullRequestId: $pullRequestId, labelIds: $labelIds, milestoneId: $milestoneId}
108+
) {
109+
clientMutationId
110+
# pullRequest {
111+
# labels(first: 100) {
112+
# nodes {
113+
# name
114+
# }
115+
# }
116+
# milestone {
117+
# title
118+
# }
119+
# }
120+
}
121+
}
122+
`, {
123+
pullRequestId,
124+
labelIds,
125+
milestoneId
126+
})

client/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ To see it in action, check out the [demo server](https://demo-open.msupply.org/)
2222

2323
`yarn start` (using demo server as API)
2424

25-
`yarn start-local` (using localhost:8000 as API)
25+
`yarn start-local` (using localhost:8000 as API - ensure you have already gone through the `server` setup instructions)
2626

2727
`cd packages/host && yarn start -- --env API_HOST='http://localhost:8001'` (using custom API url, see [config.ts for more info](./packages/config/src/config.ts))
2828

client/codegen.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
overwrite: true
2-
schema: [ '../server/schema.graphql' ]
2+
schema: ['../server/schema.graphql']
33
generates:
44
./packages/common/src/types/schema.ts:
55
plugins:

client/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
"test": "jest --config ./jest.config.js --maxWorkers=50% --env=jsdom",
2121
"storybook": "storybook dev -p 6006",
2222
"build-storybook": "storybook build",
23-
"generate": "cd ../server && cargo run --bin remote_server_cli -- export-graphql-schema && cd ../client && graphql-codegen --config codegen.yml",
23+
"gql-codegen": "graphql-codegen --config codegen.yml",
24+
"//": "This command runs graphql-codegen twice, as running once is causing import path errors for shared fragments in the generated files (but running twice resolves them??) See issue here: https://github.com/msupply-foundation/open-msupply/issues/2812",
25+
"generate": "cd ../server && cargo run --bin remote_server_cli -- export-graphql-schema && cd ../client && yarn gql-codegen && yarn gql-codegen",
2426
"android:run": "npx cap run android",
2527
"android:build:server": "yarn build && lerna run --scope @openmsupply-client/android build:server --stream",
2628
"android:build:debug": "yarn build && lerna run --scope @openmsupply-client/android build:debug --stream",
@@ -82,8 +84,8 @@
8284
"eslint-config-prettier": "^8.9.0",
8385
"eslint-plugin-jest-dom": "^5.0.1",
8486
"eslint-plugin-react": "^7.27.1",
85-
"eslint-plugin-storybook": "^0.6.11",
8687
"eslint-plugin-react-hooks": "^4.6.0",
88+
"eslint-plugin-storybook": "^0.6.11",
8789
"husky": "^8.0.3",
8890
"i18n-unused": "^0.13.0",
8991
"jest": "^29.6.2",

client/packages/android/app/src/main/java/org/openmsupply/client/FileManager.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,39 @@
77
import android.widget.Toast;
88

99
import java.io.BufferedWriter;
10+
import java.io.InputStream;
11+
import java.io.IOException;
1012
import java.io.OutputStream;
13+
import java.io.BufferedOutputStream;
1114
import java.io.OutputStreamWriter;
15+
import java.io.File;
16+
import java.io.FileInputStream;
17+
import java.util.zip.ZipEntry;
18+
import java.util.zip.ZipOutputStream;
1219

1320
public class FileManager {
1421
private static final int SAVE_FILE_REQUEST = 12321;
22+
private static final int SAVE_DATABASE_REQUEST = 12322;
1523
private Activity activity;
1624
private String content;
25+
private File dbFile;
1726

1827
public FileManager(Activity activity) {
1928
this.activity = activity;
2029
}
2130

31+
public void SaveDatabase(File file) {
32+
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
33+
intent.addCategory(Intent.CATEGORY_OPENABLE);
34+
intent.setType("application/zip");
35+
intent.putExtra(Intent.EXTRA_TITLE, "openmsupply.sqlite.zip");
36+
37+
this.dbFile = file;
38+
39+
activity.startActivityForResult(intent, SAVE_DATABASE_REQUEST);
40+
41+
}
42+
2243
public void Save(String filename, String content) {
2344
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
2445
intent.addCategory(Intent.CATEGORY_OPENABLE);
@@ -47,5 +68,60 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
4768
Toast.makeText(context, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
4869
}
4970
}
71+
72+
if (requestCode == SAVE_DATABASE_REQUEST && resultCode == Activity.RESULT_OK && data != null
73+
&& dbFile != null) {
74+
Uri uri = data.getData();
75+
Context context = activity.getApplicationContext();
76+
77+
// The db file name can be either `omsupply-database` or
78+
// `omsupply-database.sqlite`
79+
// The rust code automatically appends .sqlite to the file name if it doesn't
80+
// already exist but uses the old file name it is is still present.
81+
// We need to repeat the same logic here for older databases that don't have the
82+
// .sqlite extension
83+
84+
if (!dbFile.isFile()) {
85+
dbFile = new File(dbFile + ".sqlite");
86+
}
87+
88+
InputStream inputStream = null;
89+
OutputStream outputStream = null;
90+
ZipOutputStream zipStream = null;
91+
92+
try {
93+
inputStream = new FileInputStream(dbFile);
94+
outputStream = context.getContentResolver().openOutputStream(uri);
95+
zipStream = new ZipOutputStream(outputStream);
96+
97+
ZipEntry entry = new ZipEntry("omsupply-database.sqlite");
98+
zipStream.putNextEntry(entry);
99+
byte[] buffer = new byte[1024];
100+
int length;
101+
while ((length = inputStream.read(buffer)) >= 0) {
102+
zipStream.write(buffer, 0, length);
103+
}
104+
105+
} catch (Exception e) {
106+
Toast.makeText(context, "Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
107+
} finally {
108+
if (inputStream != null) {
109+
try {
110+
inputStream.close();
111+
} catch (IOException e) {
112+
e.printStackTrace();
113+
}
114+
}
115+
if (zipStream != null) {
116+
try {
117+
zipStream.flush();
118+
zipStream.close();
119+
} catch (IOException e) {
120+
e.printStackTrace();
121+
}
122+
}
123+
124+
}
125+
}
50126
}
51127
}

client/packages/android/app/src/main/java/org/openmsupply/client/MainActivity.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.content.Intent;
44
import android.os.Bundle;
55
import com.getcapacitor.BridgeActivity;
6+
import java.io.File;
67

78
public class MainActivity extends BridgeActivity {
89
RemoteServer server = new RemoteServer();
@@ -40,4 +41,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
4041
public void SaveFile(String filename, String content) {
4142
fileManager.Save(filename, content);
4243
}
44+
45+
public void SaveDatabase(File file) {
46+
fileManager.SaveDatabase(file);
47+
}
4348
}

0 commit comments

Comments
 (0)