activeadmin_batched_export 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f422e2d7c0f709e46fabfda5bc837d53835c5951d35520687c8c0008b0fbc851
4
- data.tar.gz: c0f9c04756c060ac5c9b5e3d8ad85fcf825a13deaad5f59eadd6b3d625ee97f4
3
+ metadata.gz: f53b863da20a561edbc6192d923009b25b6f2f7efb69befbaca5385ebb5dfac4
4
+ data.tar.gz: 727a408e9c7f12a5238441845e37222aef9dd8d34a4217ef8e2b1cf4871e4d12
5
5
  SHA512:
6
- metadata.gz: 168669e5c28b6adbac2f09f7fe2f01cba5209639d36f32221d15592e4197730a948d2cd02646bbb679ec9e195a059746282d181abc9b72f43fe9ea14ea211d61
7
- data.tar.gz: 7714ba53d4b2592d167e89ca07a41a16d61be9bec0db2a3f28fea88642d17852606ee15a96bf5adbc80524676629804013b689735065b15daa56c2a157b544f6
6
+ metadata.gz: 336b5af8351b73c2422fc566400c54c35926dcf8f953c06c53481ed8c9b34dc3eb28f8b1e5f7411d20b70746ac35bfde91c545371afd4bbc77b81681aaa1b150
7
+ data.tar.gz: ac52d361d860f738200c9c334c2d40d198e32558a356d26f78313cc464e1054ece083dc8f34c8455acfe737b30f6ac470df05bec40822963c7457dc1b5919adc
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.3.0 (2026-09-04)
6
+
7
+ - BREAKING: Walk export batches with `export_cursor` and `X-Batched-Export-Next` instead of OFFSET `batch_page`. Hosts that copied the Stimulus controller must pick up the new loop.
8
+ - Freeze filtered ids when table `active_admin_batched_export_snapshot_rows` exists (`export_snapshot`, `X-Batched-Export-Snapshot`). Without the table, batches keep walking a live keyset.
9
+ - Add `max_export_rows` (nil = unlimited). A COUNT over the cap is 400 on the first batch; meta still returns 200 with `over_max`.
10
+ - Sort NULL keys last in both directions.
11
+ - Always refetch export meta before load. Stop on a short last page. Concatenate JSON chunks as one array. Cancel keeps an incomplete Blob.
12
+ - Return 400 when `export_columns` resolve to no columns.
13
+
5
14
  ## 0.2.0 (2026-07-14)
6
15
 
7
16
  - Treat a per-resource `batched_export` DSL call as enablement; `enabled: true` is no longer required when opting in per resource.
data/CODE_OF_CONDUCT.md CHANGED
@@ -1,38 +1,26 @@
1
1
  # Code of Conduct
2
2
 
3
- ## Our Pledge
3
+ ## Pledge
4
4
 
5
- We pledge to make participation in our community a harassment-free experience for everyone. We operate on principles of mutual respect, privacy, and authentic engagement. We value substantive contributions and clarity on intentions.
5
+ Participation is a harassment-free experience. Treat each other with respect. Keep private context private.
6
6
 
7
- ## Our Standards
7
+ ## Expected behavior
8
8
 
9
- Examples of behavior that contributes to a positive environment include:
9
+ - Engage with genuine curiosity. Admit uncertainty.
10
+ - Own every line you submit, including generated code.
11
+ - Correct errors politely.
12
+ - Use language that welcomes people and respects identity and privacy.
10
13
 
11
- * **Authenticity:** Engaging with genuine curiosity and admitting uncertainty rather than feigning knowledge.
14
+ ## Unacceptable behavior
12
15
 
13
- * **Responsible Innovation:** Taking full responsibility for any content or code contributed, whether manually written or generated by automation tools.
16
+ - Harassment, trolling, or insulting comments, public or private.
17
+ - Using jargon or volume, including automated spam, to silence others.
18
+ - Sharing others' data or personal context without permission.
14
19
 
15
- * **Gentle Correction:** Responding politely to errors. We view mistakes as opportunities for learning, provided they are addressed with humility.
20
+ ## Automation
16
21
 
17
- * **Inclusive Language:** Using language that welcomes diverse perspectives and respects the privacy and identity of all participants.
18
-
19
- Examples of unacceptable behavior include:
20
-
21
- * **Harassment:** Public or private harassment, trolling, or insulting comments.
22
-
23
- * **Weaponized Complexity:** Using jargon or overwhelming volume (including automated spam) to silence others.
24
-
25
- * **Publishing Private Information:** Sharing others' data or personal context without explicit permission.
26
-
27
- ## Artificial Intelligence & Automation
28
-
29
- In accordance with our commitment to **Collective Awareness**:
30
-
31
- * Contributors are responsible for the accuracy and security of any AI-generated artifacts they submit.
32
-
33
- * "The AI wrote it" is not a valid excuse for introducing bugs, security vulnerabilities, or bias.
22
+ You remain responsible for bugs, security holes, and bias in generated artifacts you submit.
34
23
 
