Skip to content

Commit fa12ee6

Browse files
authored
Merge pull request #159 from gitopia/release-v4
Release v4
2 parents 63388a2 + aa6507c commit fa12ee6

16 files changed

Lines changed: 3833 additions & 2597 deletions

File tree

CHANGELOG.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,28 @@
11
## Changelog
22

3-
### Unreleased
4-
3+
### v4.0.0 - 8th Sep 2025
4+
5+
- Upgrade to gitopia-js v3.0.0
6+
- Implement new storage provider architecture with automatic provider selection based on latency
7+
- Add storage information display in repository clone info with dedicated "Storage Info" tab
8+
- Introduce storage provider dropdown with separate tabs for API and storage providers
9+
- Complete rewrite of create and update release workflows with authenticated file upload
10+
- Implement new fork workflow with updated fork messages
11+
- Update pull request merge flow with new merge steps for both user and DAO repositories
12+
- Handle DAO create release proposals in group proposal execution
13+
- Update merge proposals for DAO repositories
14+
- Add storage update proposal handling for release asset management
15+
- Remove deprecated fork merge access dialogs and authorization flows
16+
- Remove `authorizeGitServer` function and related authorization components
17+
- Remove deprecated `AccountGrants` component and related authorization functionalities
18+
- Fix redirect handling on repository deletion
19+
- Implement storage queries across the application
20+
- Replace hardcoded storage URLs with dynamic provider selection
521
- Don't show proposals tab in user profile
6-
- Show treasury balance upto two decimal places only
7-
- Don't re-render header everytime we switch tab
8-
- Show link to parent repo in case of fork repo
22+
- Show treasury balance limited to two decimal places
23+
- Prevent header re-rendering when switching tabs
24+
- Display link to parent repository in forked repository views
25+
- Add ChainRoot link in the explorers dropdown
926

1027
### v3.1.0 - 2nd Dec 2024
1128

