Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d4e579a
reset pagination for trashModal
ozer550 Nov 13, 2025
1b2c0b7
push new modififed field to sync
ozer550 Nov 24, 2025
db37082
Add double click blocking and error handling for user creation form s…
rtibbles Dec 1, 2025
52a27d5
make changes in test to reflect new modified field operational changes
ozer550 Dec 2, 2025
821c2f0
Merge pull request #5552 from ozer550/fix-trash-page-pagination
rtibbles Dec 4, 2025
0dc4909
First pass, based off of suggestions from AI.
DXCanas Dec 4, 2025
ff6209a
Removing vestigial git module definition
DXCanas Dec 4, 2025
c14ec2b
Removing symlink to prod dockerfile.
DXCanas Dec 4, 2025
840dcad
Clearing out prober code.
DXCanas Dec 4, 2025
aae5494
Moving nginx files out of `deploy` and housing them with other image-…
DXCanas Dec 4, 2025
200f537
WIP: Moving prod dockerfiles out of defunct k8s dir.
DXCanas Dec 5, 2025
1dbd0db
WIP: Flattening out new image structure, following current naming sta…
DXCanas Dec 5, 2025
c4155bf
Removing defunct cloudbuild-pr.yaml
DXCanas Dec 5, 2025
cb8cdfe
Flattening file structure further.
DXCanas Dec 5, 2025
0c39da8
Bringing in temporary symlinks for infra-side CD.
DXCanas Dec 5, 2025
1394aba
Cleaning up more prober code.
DXCanas Dec 5, 2025
57ef5cd
Merge pull request #5596 from DXCanas/studio-infra-file-cleanup
rtibbles Dec 16, 2025
b50bdb9
Configure Celery for graceful shutdown
claude Oct 30, 2025
8ca219b
Update paths for nginx Dockerfile in workflow
rtibbles Dec 17, 2025
502c99e
Merge pull request #5612 from learningequality/rtibbles-patch-1
bjester Dec 17, 2025
f8b957f
Merge pull request #5520 from learningequality/claude/issue-5000-hotf…
rtibbles Dec 18, 2025
eb50847
Fix Language foreign key column lengths (#5618)
claude Dec 19, 2025
19f4152
Merge pull request #5582 from learningequality/claude/fix-submissions…
rtibbles Jan 6, 2026
f05c8e0
Fix sync missing fields: language, provider, aggregator, role_visibility
claude Nov 29, 2025
b6f40a9
Merge pull request #5590 from learningequality/claude/issue-4930-plan…
bjester Jan 8, 2026
1208fee
Narrow Language FK fix to only included_languages M2M table
rtibbles Jan 12, 2026
4f67e69
Merge pull request #5623 from rtibbles/m2m_lang
bjester Jan 13, 2026
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
4 changes: 2 additions & 2 deletions .github/workflows/containerbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
with:
skip_after_successful_duplicate: false
github_token: ${{ github.token }}
paths: '["k8s/images/nginx/*", ".github/workflows/containerbuild.yml"]'
paths: '["docker/Dockerfile.nginx.prod", "docker/nginx/*", ".github/workflows/containerbuild.yml"]'

build_nginx:
name: nginx - test build of nginx Docker image
Expand All @@ -100,6 +100,6 @@ jobs:
uses: docker/build-push-action@v6
with:
context: ./
file: ./k8s/images/nginx/Dockerfile
file: ./docker/Dockerfile.nginx.prod
platforms: linux/amd64
push: false
6 changes: 0 additions & 6 deletions .gitmodules

This file was deleted.

6 changes: 1 addition & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,7 @@ dcbuild:
$(DOCKER_COMPOSE) build

dcup: .docker/minio .docker/postgres
# run all services except for cloudprober
$(DOCKER_COMPOSE) up studio-app celery-worker

dcup-cloudprober: .docker/minio .docker/postgres
# run all services including cloudprober
# run all services
$(DOCKER_COMPOSE) up

dcdown:
Expand Down
102 changes: 0 additions & 102 deletions cloudbuild-pr.yaml

This file was deleted.

99 changes: 0 additions & 99 deletions cloudbuild-production.yaml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -213,9 +213,10 @@
<KButton
primary
class="mt-5"
:disabled="offline"
:disabled="offline || submitting"
:text="$tr('finishButton')"
type="submit"
data-test="submit-button"
/>
</VForm>
</VLayout>
Expand Down Expand Up @@ -260,6 +261,7 @@
return {
valid: true,
registrationFailed: false,
submitting: false,
form: {
first_name: '',
last_name: '',
Expand Down Expand Up @@ -482,6 +484,12 @@
// We need to check the "acceptedAgreement" here explicitly because it is not a
// Vuetify form field and does not trigger the form validation.
if (this.$refs.form.validate() && this.acceptedAgreement) {
// Prevent double submission
if (this.submitting) {
return Promise.resolve();
}

this.submitting = true;
const cleanedData = this.clean(this.form);
return this.register(cleanedData)
.then(() => {
Expand Down Expand Up @@ -517,6 +525,9 @@
this.registrationFailed = true;
this.valid = false;
}
})
.finally(() => {
this.submitting = false;
});
} else if (this.$refs.top.scrollIntoView) {
this.$refs.top.scrollIntoView({ behavior: 'smooth' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,19 @@ describe('create', () => {
expect(wrapper.vm.registrationFailed).toBe(true);
});
});
describe('double-submit prevention', () => {
it('should prevent multiple API calls on rapid clicks', async () => {
const [wrapper, mocks] = await makeWrapper();

// Click submit multiple times
const p1 = wrapper.vm.submit();
const p2 = wrapper.vm.submit();
const p3 = wrapper.vm.submit();

await Promise.all([p1, p2, p3]);

// Only 1 API call should be made
expect(mocks.register).toHaveBeenCalledTimes(1);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -281,19 +281,24 @@
'moveContentNodes',
'loadContentNodes',
'loadAncestors',
'removeContentNodes',
]),
loadNodes() {
this.loading = true;
this.more = null;
this.moreLoading = false;
if (!this.trashId) {
this.loading = false;
return;
}
this.loadChildren({ parent: this.trashId, ordering: '-modified' }).then(
childrenResponse => {
this.loading = false;
this.more = childrenResponse.more || null;
},
);
this.removeContentNodes({ parentId: this.trashId }).then(() => {
this.loadChildren({ parent: this.trashId, ordering: '-modified' }).then(
childrenResponse => {
this.loading = false;
this.more = childrenResponse.more || null;
},
);
});
},
moveNodes(target) {
return this.moveContentNodes({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,12 @@ describe('ContentNode methods', () => {

it('should update the node with the payload', async () => {
node.parent = parent.id;
await expect(ContentNode.tableMove({ node, parent, payload, change })).resolves.toBe(payload);
expect(table.update).toHaveBeenCalledWith(node.id, payload);
const result = await ContentNode.tableMove({ node, parent, payload, change });
expect(result).toMatchObject({ ...payload, modified: expect.any(String) });
expect(table.update).toHaveBeenCalledTimes(1);
const [updateId, updatePayload] = table.update.mock.calls[0];
expect(updateId).toBe(node.id);
expect(updatePayload).toBe(result);
expect(table.put).not.toBeCalled();
expect(table.update).not.toHaveBeenCalledWith(node.parent, { changed: true });
});
Expand All @@ -584,19 +588,23 @@ describe('ContentNode methods', () => {
node.parent = parent.id;
updated = false;
const newPayload = { ...payload, root_id: parent.root_id };
await expect(ContentNode.tableMove({ node, parent, payload, change })).resolves.toMatchObject(
newPayload,
const result = await ContentNode.tableMove({ node, parent, payload, change });
expect(result).toMatchObject({ ...newPayload, modified: expect.any(String) });
expect(table.update).toHaveBeenCalledWith(
node.id,
expect.objectContaining({ ...payload, modified: expect.any(String) }),
);
expect(table.update).toHaveBeenCalledWith(node.id, payload);
expect(table.put).toHaveBeenCalledWith(newPayload);
expect(table.put).toHaveBeenCalledWith(result);
expect(table.update).not.toHaveBeenCalledWith(node.parent, { changed: true });
});

it('should mark the old parent as changed', async () => {
await expect(ContentNode.tableMove({ node, parent, payload, change })).resolves.toMatchObject(
payload,
const result = await ContentNode.tableMove({ node, parent, payload, change });
expect(result).toMatchObject({ ...payload, modified: expect.any(String) });
expect(table.update).toHaveBeenCalledWith(
node.id,
expect.objectContaining({ ...payload, modified: expect.any(String) }),
);
expect(table.update).toHaveBeenCalledWith(node.id, payload);
expect(table.put).not.toBeCalled();
expect(table.update).toHaveBeenCalledWith(node.parent, { changed: true });
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1687,6 +1687,10 @@ export const ContentNode = new TreeResource({
async tableMove({ node, parent, payload }) {
// Do direct table writes here rather than using add/update methods to avoid
// creating unnecessary additional change events.
payload = {
...payload,
modified: new Date().toISOString(),
};
const updated = await this.table.update(node.id, payload);
// Update didn't succeed, this node probably doesn't exist, do a put instead,
// but need to add in other parent info.
Expand Down
Loading