35
24
  ## Enforcement
36
25
 
37
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@kiskolabs.com. All complaints will be reviewed and investigated promptly and fairly.
38
-
26
+ Report abusive or harassing behavior to contact@kiskolabs.com. Reports are reviewed and investigated.
data/CONTRIBUTING.md CHANGED
@@ -1,29 +1,23 @@
1
1
  # Contributing Guidelines
2
2
 
3
- Thank you for your interest in contributing to activeadmin_batched_export. We value **learning over perfection** but require **rigor and responsibility**.
3
+ ## Automation authorship
4
4
 
5
- ## The Golden Rule of Automation
5
+ You may use AI and automation tools. You remain the author of every line you submit: review, debug, and understand the change.
6
6
 
7
- We welcome the use of AI and automation tools to reduce toil, but you must strictly adhere to the following:
7
+ Keep pull requests small enough to review. Annotate non-obvious logic.
8
8
 
9
- 1. **You are the Author:** You act as the responsible agent for any code you submit. You must review, debug, and understand every line.
10
- 2. **Manage Cognitive Load:** Do not submit massive, unreviewed automated dumps. Respect the reviewers' time by annotating complex logic.
11
- 3. **Security:** Never feed project secrets or private context into public AI models.
9
+ Never send project secrets or private context to public models.
12
10
 
13
- ## How to Contribute
11
+ ## How to contribute
14
12
 
15
- ### 1. Reporting Issues
13
+ ### Reporting issues
16
14
 
17
- - **Verify Accuracy:** Before posting, verify your information. Avoid generalizations.
18
- - **Use Structured Inputs:** Use our Issue Templates to provide clear goals, constraints, and reproduction steps.
15
+ Verify the facts before filing. Use issue templates for goals, constraints, and reproduction steps.
19
16
 
20
- ### 2. Pull Request Process
17
+ ### Pull requests
21
18
 
22
- - **Scope:** Keep PRs focused on a single goal.
23
- - **Context:** Explain why the change is necessary.
24
- - **Testing:** Run `make test` locally before opening a PR.
19
+ Keep one pull request to one goal. Explain why the change is needed. Run smoke tests and regression checks locally before opening the request.
25
20
 
26
- ### 3. Review Process
21
+ ### Review
27
22
 
28
- - We encourage productive friction. Expect questions about your approach.
29
- - If a reviewer suggests a change, view it as mutual aid, not criticism.
23
+ Reviewers will ask about approach and trade-offs. Treat suggested changes as part of the work.
data/GOVERNANCE.md CHANGED
@@ -1,32 +1,25 @@
1
1
  # Project Governance
2
2
 
3
- ## Overview
4
-
5
- This project balances **individual autonomy** with **collective coordination**. We aim for a workflow that supports rapid iteration while maintaining strict guardrails for safety and architectural integrity.
6
-
7
3
  ## Roles
8
4
 
9
5
  ### Contributors
10
6
 
11
- Anyone who submits code, documentation, or participates in discussions. Contributors are expected to exercise **Direct Action**—taking ownership of problems they identify—while adhering to our quality standards.
12
-
13
- ### Maintainers (Human Oversight)
14
-
15
- Maintainers are responsible for:
16
-
17
- 1. **Strategic Judgment:** Defining scope and architectural direction.
7
+ Anyone who submits code, documentation, or participates in discussions. Contributors take ownership of problems they identify and follow the project's quality standards.
18
8
 
19
- 2. **Review:** verifying that contributions (human or automated) meet security and logic standards.
9
+ ### Maintainers
20
10
 
21
- 3. **Consensus Building:** Facilitating decisions when the community is divided.
11
+ Maintainers:
22
12
 
23
- ## Decision Making process
13
+ 1. Set scope and architectural direction.
14
+ 2. Review contributions (human or automated) against security and logic standards.
15
+ 3. Decide when the community is divided.
24
16
 
25
- ### Lazy Consensus
17
+ ## Decision making
26
18
 
27
- For most routine changes, we operate on "lazy consensus." If a proposal is made and no objections are raised within two weeks, it is considered approved.
19
+ ### Lazy consensus
28
20
 