components/dashboard/ProposalDetailsModal.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const ProposalDetailsModal = ({
7676
policyInfo,
7777
selectedAddress,
7878
cosmosGroupApiClient,
79+
storageApiClient,
7980
}) => {
8081
const [tally, setTally] = useState(null);
8182
const [loading, setLoading] = useState(true);
@@ -142,7 +143,7 @@ const ProposalDetailsModal = ({
142143
veto: (vetoVotes / totalWeight) * 100,
143144
quorum:
144145
policyInfo?.info.decision_policy["@type"] ===
145-
"/cosmos.group.v1.PercentageDecisionPolicy"
146+
"/cosmos.group.v1.PercentageDecisionPolicy"
146147
? parseFloat(policyInfo.info.decision_policy.percentage) * 100
147148
: 0,
148149
};
@@ -205,9 +206,8 @@ const ProposalDetailsModal = ({
205206
{/* Execution Status */}
206207
{proposal.status === "PROPOSAL_STATUS_ACCEPTED" && (
207208
<div
208-
className={`p-4 rounded-lg ${
209-
canExecute ? "bg-warning/10" : "bg-success/10"
210-
}`}
209+
className={`p-4 rounded-lg ${canExecute ? "bg-warning/10" : "bg-success/10"
210+
}`}
211211
>
212212
<div className="flex items-center">
213213
<Info className="w-5 h-5 mr-2 text-warning" />
@@ -216,15 +216,15 @@ const ProposalDetailsModal = ({
216216
{isTextProposal
217217
? "Text Proposal Passed"
218218
: canExecute
219-
? "Proposal Execution Required"
220-
: "Proposal Executed"}
219+
? "Proposal Execution Required"
220+
: "Proposal Executed"}
221221
</p>
222222
<p className="text-sm text-gray-400">
223223
{isTextProposal
224224
? "This is a text-only proposal that required no execution."
225225
: canExecute
226-
? "This proposal has passed but hasn't been executed yet. Execute it to apply the changes."
227-
: "This proposal has been executed successfully."}
226+
? "This proposal has passed but hasn't been executed yet. Execute it to apply the changes."
227+
: "This proposal has been executed successfully."}
228228
</p>
229229
</div>
230230
</div>

components/dashboard/ProposalsSection.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,10 @@ const ProposalCard = ({
199199
vote.option === "VOTE_OPTION_YES"
200200
? "text-success"
201201
: vote.option === "VOTE_OPTION_NO"
202-
? "text-error"
203-
: vote.option === "VOTE_OPTION_NO_WITH_VETO"
204-
? "text-warning"
205-
: "text-muted"
202+
? "text-error"
203+
: vote.option === "VOTE_OPTION_NO_WITH_VETO"
204+
? "text-warning"
205+
: "text-muted"
206206
}
207207
>
208208
{vote.option.replace("VOTE_OPTION_", "")}
@@ -266,9 +266,8 @@ const ProposalFilters = ({ onFilter, activeFilter }) => (
266266
<button
267267
key={filter}
268268
onClick={() => onFilter(filter.toLowerCase())}
269-
className={`btn btn-sm ${
270-
activeFilter === filter.toLowerCase() ? "btn-primary" : "btn-ghost"
271-
}`}
269+
className={`btn btn-sm ${activeFilter === filter.toLowerCase() ? "btn-primary" : "btn-ghost"
270+
}`}
272271
>
273272
{filter}
274273
</button>
@@ -347,6 +346,7 @@ export default function ProposalsSection({
347346
cosmosBankApiClient,
348347
cosmosFeegrantApiClient,
349348
cosmosGroupApiClient,
349+
storageApiClient,
350350
} = useApiClient();
351351
const [isExecuting, setIsExecuting] = useState(false);
352352
const dispatch = useDispatch();
@@ -405,21 +405,32 @@ export default function ProposalsSection({
405405
}
406406
}, [proposals, cosmosGroupApiClient]);
407407

408-
const handleExecuteProposal = async (proposalId) => {
408+
const handleExecuteProposal = async (proposal) => {
409409
setIsExecuting(true);
410410
try {
411411
const result = await dispatch(
412412
executeGroupProposal(
413413
apiClient,
414414
cosmosBankApiClient,
415415
cosmosFeegrantApiClient,
416-
proposalId
416+
storageApiClient,
417+
proposal
417418
)
418419
);
419420

420421
if (result && result.code === 0) {
421422
// Refresh proposals list after successful execution
422423
await onRefreshProposals();
424+
425+
// Fetch updated proposal data to update the modal UI
426+
try {
427+
const updatedProposalRes = await cosmosGroupApiClient.queryProposal(proposal.id);
428+
if (updatedProposalRes && updatedProposalRes.data && updatedProposalRes.data.proposal) {
429+
setSelectedProposal(updatedProposalRes.data.proposal);
430+
}
431+
} catch (error) {
432+
console.error("Error fetching updated proposal:", error);
433+
}
423434
}
424435
} catch (error) {
425436
console.error("Error executing proposal:", error);
@@ -519,13 +530,14 @@ export default function ProposalsSection({
519530
setSelectedProposal(null);
520531
}}
521532
onVote={onVote}
522-
onExecute={() => handleExecuteProposal(selectedProposal.id)}
533+
onExecute={() => handleExecuteProposal(selectedProposal)}
523534
isExecuting={isExecuting}
524535
groupInfo={groupInfo}
525536
policyInfo={policyInfo}
526537
selectedAddress={selectedAddress}
527538
votes={proposalVotes[selectedProposal.id]}
528539
cosmosGroupApiClient={cosmosGroupApiClient}
540+
storageApiClient={storageApiClient}
529541
/>
530542
)}
531543
</div>

components/header.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,15 @@ function Header(props) {
270270
tabIndex={0}
271271
className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52"
272272
>
273+
<li>
274+
<a
275+
href="https://explorer.chainroot.io/gitopia"
276+
target="_blank"
277+
rel="noreferrer"
278+
>
279+
ChainRoot
280+
</a>
281+
</li>
273282
<li>
274283
<a
275284
href="https://gitopia.exploreme.pro/"

components/repository/deleteRepository.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { deleteRepository } from "../../store/actions/repository";
44
import { useApiClient } from "../../context/ApiClientContext";
55

66
function DeleteRepository({
7+
repositoryId = null,
78
repoName = "",
89
currentOwnerId = "",
910
onSuccess,
@@ -16,6 +17,7 @@ function DeleteRepository({
1617
apiClient,
1718
cosmosBankApiClient,
1819
cosmosFeegrantApiClient,
20+
storageApiClient,
1921
storageProviderAddress,
2022
} = useApiClient();
2123

@@ -91,8 +93,10 @@ function DeleteRepository({
9193
apiClient,
9294
cosmosBankApiClient,
9395
cosmosFeegrantApiClient,
96+
storageApiClient,
9497
storageProviderAddress,
9598
{
99+
repositoryId,
96100
ownerId: currentOwnerId,
97101
name: repoName,
98102
}

components/repository/mergePullRequestView.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import getPullRequestMergePermission from "../../helpers/getPullRequestMergePerm
1212
import getDao from "../../helpers/getDao";
1313
import { useApiClient } from "../../context/ApiClientContext";
1414
import { useRouter } from "next/router";
15+
import getBranchSha from "../../helpers/getBranchSha";
1516

1617
function MergePullRequestView({
1718
repository,
@@ -30,6 +31,7 @@ function MergePullRequestView({
3031
cosmosBankApiClient,
3132
cosmosFeegrantApiClient,
3233
cosmosGroupApiClient,
34+
storageApiClient,
3335
storageProviderAddress,
3436
storageApiUrl,
3537
} = useApiClient();
@@ -92,6 +94,10 @@ function MergePullRequestView({
9294
const createMergeProposal = async () => {
9395
setIsCreatingProposal(true);
9496
try {
97+
const baseCommitSha = getBranchSha(
98+
pullRequest.base.branch,
99+
repository.branches,
100+
);
95101
const result = await props.mergePullRequestForDao(
96102
apiClient,
97103
cosmosBankApiClient,
@@ -102,6 +108,7 @@ function MergePullRequestView({
102108
repositoryId: repository.id,
103109
iid: pullRequest.iid,
104110
groupId: daoInfo.group_id,
111+
baseCommitSha,
105112
}
106113
);
107114

@@ -133,20 +140,25 @@ function MergePullRequestView({
133140
);
134141

135142
if (user && user.havePermission) {
143+
const baseCommitSha = getBranchSha(
144+
pullRequest.base.branch,
145+
repository.branches,
146+
);
136147
const res = await props.mergePullRequest(
137148
apiClient,
138149
cosmosBankApiClient,
139150
cosmosFeegrantApiClient,
151+
storageApiClient,
140152
storageProviderAddress,
141153
{
142154
repositoryId: repository.id,
143155
iid: pullRequest.iid,
144-
branchName: pullRequest.head.branch,
156+
baseCommitSha,
145157
}
146158
);
147159

148160
if (res) {
149-
if (res.state === "TASK_STATE_SUCCESS") refreshPullRequest();
161+
if (res.code === 0) refreshPullRequest();
150162
} else {
151163
props.notify("Unknown error", "error");
152164
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"@cosmjs/ledger-amino": "^0.32.4",
2121
"@cosmjs/proto-signing": "^0.32.4",
2222
"@cosmjs/stargate": "^0.32.4",
23-
"@gitopia/gitopia-js": "2.1.0",
23+
"@gitopia/gitopia-js": "3.0.0",
2424
"@heroicons/react": "^2.1.5",
2525
"@ledgerhq/hw-transport-webhid": "^6.27.13",
2626
"@ledgerhq/hw-transport-webusb": "^6.27.13",

pages/[userId]/[repositoryId]/releases/edit/[tagName].js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,24 +56,25 @@ function RepositoryReleaseEditView(props) {
5656
const [description, setDescription] = useState("");
5757
const [tagName, setTagName] = useState("");
5858
const [target, setTarget] = useState({ name: "", sha: null });
59-
const [postingIssue, setPostingIssue] = useState(false);
59+
const [postingRelease, setPostingRelease] = useState(false);
6060
const [attachments, setAttachments] = useState([]);
6161
const [uploadingAttachment, setUploadingAttachment] = useState({ file: {} });
6262
const [newTagOptionShown, setNewTagOptionShown] = useState(false);
6363
const [creatingTag, setCreatingTag] = useState(false);
64-
const { apiClient, cosmosBankApiClient, cosmosFeegrantApiClient, storageProviderAddress } =
64+
const { apiClient, cosmosBankApiClient, cosmosFeegrantApiClient, storageApiClient, storageProviderAddress, storageApiUrl } =
6565
useApiClient();
6666

67-
const validateIssue = () => {
67+
const validateRelease = () => {
6868
return true;
6969
};
7070

71-
const createIssue = async () => {
72-
setPostingIssue(true);
73-
if (validateIssue()) {
74-
const issue = {
71+
const handleUpdateRelease = async () => {
72+
setPostingRelease(true);
73+
if (validateRelease()) {
74+
const releaseData = {
7575
name: title,
7676
description,
77+
repositoryId: repository.id,
7778
repoOwner: repository.owner.id,
7879
repoName: repository.name,
7980
tagName,
@@ -91,13 +92,13 @@ function RepositoryReleaseEditView(props) {
9192
}),
9293
releaseId: parseInt(release.id),
9394
};
94-
console.log("before call", issue);
9595
const res = await props.createRelease(
9696
apiClient,
9797
cosmosBankApiClient,
9898
cosmosFeegrantApiClient,
99+
storageApiClient,
99100
storageProviderAddress,
100-
issue,
101+
releaseData,
101102
true
102103
);
103104
if (res && res.code === 0) {
@@ -111,7 +112,7 @@ function RepositoryReleaseEditView(props) {
111112
);
112113
}
113114
}
114-
setPostingIssue(false);
115+
setPostingRelease(false);
115116
};
116117

117118
const getRelease = async () => {
@@ -434,7 +435,7 @@ function RepositoryReleaseEditView(props) {
434435
<div>
435436
<Uploady
436437
destination={{
437-
url: process.env.NEXT_PUBLIC_OBJECTS_URL + "/upload",
438+
url: storageApiUrl + "/upload",
438439
}}
439440
>
440441
<UploadDropZone
@@ -453,10 +454,10 @@ function RepositoryReleaseEditView(props) {
453454
<button
454455
className={
455456
"btn btn-sm btn-primary btn-block " +
456-
(postingIssue ? "loading" : "")
457+
(postingRelease ? "loading" : "")
457458
}
458-
disabled={title.trim().length === 0 || postingIssue}
459-
onClick={createIssue}
459+
disabled={title.trim().length === 0 || postingRelease}
460+
onClick={handleUpdateRelease}
460461
data-test="update-release"
461462
>
462463
Update Release

pages/[userId]/[repositoryId]/releases/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function RepositoryReleasesView(props) {
3535
const [olderReleases, setOlderReleases] = useState([]);
3636
const [currentUserEditPermission, setCurrentUserEditPermission] =
3737
useState(false);
38-
const { apiClient, cosmosBankApiClient, cosmosFeegrantApiClient } =
38+
const { apiClient, cosmosBankApiClient, cosmosFeegrantApiClient, storageApiClient, storageProviderAddress } =
3939
useApiClient();
4040

4141
const getReleases = async () => {
@@ -98,8 +98,12 @@ function RepositoryReleasesView(props) {
9898
apiClient,
9999
cosmosBankApiClient,
100100
cosmosFeegrantApiClient,
101+
storageApiClient,
102+
storageProviderAddress,
101103
{
102104
releaseId: id,
105+
repositoryId: repository.id,
106+
tagName: latestRelease.tagName,
103107
}
104108
);
105109
await refreshRepository();

0 commit comments

Comments
 (0)