This extension is no longer maintained.
You can use https://github.com/keitaroinc/ckanext-issues instead
CKAN Issues Extension
Home Page: https://github.com/ckan/ideas-and-roadmap/issues/4
License: MIT License
This extension is no longer maintained.
You can use https://github.com/keitaroinc/ckanext-issues instead
All admins & editors. But for only configured sample of publishers, while we test it out.
I get these errors trying to run both the postgres and sqlite test.
Any idea?
# nosetests --ckan --with-pylons=test.ini -v --with-id ckanext/issues --with-coverage --cover-package=ckanext.issues --nologcapture
Traceback (most recent call last):
File "/usr/lib/ckan/default/bin/nosetests", line 11, in <module>
sys.exit(run_exit())
File "/usr/lib/ckan/default/lib/python2.7/site-packages/nose/core.py", line 121, in __init__
**extra_args)
File "/usr/lib64/python2.7/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/nose/core.py", line 145, in parseArgs
self.config.configure(argv, doc=self.usage())
File "/usr/lib/ckan/default/lib/python2.7/site-packages/nose/config.py", line 347, in configure
self.plugins.begin()
File "/usr/lib/ckan/default/lib/python2.7/site-packages/nose/plugins/manager.py", line 99, in __call__
return self.call(*arg, **kw)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/nose/plugins/manager.py", line 167, in simple
result = meth(*arg, **kw)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/pylons/test.py", line 74, in begin
relative_to=path)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/paste/deploy/loadwsgi.py", line 247, in loadapp
return loadobj(APP, uri, name=name, **kw)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/paste/deploy/loadwsgi.py", line 272, in loadobj
return context.create()
File "/usr/lib/ckan/default/lib/python2.7/site-packages/paste/deploy/loadwsgi.py", line 710, in create
return self.object_type.invoke(self)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/paste/deploy/loadwsgi.py", line 146, in invoke
return fix_call(context.object, context.global_conf, **context.local_conf)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/paste/deploy/util.py", line 58, in fix_call
reraise(*exc_info)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/paste/deploy/compat.py", line 23, in reraise
exec('raise t, e, tb', dict(t=t, e=e, tb=tb))
File "/usr/lib/ckan/default/lib/python2.7/site-packages/paste/deploy/util.py", line 55, in fix_call
val = callable(*args, **kw)
File "/usr/lib/ckan/default/src/ckan/ckan/config/middleware/__init__.py", line 46, in make_app
load_environment(conf, app_conf)
File "/usr/lib/ckan/default/src/ckan/ckan/config/environment.py", line 99, in load_environment
p.load_all()
File "/usr/lib/ckan/default/src/ckan/ckan/plugins/core.py", line 129, in load_all
unload_all()
File "/usr/lib/ckan/default/src/ckan/ckan/plugins/core.py", line 182, in unload_all
unload(*reversed(_PLUGINS))
File "/usr/lib/ckan/default/src/ckan/ckan/plugins/core.py", line 210, in unload
plugins_update()
File "/usr/lib/ckan/default/src/ckan/ckan/plugins/core.py", line 121, in plugins_update
environment.update_config()
File "/usr/lib/ckan/default/src/ckan/ckan/config/environment.py", line 267, in update_config
engine = sqlalchemy.engine_from_config(config, client_encoding='utf8')
File "/usr/lib/ckan/default/lib/python2.7/site-packages/sqlalchemy/engine/__init__.py", line 366, in engine_from_config
return create_engine(url, **options)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/sqlalchemy/engine/__init__.py", line 344, in create_engine
return strategy.create(*args, **kwargs)
File "/usr/lib/ckan/default/lib/python2.7/site-packages/sqlalchemy/engine/strategies.py", line 144, in create
engineclass.__name__))
TypeError: Invalid argument(s) 'client_encoding' sent to create_engine(), using configuration SQLiteDialect_pysqlite/NullPool/Engine. Please check that the keyword arguments are appropriate for this combination of components.; got ({'__file...an'}, apikey_header_name=..., auth.blacklist=..., beaker.session.key=..., beaker.session.secret=..., cache_dir=..., carrot_messaging_library=..., ckan.activity_list_limit=..., ckan.activity_streams_email_notifications=..., ckan.auth.anon_create_dataset=..., ckan.auth.create_dataset_if_not_in_organization=..., ckan.auth.create_unowned_dataset=..., ckan.auth.create_user_via_api=..., ckan.auth.create_user_via_web=..., ckan.auth.roles_that_cascade_to_sub_groups=..., ckan.auth.user_create_groups=..., ckan.auth.user_create_organizations=..., ckan.auth.user_delete_groups=..., ckan.auth.user_delete_organizations=..., ckan.cache_enabled=..., ckan.cache_validation_enabled=..., ckan.datapusher.formats=..., ckan.datapusher.url=..., ckan.datasets_per_page=..., ckan.datastore.read_url=..., ckan.datastore.write_url=..., ckan.extra_resource_fields=..., ckan.legacy_templates=..., ckan.locale_default=..., ckan.locale_order=..., ckan.locales_filtered_out=..., ckan.plugins=..., ckan.redis.url=..., ckan.simple_search=..., ckan.site_description=..., ckan.site_id=..., ckan.site_logo=..., ckan.site_title=..., ckan.site_url=..., ckan.storage_path=..., ckan.template_footer_end=..., ckan.template_head_end=..., ckan.tests.functional.test_cache.TestCacheBasics.test_get_cache_expires.expires=..., ckan.tests.functional.test_cache.expires=..., ckan.tracking_enabled=..., ckanext.issues.send_email_notifications=..., ckanext.stats.cache_enabled=..., debug=..., full_stack=..., licenses_group_url=..., package_edit_return_url=..., package_form=..., package_new_return_url=..., search_backend=..., smtp.mail_from=..., smtp.test_server=..., solr_url=..., sqlalchemy.url=..., testing=..., who.config_file=..., who.log_file=..., who.log_level=...), wanted (conf, full_stack=True, static_files=True, **app_conf)
I am testing the extension on a CKAN 2.3 based instance. When I open the page of a particular dataset that does not have any extras I get Internal Server Error 500. Here the log:
Error - <type 'exceptions.TypeError'>: 'NoneType' object is not iterable
URL: http://192.168.33.10:8081/dataset/community_fishery_kh
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/weberror/errormiddleware.py', line 162 in __call__
app_iter = self.application(environ, sr_checker)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/dec.py', line 147 in __call__
resp = self.call_func(req, *args, **self.kwargs)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/dec.py', line 208 in call_func
return self.func(req, *args, **kwargs)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/fanstatic/publisher.py', line 234 in __call__
return request.get_response(self.app)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/request.py', line 1053 in get_response
application, catch_exc_info=False)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/request.py', line 1022 in call_application
app_iter = application(self.environ, start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/dec.py', line 147 in __call__
resp = self.call_func(req, *args, **self.kwargs)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/dec.py', line 208 in call_func
return self.func(req, *args, **kwargs)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/fanstatic/injector.py', line 54 in __call__
response = request.get_response(self.app)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/request.py', line 1053 in get_response
application, catch_exc_info=False)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/webob/request.py', line 1022 in call_application
app_iter = application(self.environ, start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/beaker/middleware.py', line 73 in __call__
return self.app(environ, start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/beaker/middleware.py', line 155 in __call__
return self.wrap_app(environ, session_start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/routes/middleware.py', line 131 in __call__
response = self.app(environ, start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 125 in __call__
response = self.dispatch(controller, environ, start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/pylons/wsgiapp.py', line 324 in dispatch
return controller(environ, start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/lib/base.py', line 338 in __call__
res = WSGIController.__call__(self, environ, start_response)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 221 in __call__
response = self._dispatch_call()
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 172 in _dispatch_call
response = self._inspect_call(func)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 107 in _inspect_call
result = self._perform_call(func, args)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/pylons/controllers/core.py', line 60 in _perform_call
return func(**args)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/controllers/package.py', line 424 in read
extra_vars={'dataset_type': package_type})
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/lib/base.py', line 217 in render
loader_class=loader_class)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/pylons/templating.py', line 249 in cached_template
return render_func()
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/lib/base.py', line 155 in render_template
return render_jinja2(template_name, globs)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/lib/base.py', line 104 in render_jinja2
return template.render(**extra_vars)
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/jinja2/environment.py', line 894 in render
return self.environment.handle_exception(exc_info, True)
File '/home/vagrant/.virtualenvs/ckan/src/ckanext-odm_theme/ckanext/odm_theme/templates/package/read.html', line 9 in top-level template code
{% do image_resources.append(resource) %}
File '/home/vagrant/.virtualenvs/ckan/src/ckanext-issues/ckanext/issues/templates/package/read_base.html', line 1 in top-level template code
{% ckan_extends "package/read_base.html" %}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/package/read_base.html', line 1 in top-level template code
{% extends "package/base.html" %}
File '/home/vagrant/.virtualenvs/ckan/src/ckanext-odm_theme/ckanext/odm_theme/templates/package/base.html', line 5 in top-level template code
{% set is_library_orga = h.odm_theme_get_in_library() %}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/page.html', line 1 in top-level template code
{% extends "base.html" %}
File '/home/vagrant/.virtualenvs/ckan/src/ckanext-odm_theme/ckanext/odm_theme/templates/base.html', line 103 in top-level template code
{%- block page %}{% endblock -%}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/page.html', line 19 in block "page"
{%- block content %}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/page.html', line 22 in block "content"
{% block main_content %}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/page.html', line 57 in block "main_content"
{% block primary %}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/page.html', line 70 in block "primary"
{% block primary_content %}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/page.html', line 72 in block "primary_content"
{% block page_header %}
File '/home/vagrant/.virtualenvs/ckan/local/lib/python2.7/site-packages/ckan/templates/page.html', line 80 in block "page_header"
{% block content_primary_nav %}{% endblock %}
File '/home/vagrant/.virtualenvs/ckan/src/ckanext-issues/ckanext/issues/templates/package/read_base.html', line 5 in block "content_primary_nav"
{% if h.issues_enabled(pkg) %}
File '/home/vagrant/.virtualenvs/ckan/src/ckanext-issues/ckanext/issues/lib/helpers.py', line 98 in issues_enabled
for extra in extras:
TypeError: 'NoneType' object is not iterable
Analizing the code, i see that on https://github.com/okfn/ckanext-issues/blob/master/ckanext/issues/lib/helpers.py#L97
extras = dataset.get('extras')
is returning None for that particular dataset
When I assign an issue to someone it is still showing the ASSIGNEE as "No one" for logged out users.
If the details are not going to be shown for security reasons then it should probably not display the ASSIGNEE section at all.
datagovuk is maintaining this repo over on their fork, and rather than them hassling okfn as they have several times in the past to merge their changes, I'm wondering if now okfn have finished their paid-for work they should pass the repo to the CKAN community to continue development in a new home at github.com/ckan? The problem is that while it lives in okfn that will be the default home everyone where everyone will look. There are two other forks off okfn's potentially dead mainline, rather than the live datagovuk one. Users are raising issues and pull-requests that are ignored on okfn's one. I think it would be better to move this repo to http://github.com/ckan/ckanext-issues and datagovuk take over official responsibility for it.
Thoughts @rgrp?
The table creation command
paster --plugin=ckanext-issues issues init_db -c ckan.ini
is missing from the instructions at http://extensions.ckan.org/extension/issues/
Your code suggests you've got Issue defined in the base model somehow. Is this a new ckan feature? (We run ckan 2.2 at the moment)
Module ckanext.issues.controller.controller:421 in all_issues_page view
>> func.count(model.Issue.id).label('issue_count'),
AttributeError: 'module' object has no attribute 'Issue'
An issues and all its comments say "Owner" if the user looking at them is able to edit the issue (can_edit_issue). I just don't see the logic or usefulness of that.
IMO it should work like Github where it says "Owner" if the author of the specific issue or comment is/was an editor/admin/sysadmin.
I'm getting this error on CKAN 2.41 - TemplateNotFound: Template issues/dataset.html cannot be found
We have pages for dataset issues, organization issues, and now we want to also have 'all issues'. A page for sysadmins and other interested members of the public. Allows you to get a sense of how many issues, what sorts (tags) are popular etc. Otherwise they are effectively siloed.
Maybe could be combined with the organization issues page, with the org being a facet.
To allow sites to customise
Because I've seen the database schema I can see why only the top box on a page with lots of comments is editable - but for a user it would be confusing.
It would be good to either implement comment editing or change the UI slightly to emphasise that the top box shows the original issue and subsequent boxes show comments.
I wanted to express my view of how moderation should work, based on how we have it in Drupal at DGU, although I've not done much moderation myself. (I'm aware that we've not established this as a minimum necessary thing, but want to chart a direction if it does go into scope.)
We have:
So when a new issue or comment comes in, our 'spam logic' decide it is:
And in the future we could add more tests, like for strong language, or bayesian (e.g. Mollom) which could add more info like issue.mollom_verdict=True/False/not_sure and our 'spam logic' might make a different decision and make visible=False, so a moderator would have to make it visible again if it was genuine.
At this point a moderator could come along and browse latest issues/comments and point out any that are spam or not, setting the is_spam field and therefore .visible reflects that.
Another user could say it looks like spam, and we add a line to spam_reports. If a second user does this and the moderator has not said anything, then our 'spam_logic' would decide to change visible=False.
Again the moderator comes along to the "moderate issues/comments" page. This would be a faceted view or maybe a few tabs. Perhaps the highest priority for him to look at are those in the 'grey area' - had one spam report, or mollum said its not sure, or there are other indicators we can add later, like strong language. Then next you might check for false positives, since there might only be a few of those, e.g. a flurry incorrect spam_reports - people ganging up on someone. And then you might want to scan through the dozens of comments in case you can spot any spam. Ideally by the end he'd mark all as is_spam=True/False, so they wouldn't be shown when he next does a batch of moderation. However there is a chance that he'll want to rereview stuff in the past, so I'd think it is useful to have them available if necessary. Hence me suggesting facets / tabs.
The 'spam_logic' should be replaceable, to be more or less defensive and rely on more clues that become available, e.g. if bayesian is available, or take a dim view of particular email providerts, or location of the IP address etc.
Are issues not included in the Dashboard and User Activity Stream by design?
Whilst there is a more extensive bit of work to have some auto-moderation logic and monitor how it is doing: #27 , before then it would be helpful to just be able to manually view issues & comments and manually moderate.
The moderator comes along to the "moderate issues/comments" page. Doesn't need facets or tabs. Just a single list of all issues and comments, showing all the user-input fields, to scan through and spot the spam. Then with a single click a moderator can mark any issue/comment as spam.
Hi,
I do not see in the code a mecanism for string translation. Do you plan on adding it ? Can we contribute to the project by adding this possibility ? In that cas what would be your prefered system ?
In a suitable location for the new ckan HTML templates
(from memory)
It should take the user to the login screen, and after logging in they should be taken back to the dataset they wanted to add todo items to.
When installing and activating the ckanext-issues plugin on a ckan 2.5.2 site there seems to be a configuration issue.
All form submission (add issue, comment on issue) led to a server error 500
For exemple :
https://www.datalocale.fr/dataset/liste-des-activites-de-pratique-equestre-en-aquitaine/
https://www.datalocale.fr/dataset/liste-des-activites-de-pratique-equestre-en-aquitaine/issues/new
Is this an identified issue ? :)
When you assign an issue to user then they get an email.
I believe that the "mark comment as spam" storage needs to be unique to the user, rather than storing it as issue.spam_state (i.e. you can't identify it per user).
As it is currently, other users see whether someone else has marked it as spam, which I believe is confusing.
This is how I see it working:
When Alice clicks "notify" then it should display "notified as abuse" on the issue/comment. (The user can also come back to the same page later and click an [x] to cancel the notification.) When Bob views the issue/comment then it displays as normal. If Bob then clicks "notify" then because that's a second person then the issue becomes hidden - maybe it still displays to him and Alice, or maybe it disappears for them too and Bob gets a flash message telling him "notified as abuse".
When we have moderation #27 , any issue/comment that has one or more people having pressed "notify" for it, goes into the moderation queue for the sysadmin.
Some CKAN instances might want to restrict the access to the Issue information to only certain user roles. Im thinking about scenarios such as:
For this, a new variable could be added to the configuration file (suggestion ckanext.issues.minimun_role_required) which allows to specify the minimum role required for users to access the Issues information both on the Web UI and API. Possible values would be:
The installation command failed with
ERROR: Could not detect requirement name for 'git+http://github.com/ckan/ckanext-issues', please specify one with #egg=your_package_name
System details:
OS: ubuntu 18.04
Python: 2.7.15rc1
It possibly should be:
pip install -e git+https://github.com/ckan/ckanext-issues.git#egg=ckanext-issues
I installed following instructions in a vanilla instance of CKAN 2.2, and got the following error:
File "/usr/lib/ckan/default/local/lib/python2.7/site-packages/ckanext/issues/model.py", line 9, in <module>
from ckan.model.meta import types, Table, ForeignKey, DateTime
ImportError: cannot import name types
Missing dependency?
Use jQuery UI buttons and forms, remove code that is no longer needed now that we're using jQuery UI
At /dataset/{name}/issues/{issue-id}
It's weird when you go to a dataset and the issues are numbered 3, 46 & 105. Even accounting for some closed issues, it suggests there have been over 100 issues in total for the dataset. It rubs with the commonly assumed mental model of a dataset having issues starting at 1.
The directory name/module name, the plugin name, etc. etc.
Each issue has a list of users who get (email) notifications for it. When you create an issue, make a comment or are assigned then you get added to this list. You can manually add/remove yourself too.
Email notifications are a key way to draw people into issues. And by making it possible for users to stop the notifications, it gives the system the moral right to send them some emails in the first place.
I see this as really helpful when a member of the public raises an issue on an organization's dataset. Rather than automatically assign that org's admins/editors to the dataset (you can only have one assignee anyway), you could just add the org's admins/editors to the notifications list so that they hear about it. Then one could assign it to themselves to deal with, and that helps the user to see something is happening.
When you create an issue it shows the 'resource' box. This doesn't do anything yet, but I believe the intention was so that you could raise the issue against a specific resource in the dataset. I quite like that idea, but for the time being can it just be hidden until it is implemented?
e.g. /dataset/air-quality-monitoring-2014/issues
Module ckanext.issues.controller.home:39 in _search_issues view
>> issues = toolkit.get_action('issue_search')(data_dict=params)
Module ckan.logic:425 in wrapped view
>> result = _action(context, data_dict, **kw)
Module ckan.logic:556 in wrapper view
>> return action(context, data_dict)
Module ckan.logic:523 in wrapper view
>> data_dict, errors = _validate(data_dict, schema, context)
Module ckan.lib.navl.dictization_functions:234 in validate view
>> converted_data, errors = _validate(flattened, schema, context)
Module ckan.lib.navl.dictization_functions:295 in _validate view
>> convert(converter, key, converted_data, errors, context)
Module ckan.lib.navl.dictization_functions:204 in convert view
>> value = converter(converted_data.get(key), context)
Module ckanext.issues.logic.validators.validators:19 in is_valid_sort view
>> return issuemodel.IssueFilter[filter_string]
TypeError: 'type' object has no attribute '__getitem__'
Is it because you are using a different enum library? There was none specified in the setup.py, so I just tried 'pip install enum' and it doesn't seem to like access using [].
There doesn't seem great visual integration of a dataset's issues tab.
The issues tab appears:
but when you click on it the tab concept disappears:
And its also disorienting that the dataset name is no longer displayed at the top of the sidebar, like it is in all the other tabs. Of course it is in the breadcrumbs, but I don't think that is enough.
I don't really care about the UI as DGU doesn't use it, but just logging it as an issue for others really
some database indexes should be added to the columns that are filtered on, especially if there is a large number of issues.
There is confusion in the terminology. Is it spam or abuse? If you click "Report abuse" then you get flash message "Notified as spam" and on the issue it says "Marked as spam" and you filter for it using "Spam state visible". Choose one way of describing it and stick to it. Same goes for the code.
There are separate problems here - I consider spam as generally automated garbage. These would be banned. However genuine users occasionally cross the line and advertise, use swear words or are vicious to other users, and we'd want to remove their comment - I'd call that abuse. You could say that spam is also abuse, so maybe we should simply call it 'abuse' everywhere instead of 'spam'?
BTW I believe that the "mark comment as spam" storage needs to be unique to the user, rather than storing it as issue.spam_state for all users. I don't understand why other users would want to see whether someone else has marked it as spam. Then once 2 users have marked a comment as spam, then we have some logic that makes the comment invisible for non-admins (as you have it). When an admin marks it as spam then we believe them and change the state to 'deleted'. An admin needs to be able to see those marked by non-admins as spam and choose whether to say if it is ok or indeed spam. So how about we call what non-admins do as 'reporting comments to admins' (say it is 'reported to admins'), and what admins do is 'confirm abuse' or 'confirm not-abuse'.
This extension provides some rather important functionality IMHO.
@davidread As the latest commits for this extension date from 2017:
Is it still maintained and are there any deployments out there?
This helps with discoverability, and also enables Discourse oneboxing, e.g.
https://talk.beta.nyc/t/data-beta-nyc-ckan-customizations/773/2
e.g. show the dataset name
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.