29
- ### Strategic Alignment
21
+ For routine changes, a proposal that draws no objection within two weeks is approved.
30
22
 
31
- Major architectural changes, high-risk automation integrations, or changes that affect business logic require explicit approval from the Maintainers. We prioritize **substance over performance**—a change must solve a real problem, not just appear polished.
23
+ ### Maintainer approval
32
24
 
25
+ Major architectural changes, high-risk automation integrations, or changes that affect business logic need explicit maintainer approval. A change must solve a real problem.
data/README.md CHANGED
@@ -4,11 +4,11 @@
4
4
 
5
5
  Batched CSV, JSON, and XML export workspace for ActiveAdmin 4.
6
6
 
7
- Replaces single long-lived index downloads with a workspace page that loads filtered data in sequential HTTP batches, then offers one client-side file download.
7
+ Replaces single long-lived index downloads with a workspace page that loads filtered data in sequential batches, then offers one client-side file download.
8
8
 
9
9
  ## Requirements
10
10
 
11
- - Ruby 3.2+
11
+ - Ruby 3.4+
12
12
  - Rails 7.1+
13
13
  - ActiveAdmin 4.0.0.beta13+
14
14
  - importmap-rails and Stimulus (ActiveAdmin 4 default)
@@ -39,6 +39,22 @@ bundle install
39
39
 
40
40
  The engine registers routes, views, importmap pins, and install hooks automatically. Optional host overrides go in `config/initializers/activeadmin_batched_export.rb`.
41
41
 
42
+ To freeze export ids across batches (RFC-0003), create this table in the host app:
43
+
44
+ ```ruby
45
+ create_table :active_admin_batched_export_snapshot_rows do |t|
46
+ t.string :token, null: false
47
+ t.string :resource_type, null: false
48
+ t.bigint :record_id, null: false
49
+ t.integer :position, null: false
50
+ t.datetime :created_at, null: false
51
+ end
52
+ add_index :active_admin_batched_export_snapshot_rows, [:token, :position], unique: true
53
+ add_index :active_admin_batched_export_snapshot_rows, :created_at
54
+ ```
55
+
56
+ Without that table, batches walk a live keyset cursor. With it, the first batch stores filtered primary keys and later batches join live rows in freeze order. The token is not an access grant: rows still load through `find_collection`.
57
+
42
58
  Enable download formats per resource:
43
59
 
