{"id":19175572,"url":"https://github.com/senaite/senaite.app.listing","last_synced_at":"2026-04-07T16:01:21.069Z","repository":{"id":37981255,"uuid":"169101610","full_name":"senaite/senaite.app.listing","owner":"senaite","description":"ReactJS listing component for SENAITE CORE","archived":false,"fork":false,"pushed_at":"2026-04-03T04:59:02.000Z","size":8921,"stargazers_count":7,"open_issues_count":0,"forks_count":21,"subscribers_count":4,"default_branch":"2.x","last_synced_at":"2026-04-03T12:58:24.205Z","etag":null,"topics":["coffeescript","lims","plone","reactjs","senaite","webpack"],"latest_commit_sha":null,"homepage":null,"language":"CoffeeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/senaite.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-02-04T15:39:58.000Z","updated_at":"2026-04-03T04:59:04.000Z","dependencies_parsed_at":"2026-03-26T11:03:26.905Z","dependency_job_id":null,"html_url":"https://github.com/senaite/senaite.app.listing","commit_stats":{"total_commits":268,"total_committers":3,"mean_commits":89.33333333333333,"dds":"0.19029850746268662","last_synced_commit":"2dcccb044cb3f497c64ee96ab7b98ff3816e77af"},"previous_names":["senaite/senaite.core.listing"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/senaite/senaite.app.listing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senaite%2Fsenaite.app.listing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senaite%2Fsenaite.app.listing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senaite%2Fsenaite.app.listing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senaite%2Fsenaite.app.listing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/senaite","download_url":"https://codeload.github.com/senaite/senaite.app.listing/tar.gz/refs/heads/2.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/senaite%2Fsenaite.app.listing/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31518642,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T03:10:19.677Z","status":"ssl_error","status_checked_at":"2026-04-07T03:10:13.982Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["coffeescript","lims","plone","reactjs","senaite","webpack"],"created_at":"2024-11-09T10:23:59.833Z","updated_at":"2026-04-07T16:01:21.040Z","avatar_url":"https://github.com/senaite.png","language":"CoffeeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n  \u003ca href=\"https://github.com/senaite/senaite.app.listing\"\u003e\n    \u003cimg src=\"static/logo.png\" alt=\"senaite.app.listing\" height=\"128\" /\u003e\n  \u003c/a\u003e\n\n  \u003cp\u003eReactJS powered listing tables for SENAITE LIMS\u003c/p\u003e\n\n  \u003cdiv\u003e\n    \u003ca href=\"https://pypi.python.org/pypi/senaite.app.listing\"\u003e\n      \u003cimg src=\"https://img.shields.io/pypi/v/senaite.app.listing.svg?style=flat-square\" alt=\"pypi-version\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://travis-ci.org/senaite/senaite.app.listing\"\u003e\n      \u003cimg src=\"https://img.shields.io/travis/senaite/senaite.app.listing.svg?style=flat-square\" alt=\"travis-ci\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/senaite/senaite.app.listing/pulls\"\u003e\n      \u003cimg src=\"https://img.shields.io/github/issues-pr/senaite/senaite.app.listing.svg?style=flat-square\" alt=\"open PRs\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/senaite/senaite.app.listing/issues\"\u003e\n      \u003cimg src=\"https://img.shields.io/github/issues/senaite/senaite.app.listing.svg?style=flat-square\" alt=\"open Issues\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"#\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square\" alt=\"pr\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.senaite.com\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/Made%20for%20SENAITE-%E2%AC%A1-lightgrey.svg\" alt=\"Made for SENAITE\" /\u003e\n    \u003c/a\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\n## About\n\nThis package provides a [ReactJS](https://reactjs.org) based\nlisting tables for [SENAITE LIMS](https://www.senaite.com).\n\n[ReactJS](https://reactjs.org/) is a declarative, efficient, and flexible\nJavaScript library for building user interfaces built by\n[Facebook](https://github.com/facebook/react) and is licensed under the [MIT\nLicense](https://github.com/facebook/react/blob/master/LICENSE)\n\n\n## Screenshots\n\nThis section shows some screenshots how `senaite.app.listing` looks like.\n\n\n### Samples Listing\n\n\u003cimg src=\"static/1_samples_listing.png\" alt=\"Samples Listing\" /\u003e\n\n\n### Worksheet Classic Listing\n\n\u003cimg src=\"static/2_worksheet_classic_listing.png\" alt=\"Worksheet Classic Listing\" /\u003e\n\n\n### Worksheet Transposed Listing\n\n\u003cimg src=\"static/3_worksheet_transposed_listing.png\" alt=\"Worksheet Transposed Listing\" /\u003e\n\n\n### Clients Listing\n\n\u003cimg src=\"static/4_clients_listing.png\" alt=\"Clients Listing\" /\u003e\n\n\n## Adapting Listings\n\nIn most cases, adding a subscriber adapter for `IListingView` is enough to\nextend a given listing with additional columns, status or even behavior. With\nthe subscriber approach, a given listing can be modified multiple times by same\nor different add-ons, without the need of inheritance and dependency bindings\namongst them. More information here: https://docs.zope.org/zope.interface/adapter.html#subscriptions\n\nFor instance, imagine you have two independent add-ons (A and B),\nwith the following use-case:\n\n- A adds a column \"DateStored\" in Samples listing, along with filter \"Stored\"\n- B adds a column \"Participant\" in Samples listing, along with filter \"Ordered\"\n- Both changes are displayed in the result listing when A and B are installed\n\nMaking B dependent on A or the other way round is not a solution. With\nsubscriber adapters, we can address this problem easily as follows:\n\n### 1. Create a subscriber adapter for each add-on\n\nThe skeleton of the subscriber adapter may look like follows:\n\n```python\nfrom bika.lims import api\nfrom senaite.app.listing.interfaces import IListingView\nfrom senaite.app.listing.interfaces import IListingViewAdapter\nfrom senaite.app.listing.utils import add_column\nfrom senaite.app.listing.utils import add_review_state\nfrom zope.component import adapts\nfrom zope.component import implements\n\n\nclass SamplesListingViewAdapter(object):\n    adapts(IListingView)\n    implements(IListingViewAdapter)\n\n    def __init__(self, listing, context):\n        self.listing = listing\n        self.context = context\n\n    def before_render(self):\n        # Add new column for all available states\n        states = map(lambda r: r[\"id\"], self.listing.review_states)\n        add_column(\n            listing=self.listing,\n            column_id=\"MyColumn\",\n            column_values={\n                \"title\": \"My new column\",\n                \"sortable\": False,\n            },\n            review_states=states)\n\n    def folder_item(self, obj, item, index):\n        item[\"MyColumn\"] = api.get_object(obj).getMyColumnValue()\n        return item\n```\n\n### 2. Register the subscriber adapter in configure.zcml\n\nThe next thing is to tell the system to use this adapter when the context is an\n`AnalysisRequestFolder` object and the listing view is `AnalysisRequestsView`.\nWe assume here you created the subscriber adapter inside a `samples.py` file and\nthe configure.zcml is in that same directory:\n\n```\n  \u003c!-- Samples view with additional filters and columns --\u003e\n  \u003csubscriber\n    for=\"bika.lims.browser.analysisrequest.AnalysisRequestsView\n         bika.lims.interfaces.IAnalysisRequestsFolder\"\n    provides=\"senaite.app.listing.interfaces.IListingViewAdapter\"\n    factory=\".samples.SamplesListingViewAdapter\"\n  /\u003e\n```\n\nNote that `AnalysisRequestsView` (from `senaite.core`) inherits from\n`senaite.app.listing`'s `ListingView`, that in turn implements `IListingView`.\n\n\n## Development\n\nThis package uses [webpack](https://webpack.js.org) to bundle all assets for the\nfinal JavaScript file.\n\nUsed libraries:\n\n    - ReactJS https://reactjs.org/\n\n\n### Prerequisites\n\nYou need `node` and `npm` and `yarn` installed:\n\n    » node --version\n    v18.10.0\n\n    » node --version\n    8.19.2\n\n    » yarn --version\n    1.21.1\n\n\n### Installation of JS Dependencies\n\nUse `yarn` (or `npm`) to install the develoment dependencies:\n\n    » cd webpack\n    » yarn install\n\nThis creates a local node_modules directory where all the dependencies are stored.\n\n\nYou can now run `webpack` locally:\n\n    » node_modules/.bin/webpack\n\nPrint usage (output below is cutted):\n\n    » node_modules/.bin/webpack --help\n\n    webpack: 5.69.1\n    webpack-cli 4.9.2\n    Usage: https://webpack.js.org/api/cli/\n    Usage without config file: webpack \u003centry\u003e [\u003centry\u003e] --output [-o] \u003coutput\u003e\n\n    Initialization:\n    --init             Initializes a new webpack configuration or loads a\n                        addon if specified                                [boolean]\n\n    Basic options:\n    --watch, -w  Watch the filesystem for changes                        [boolean]\n    -d           shortcut for --debug --devtool eval-cheap-module-source-map\n                --output-pathinfo                                       [boolean]\n    -p           shortcut for --optimize-minimize --define\n\n\n### Building the Project for Production/Development\n\nThe following script commands which can be executed by the `npm run` command are\nlocated in `package.json`.\n\nThe configuration for the used `webpack` command is located in `webpack.config.js`.\n\n\nRun this command to watch/rebuild the JavaScript for Development:\n\n    » yarn watch\n\nRun this command to build the final JavaScript for Production:\n\n    » yarn build\n\n\n## License\n\n**SENAITE.APP.LISTING** Copyright (C) RIDING BYTES \u0026 NARALABS\n\nThis program is free software; you can redistribute it and/or modify it under\nthe terms of the [GNU General Public License version\n2](https://github.com/senaite/senaite.app.listing/blob/master/LICENSE)\nas published by the Free Software Foundation.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsenaite%2Fsenaite.app.listing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsenaite%2Fsenaite.app.listing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsenaite%2Fsenaite.app.listing/lists"}