44
60
  ```ruby
@@ -62,6 +78,8 @@ ActiveAdmin::BatchedExport.configure do |config|
62
78
  config.batch_size = 1000
63
79
  config.max_batch_size = 10_000
64
80
  config.large_export_row_threshold = 25_000
81
+ config.max_export_rows = nil
82
+ config.snapshot_ttl = 86_400
65
83
  config.stimulus_controller = "activeadmin-batched-export--batched-export"
66
84
 
67
85
  config.styles = ActiveAdmin::BatchedExport::Styles.new(
@@ -121,6 +139,7 @@ ActiveAdmin::BatchedExport.configure do |config|
121
139
  card: "rounded-lg border border-slate-200 bg-slate-50 p-6",
122
140
  primary_button: "btn btn-primary",
123
141
  secondary_button: "btn btn-outline",
142
+ cancel_button: "btn btn-ghost",
124
143
  back_link: "link link-primary"
125
144
  )
126
145
  end
@@ -128,7 +147,7 @@ end
128
147
 
129
148
  Override only the keys you need; unset keys keep gem defaults (light and dark Tailwind classes).
130
149
 
131
- Available keys: `workspace`, `card`, `card_title`, `table`, `table_body`, `table_row`, `table_header`, `table_cell`, `table_cell_mono`, `hint`, `column_grid`, `column_label`, `column_checkbox`, `heading`, `progress_wrap`, `progress_bar`, `progress_status_row`, `error`, `warning`, `actions`, `primary_button`, `secondary_button`, `back_link`.
150
+ Available keys: `workspace`, `card`, `card_title`, `table`, `table_body`, `table_row`, `table_header`, `table_cell`, `table_cell_mono`, `hint`, `column_grid`, `column_label`, `column_checkbox`, `heading`, `progress_wrap`, `progress_bar`, `progress_status_row`, `error`, `warning`, `actions`, `primary_button`, `secondary_button`, `cancel_button`, `back_link`.
132
151
 
133
152
  ### Override partials
134
153
 
@@ -139,7 +158,7 @@ Copy any partial from the gem into `app/views/active_admin/batched_export/` in t
139
158
  - `_columns.html.erb`
140
159
  - `_filters.html.erb`
141
160
  - `_progress.html.erb`
142
- - `_actions.html.erb` — export and back buttons
161
+ - `_actions.html.erb` — load, cancel, save, and back buttons
143
162
 
144
163
  ### Stimulus controller
145
164
 
@@ -157,20 +176,20 @@ See [examples/custom_theme/README.md](examples/custom_theme/README.md) for local
157
176
 
158
177
  ## Stimulus controller and assets
159
178
 
160
- The engine pins `controllers/activeadmin_batched_export/batched_export_controller` on both the host and ActiveAdmin importmaps. Include the gem asset path in your ActiveAdmin importmap cache sweeper when developing locally.
179
+ The engine pins `controllers/activeadmin_batched_export/batched_export_controller` and `activeadmin_batched_export/chunk_assembly` on both the host and ActiveAdmin importmaps. Include the gem `app/assets/controllers` and `app/assets/javascripts` paths in your ActiveAdmin importmap cache sweeper when developing locally.
161
180
 
162
181
  ## How it works
163
182
 
164
183
  1. Index download links route to `batched_export` instead of synchronous format URLs.
165
184
  2. Workspace shows filter context, optional column checkboxes, and batch metadata.
166
- 3. Stimulus fetches `export_meta` JSON, then each `batch_page` chunk.
167
- 4. User saves the assembled Blob locally.
185
+ 3. Load export always refetches `export_meta` JSON for a progress estimate, then walks chunks with `export_cursor` / `X-Batched-Export-Next` until that header is absent. When the freeze table exists, the first batch also returns `X-Batched-Export-Snapshot` and later chunks send `export_snapshot` with the cursor.
186
+ 4. User saves the assembled Blob locally. Cancel keeps an incomplete file when any chunks already arrived.
168
187
 
169
- Batched requests limit server memory per request; the browser still holds the full assembled file before save. Very large exports can exhaust tab memory. Tune `batch_size`, `max_batch_size`, and `large_export_row_threshold` for your data width and row counts. The workspace shows a warning when row count reaches the threshold.
188
+ Batched requests limit server memory per request; the browser still holds the full assembled file before save. Very large exports can exhaust tab memory. Tune `batch_size`, `max_batch_size`, and `large_export_row_threshold` for your data width and row counts. The workspace shows a warning when row count reaches the threshold. Set `max_export_rows` to refuse a collection larger than that count (`over_max` on meta, 400 on the first batch).
170
189
 
171
- Each batch page uses offset pagination on the filtered collection. Later batches can slow down on very large tables; narrowing filters or raising `batch_size` within `max_batch_size` reduces batch count.
190
+ When the freeze table exists, the first batch stores filtered primary keys in NULL-safe order (RFC-0003). Later batches walk those positions and join live cells. Inserts after freeze are omitted. Updates after freeze appear. Deleted freeze ids are skipped. Without the table, each chunk continues after the last returned sort key and primary key (RFC-0002) and is not a point-in-time snapshot. Custom `order_by` expressions fall back to primary key descending. NULL sort keys sort last in both directions.
172
191
 
173
- JSON and XML exports use the same column definitions as `csv` blocks. JSON batches return arrays of row objects; the client merges them into one array. XML batches return record fragments; the client wraps them in a single `<export>` root. Shapes differ from ActiveAdmin synchronous JSON/XML downloads.
192
+ JSON and XML exports use the same column definitions as `csv` blocks. JSON batches return arrays of row objects; the client concatenates those arrays as text into one array. XML batches return record fragments; the client wraps them in a single `<export>` root. Shapes differ from ActiveAdmin synchronous JSON/XML downloads.
174
193
 
175
194
  Authorization follows ActiveAdmin `download_links` and `authorize!` on the resource. Disable a format with `index download_links: [:csv]` (or `false` to hide exports). Batch endpoints reject formats not listed on the resource index presenter.
176
195
 
@@ -182,10 +201,11 @@ From the gem root:
182
201
  bundle install
183
202
  bundle exec appraisal install
184
203
  bundle exec rubocop
204
+ make test-javascript
185
205
  bundle exec polyrun parallel-rspec --workers 5 --merge-failures
186
206
  ```
187
207
 
188
- Matrixed Rails versions use [Appraisal](https://github.com/thoughtbot/appraisal): `gemfiles/rails72.gemfile`, `rails8ruby34.gemfile`, and `rails8truffleruby.gemfile`. Run `bundle exec appraisal rspec` to execute RSpec in each gemfile context.
208
+ Matrixed Rails versions use [Appraisal](https://github.com/thoughtbot/appraisal): `gemfiles/rails72.gemfile` and `rails8ruby34.gemfile`. Run `bundle exec appraisal rspec` to execute RSpec in each gemfile context.
189
209
 
190
210
  Shared agent guidance is managed with [pray](https://github.com/kiskolabs/pray) via `Prayfile`.
191
211
 
@@ -195,6 +215,19 @@ Shared agent guidance is managed with [pray](https://github.com/kiskolabs/pray)
195
215
 
196
216
  See [CONTRIBUTING.md](CONTRIBUTING.md). Bug reports and pull requests are welcome at https://github.com/amkisko/activeadmin_batched_export.rb/issues
197
217
 
218
+ ## Links
219
+
220
+ - [GitHub](https://github.com/amkisko/activeadmin_batched_export.rb)
221
+ - [GitLab](https://gitlab.com/amkisko/activeadmin_batched_export.rb)
222
+ - [RubyGems](https://rubygems.org/gems/activeadmin_batched_export)
223
+ - [Versions Atom](https://rubygems.org/gems/activeadmin_batched_export/versions.atom) (feed id `11574013576629`)
224
+ - [libraries.io](https://libraries.io/rubygems/activeadmin_batched_export)
225
+ - [Deps.dev](https://deps.dev/rubygems/activeadmin_batched_export)
226
+ - [SonarCloud](https://sonarcloud.io/project/overview?id=amkisko_activeadmin_batched_export.rb)
227
+ - [Snyk](https://snyk.io/test/github/amkisko/activeadmin_batched_export.rb)
228
+ - [Codecov](https://app.codecov.io/github/amkisko/activeadmin_batched_export.rb)
229
+ - [OpenSSF Scorecard](https://scorecard.dev/viewer/?uri=github.com/amkisko/activeadmin_batched_export.rb)
230
+
198
231
  ## License
199
232
 
200
233
  MIT — see [LICENSE.md](LICENSE.md).
data/SECURITY.md CHANGED
@@ -2,27 +2,24 @@
2
2
 
3
3
  ## Reporting a Vulnerability
4
4
 
5
- Do NOT open a public GitHub issue for security vulnerabilities.
6
-
7
5
  Email security details to: security@kiskolabs.com
8
6
 
9
- Include: description, steps to reproduce, potential impact, and suggested fix (if available).
7
+ Send the report only to that address. Include description, steps to reproduce, potential impact, and a suggested fix when you have one.
10
8
 
11
9
  ### Response Timeline
12
10
 
13
- - We will acknowledge receipt of your report
14
- - We will provide an initial assessment
15
- - We will keep you informed of our progress and resolution timeline
11
+ - We will acknowledge receipt of your report.
12
+ - We will provide an initial assessment.
13
+ - We will keep you informed of our progress and resolution timeline.
16
14
 
17
15
  ### Disclosure Policy
18
16
 
19
- - We will work with you to understand and resolve the issue
20
- - We will credit you for the discovery (unless you prefer to remain anonymous)
21
- - We will publish a security advisory after the vulnerability is patched
22
- - We will coordinate public disclosure with you
17
+ - We will work with you to understand and resolve the issue.
18
+ - We will credit you for the discovery unless you prefer to remain anonymous.
19
+ - We will publish a security advisory after the vulnerability is patched.
20
+ - We will coordinate public disclosure with you.
23
21
 
24
22
  ## Automation Security
25
23
 
26
- * Context Isolation: It is strictly forbidden to include production credentials, API keys, or Personally Identifiable Information (PII) in prompts sent to third-party LLMs or automation services.
27
-
28
- * Supply Chain: All automated dependencies must be verified.
24
+ - Keep production credentials, API keys, and personal data out of prompts sent to third-party models or automation services.
25
+ - Verify automated dependencies.
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "Replaces long-lived ActiveAdmin index downloads with a batched export workspace, customizable views, and export column macros."
13
13
  spec.license = "MIT"
14
14
  spec.platform = Gem::Platform::RUBY
15
- spec.required_ruby_version = ">= 3.2.0"
15
+ spec.required_ruby_version = ">= 3.4"
16
16
 
17
17
  repository_url = "https://github.com/amkisko/activeadmin_batched_export.rb"
18
18
 
@@ -63,5 +63,5 @@ Gem::Specification.new do |spec|
63
63
  spec.add_development_dependency "standard-performance", "~> 1.8"
64
64
  spec.add_development_dependency "standard-rails", "~> 1.5"
65
65
  spec.add_development_dependency "standard-rspec", "~> 0.3"
66
- spec.add_development_dependency "rbs", "~> 3"
66
+ spec.add_development_dependency "rbs", "~> 4"
67
67
  end