Skip to content

Dataset Scheming Form Pages [OPEN-4034]#1582

Open
wardi wants to merge 28 commits intomasterfrom
OPEN-4034-form-pages
Open

Dataset Scheming Form Pages [OPEN-4034]#1582
wardi wants to merge 28 commits intomasterfrom
OPEN-4034-form-pages

Conversation

@wardi
Copy link
Copy Markdown
Member

@wardi wardi commented Jun 13, 2025

split dataset type into separate pages using scheming form pages and dataset completeness feature

@wardi wardi force-pushed the OPEN-4034-form-pages branch from 1432f66 to 7b9b271 Compare August 19, 2025 01:18
@wardi
Copy link
Copy Markdown
Member Author

wardi commented Jan 30, 2026

@JVickery-TBS this is working for me now since open-data/ckan#214 was merged. See also @RabiaSajjad 's CSS changes in #1633 that makes more room for form page tabs by moving the side bar above the content.

@JVickery-TBS
Copy link
Copy Markdown
Contributor

Had to do some more css and template stuff, mainly for the Add Resource in Draft part. and then some small screen stuff.

Have to do a couple more to polish this up. But this is in staging and working fairly well now.

@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 21, 2026

❌ 6 Tests Failed:

Tests completed Failed Passed Skipped
229 6 223 0
View the top 3 failed test(s) by shortest run time
ckanext/canada/tests/test_validators.py::TestNAVLSchema::test_raw_required
Stack Traces | 0.384s run time
self = <ckanext.canada.tests.test_validators.TestNAVLSchema object at 0x7fa1e3aa2760>

    def test_raw_required(self):
        raw_pkg = dict(self.complete_pkg)
        del raw_pkg['title_translated']
    
        with pytest.raises(ValidationError) as ve:
>           self.normal_action.package_create(**raw_pkg)
E           Failed: DID NOT RAISE <class 'ckan.logic.ValidationError'>

.../canada/tests/test_validators.py:215: Failed
ckanext/canada/tests/test_logic.py::TestResourcePositionLogic::test_delete_resource_assigns_positions
Stack Traces | 0.866s run time
self = <ckanext.canada.tests.test_logic.TestResourcePositionLogic object at 0x7f1136fe92b0>

    def test_delete_resource_assigns_positions(self):
        """
        Deleting a Resource from a package should reorder the other
        Resources properly, and set the deleted position to 0.
        """
        pkg = self.sysadmin_action.package_create(
            name='44cefde8-7cce-defc-1234-56789abcd34c',
            resources=[self.res_dict, self.res_dict, self.res_dict,
                       self.res_dict, self.res_dict, self.res_dict],
            **self.pkg_dict)
    
        assert len(pkg['resources']) == 6
        assert pkg['resources'][0]['position'] == 0
        assert pkg['resources'][1]['position'] == 1
        assert pkg['resources'][2]['position'] == 2
        assert pkg['resources'][3]['position'] == 3
        assert pkg['resources'][4]['position'] == 4
        assert pkg['resources'][5]['position'] == 5
    
        deleted_res_id = pkg['resources'][2]['id']
    
        self.sysadmin_action.resource_delete(
            id=deleted_res_id)
    
        pkg = self.sysadmin_action.package_show(id=pkg['id'])
    
        assert len(pkg['resources']) == 5
        assert pkg['resources'][0]['position'] == 0
        assert pkg['resources'][1]['position'] == 1
        assert pkg['resources'][2]['position'] == 2
        assert pkg['resources'][3]['position'] == 3
        assert pkg['resources'][4]['position'] == 4
        for r in pkg['resources']:
            assert r['id'] != deleted_res_id
    
        res = model.Resource.get(deleted_res_id)
    
        assert res.id == deleted_res_id
>       assert res.position == 0
E       assert None == 0
E        +  where None = <Resource id=d6242734-7db4-4403-a0a0-e1c33d9e346d package_id=a94629a6-e61e-468f-bbd0-201f0c1af79f url=http://www.annakarenina.com/download/ format=TXT description=None hash= position=None name=None resource_type=dataset mimetype=None mimetype_inner=None size=42 created=1994-01-01 00:00:01 last_modified=1994-01-01 00:00:01 metadata_modified=1994-01-01 00:00:01 cache_url=None cache_last_updated=None url_type=None extras={'data_quality': '[]', 'language': '["zxx"]', 'name_translated': '{"en": "Full text.", "fr": "Full text."}'} state=deleted>.position

.../canada/tests/test_logic.py:472: AssertionError
ckanext/canada/tests/test_webforms.py::TestPackageWebForms::test_new_dataset_required_fields
Stack Traces | 9.38s run time
self = <ckanext.canada.tests.test_webforms.TestPackageWebForms object at 0x7f8075ada250>
app = <ckan.tests.helpers.CKANTestApp object at 0x7f80763a8100>

    @mock.patch.object(h, 'flash_success', flashes.mock_flash)
    @mock.patch.object(h, 'get_flashed_messages', flashes.mock_get_flashed_messages)
    @mock.patch.object(h, 'is_registry_domain', mock_is_registry_domain)
    def test_new_dataset_required_fields(self, app):
        dataset_id = 'f3e4adb9-6e32-4cb4-bf68-1eab9d1288f5'
    
        offset = h.url_for('dataset.new')
        response = app.get(offset, extra_environ=self.extra_environ_tester,
                           environ_overrides=self.environ_overrides_tester)
    
        assert 'Create Dataset' in response.body
        assert 'Before you can create a dataset you need to create an organization' not in response.body
    
        response = app.post(offset,
                            data=self._filled_dataset_form(dataset_id),
                            extra_environ=self.extra_environ_tester,
                            environ_overrides=self.environ_overrides_tester,
                            follow_redirects=False)
    
        offset = _get_relative_offset_from_response(response)
        response = app.get(offset, extra_environ=self.extra_environ_tester,
                           environ_overrides=self.environ_overrides_tester)
    
>       assert 'Add data to the dataset' in response.body
E       assert 'Add data to the dataset' in '\n  <!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="ImJkODg3MWVkNTQ1YTIwMTg0MzM1OTM0MzA3MDQ0OGYzNDY5MjAwMWQi.acBwMg.-wBdY0e9p1McAfOr_L4pdav-SYY" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="\n    Edit Draft Open Data Record:&nbsp;english title\n  \n - CKAN">\n  \n  \n    \n  \n\n    <title>\n    Edit Draft Open Data Record:&nbsp;english title\n  \n - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    \n  \n    \n    \n  \n  <script src="https://www.canada.ca/etc/desig...  $(document).ready(function(){\n            if (navigator.appName == \'Microsoft Internet Explorer\' ||\n            !!(navigator.userAgent.match(/Trident/) || navigator.userAgent.match(/rv:11/)) ||\n            (typeof $.browser !== "undefined" && $.browser.msie == 1))\n            {\n              let ieWarning = document.getElementById("ie_warning");\n              if( ieWarning.length > 0 ){\n                $(ieWarning).show();\n              }\n            }\n          });\n        });\n      </script>\n    \n  \n\n  <script nonce="Z9u8JC0hlWCJCMJGYLLUEd">\n    window.addEventListener(\'load\', function(){\n      $(document).ready(function(){\n        let select2Fields = $(\'[data-field-select2="True"]\');\n        if( select2Fields.length > 0 ){\n          $(select2Fields).each(function(_index, _select2Field){\n            $(_select2Field).select2();\n          });\n        }\n      });\n    });\n  </script>\n\n  \n\n      <div role="region"><strong>TEST TEMPLATE_FOOTER_END TEST</strong></div>\n\n    \n    \n    \n    <script src="....../webassets/ckanext-scheming/079217e5_scheming_subfields.js" type="text/javascript" nonce="Z9u8JC0hlWCJCMJGYLLUEd"></script>\n  </body>\n</html>'
E        +  where '\n  <!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="ImJkODg3MWVkNTQ1YTIwMTg0MzM1OTM0MzA3MDQ0OGYzNDY5MjAwMWQi.acBwMg.-wBdY0e9p1McAfOr_L4pdav-SYY" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="\n    Edit Draft Open Data Record:&nbsp;english title\n  \n - CKAN">\n  \n  \n    \n  \n\n    <title>\n    Edit Draft Open Data Record:&nbsp;english title\n  \n - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    \n  \n    \n    \n  \n  <script src="https://www.canada.ca/etc/desig...  $(document).ready(function(){\n            if (navigator.appName == \'Microsoft Internet Explorer\' ||\n            !!(navigator.userAgent.match(/Trident/) || navigator.userAgent.match(/rv:11/)) ||\n            (typeof $.browser !== "undefined" && $.browser.msie == 1))\n            {\n              let ieWarning = document.getElementById("ie_warning");\n              if( ieWarning.length > 0 ){\n                $(ieWarning).show();\n              }\n            }\n          });\n        });\n      </script>\n    \n  \n\n  <script nonce="Z9u8JC0hlWCJCMJGYLLUEd">\n    window.addEventListener(\'load\', function(){\n      $(document).ready(function(){\n        let select2Fields = $(\'[data-field-select2="True"]\');\n        if( select2Fields.length > 0 ){\n          $(select2Fields).each(function(_index, _select2Field){\n            $(_select2Field).select2();\n          });\n        }\n      });\n    });\n  </script>\n\n  \n\n      <div role="region"><strong>TEST TEMPLATE_FOOTER_END TEST</strong></div>\n\n    \n    \n    \n    <script src="....../webassets/ckanext-scheming/079217e5_scheming_subfields.js" type="text/javascript" nonce="Z9u8JC0hlWCJCMJGYLLUEd"></script>\n  </body>\n</html>' = <WrapperTestResponse 32778 bytes [200 OK]>.body

.../canada/tests/test_webforms.py:80: AssertionError
ckanext/canada/tests/test_webforms.py::TestPackageWebForms::test_new_dataset_missing_fields
Stack Traces | 10.8s run time
self = <ckanext.canada.tests.test_webforms.TestPackageWebForms object at 0x7f3d93c08d00>
app = <ckan.tests.helpers.CKANTestApp object at 0x7f3d93d43220>

    @mock.patch.object(h, 'is_registry_domain', mock_is_registry_domain)
    def test_new_dataset_missing_fields(self, app):
        dataset_id = 'f3e4adb9-6e32-4cb4-bf68-1eab9d1288f4'
    
        offset = h.url_for('dataset.new')
        response = app.get(offset, extra_environ=self.extra_environ_tester,
                           environ_overrides=self.environ_overrides_tester)
    
        assert 'Create Dataset' in response.body
        assert 'Before you can create a dataset you need to create an organization' not in response.body
    
        incomplete_dataset_form = {
            'id': dataset_id,
            'save': '',
            '_ckan_phase': '1',
        }
        response = app.post(offset,
                            data=incomplete_dataset_form,
                            extra_environ=self.extra_environ_tester,
                            environ_overrides=self.environ_overrides_tester,
                            follow_redirects=True)
    
>       assert 'Errors in form' in response.body
E       assert 'Errors in form' in '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="ImFkNGJhMDI1N2JmMDE3MjYwNTkzZjlkMzZlYWM0ZTVkZWZiNmQxMTEi.acBwgg.YgxlUbmhdJjuH70THNOOj_BqMPs" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 404 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 404 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    \n  \n    \n    \n  \n  <script src="https://www.canada..../cdts/compiled/soyutils.js" integrity="sha384-hfwnpowMIP7hDqCMoNULlqSq7k2nu8R...d06kpBf21XdHoEGaAx\');\n    newWetFooterString += _style.outerHTML;\n  });\n  const wetFooterObjLinks = wetFooterDOC.querySelectorAll(\'link\');\n  wetFooterObjLinks.forEach(function(_link){\n    _link.setAttribute(\'nonce\', \'XQ4nd06kpBf21XdHoEGaAx\');\n    newWetFooterString += _link.outerHTML;\n  });\n  document.write(newWetFooterString);\n  \n</script>\n  \n  \n    \n      \n    \n  \n  \n  \n  \n    \n  \n  \n    \n\n  \n\n  \n      <script nonce="XQ4nd06kpBf21XdHoEGaAx">\n        window.addEventListener(\'load\', function(){\n          $(document).ready(function(){\n            if (navigator.appName == \'Microsoft Internet Explorer\' ||\n            !!(navigator.userAgent.match(/Trident/) || navigator.userAgent.match(/rv:11/)) ||\n            (typeof $.browser !== "undefined" && $.browser.msie == 1))\n            {\n              let ieWarning = document.getElementById("ie_warning");\n              if( ieWarning.length > 0 ){\n                $(ieWarning).show();\n              }\n            }\n          });\n        });\n      </script>\n    \n  \n\n      <div role="region"><strong>TEST TEMPLATE_FOOTER_END TEST</strong></div>\n\n    \n    \n    \n    \n  </body>\n</html>'
E        +  where '<!DOCTYPE html><!--[if lt IE 9]>\n  <html class="no-js lt-ie9" lang="en" dir="ltr"><![endif]--> <!--[if gt IE 8]><!-->\n  <html class="no-js" lang="en" dir="ltr"> <!--<![endif]-->\n  <head>\n    \n  <meta charset="utf-8" />\n      <meta name="csrf_field_name" content="_csrf_token" />\n      <meta name="_csrf_token" content="ImFkNGJhMDI1N2JmMDE3MjYwNTkzZjlkMzZlYWM0ZTVkZWZiNmQxMTEi.acBwgg.YgxlUbmhdJjuH70THNOOj_BqMPs" />\n\n      <meta name="generator" content="ckan 2.10.8" />\n      <meta name="viewport" content="width=device-width, initial-scale=1.0">\n  \n    <meta property="og:title" content="Error 404 - CKAN">\n  \n  \n    \n  \n\n    <title>Error 404 - CKAN</title>\n\n    \n    \n  <link rel="shortcut icon" href="https://www.canada..../wet-boew/assets/favicon.ico" />\n    \n  \n    \n    \n    \n  \n  \n  \n\n  \n  \n      \n      \n      \n    \n  \n\n  \n\n\n    \n      \n      <link rel="stylesheet" href="TEST_TEMPLATE_HEAD_END.css" type="text/css">\n    \n\n    \n    \n  \n    \n    \n  \n  <script src="https://www.canada..../cdts/compiled/soyutils.js" integrity="sha384-hfwnpowMIP7hDqCMoNULlqSq7k2nu8R...d06kpBf21XdHoEGaAx\');\n    newWetFooterString += _style.outerHTML;\n  });\n  const wetFooterObjLinks = wetFooterDOC.querySelectorAll(\'link\');\n  wetFooterObjLinks.forEach(function(_link){\n    _link.setAttribute(\'nonce\', \'XQ4nd06kpBf21XdHoEGaAx\');\n    newWetFooterString += _link.outerHTML;\n  });\n  document.write(newWetFooterString);\n  \n</script>\n  \n  \n    \n      \n    \n  \n  \n  \n  \n    \n  \n  \n    \n\n  \n\n  \n      <script nonce="XQ4nd06kpBf21XdHoEGaAx">\n        window.addEventListener(\'load\', function(){\n          $(document).ready(function(){\n            if (navigator.appName == \'Microsoft Internet Explorer\' ||\n            !!(navigator.userAgent.match(/Trident/) || navigator.userAgent.match(/rv:11/)) ||\n            (typeof $.browser !== "undefined" && $.browser.msie == 1))\n            {\n              let ieWarning = document.getElementById("ie_warning");\n              if( ieWarning.length > 0 ){\n                $(ieWarning).show();\n              }\n            }\n          });\n        });\n      </script>\n    \n  \n\n      <div role="region"><strong>TEST TEMPLATE_FOOTER_END TEST</strong></div>\n\n    \n    \n    \n    \n  </body>\n</html>' = <WrapperTestResponse 8977 bytes [404 NOT FOUND]>.body

.../canada/tests/test_webforms.py:116: AssertionError
View the full list of 2 ❄️ flaky test(s)
ckanext/canada/tests/test_validators.py::TestNAVLSchema::test_basic_package

Flake rate in main: 8.70% (Passed 63 times, Failed 6 times)

Stack Traces | 0.331s run time
self = <ckanext.canada.tests.test_validators.TestNAVLSchema object at 0x7f3d9486fc10>

    def test_basic_package(self):
        with pytest.raises(ValidationError) as ve:
>           self.normal_action.package_create(
                name='12345678-9abc-def0-1234-56789abcdef0',
                **self.incomplete_pkg)
E           Failed: DID NOT RAISE <class 'ckan.logic.ValidationError'>

.../canada/tests/test_validators.py:123: Failed
ckanext/canada/tests/test_validators.py::TestNAVLSchema::test_validation_schema

Flake rate in main: 7.14% (Passed 26 times, Failed 2 times)

Stack Traces | 0.051s run time
self = <ckanext.canada.tests.test_validators.TestNAVLSchema object at 0x7f35b2a3ee80>

    def test_validation_schema(self):
        "creating a resource with a URL schema should empty the schema"
>       pkg = self.sysadmin_action.package_create(**self.complete_pkg)

.../canada/tests/test_validators.py:366: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
.../ckanapi/ckanapi/common.py:60: in action
    return self._ckan.call_action(name, data_dict=kwargs)
.../ckanapi/ckanapi/localckan.py:74: in call_action
    return self._get_action(action)(context, data_dict)
.../ckan/logic/__init__.py:581: in wrapped
    result = _action(context, data_dict, **kw)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

context = {'__auth_audit': [], '__auth_user_obj_checked': True, 'auth_user_obj': <User id=333488d6-18f0-4a89-819a-a74ae699a68a n...hotos/440/883 plugin_extras=None>, 'model': <module 'ckan.model' from '.../ckan/model/__init__.py'>, ...}
data_dict = {'collection': 'primary', 'date_published': '2013-01-01', 'frequency': 'as_needed', 'imso_approval': 'true', ...}

    def package_create(
            context: Context, data_dict: DataDict) -> ActionResult.PackageCreate:
        '''Create a new dataset (package).
    
        You must be authorized to create new datasets. If you specify any groups
        for the new dataset, you must also be authorized to edit these groups.
    
        Plugins may change the parameters of this function depending on the value
        of the ``type`` parameter, see the
        :py:class:`~ckan.plugins.interfaces.IDatasetForm` plugin interface.
    
        :param name: the name of the new dataset, must be between 2 and 100
            characters long and contain only lowercase alphanumeric characters,
            ``-`` and ``_``, e.g. ``'warandpeace'``
        :type name: string
        :param title: the title of the dataset (optional, default: same as
            ``name``)
        :type title: string
        :param private: If ``True`` creates a private dataset
        :type private: bool
        :param author: the name of the dataset's author (optional)
        :type author: string
        :param author_email: the email address of the dataset's author (optional)
        :type author_email: string
        :param maintainer: the name of the dataset's maintainer (optional)
        :type maintainer: string
        :param maintainer_email: the email address of the dataset's maintainer
            (optional)
        :type maintainer_email: string
        :param license_id: the id of the dataset's license, see
            :py:func:`~ckan.logic.action.get.license_list` for available values
            (optional)
        :type license_id: license id string
        :param notes: a description of the dataset (optional)
        :type notes: string
        :param url: a URL for the dataset's source (optional)
        :type url: string
        :param version: (optional)
        :type version: string, no longer than 100 characters
        :param state: the current state of the dataset, e.g. ``'active'`` or
            ``'deleted'``, only active datasets show up in search results and
            other lists of datasets, this parameter will be ignored if you are not
            authorized to change the state of the dataset (optional, default:
            ``'active'``)
        :type state: string
        :param type: the type of the dataset (optional),
            :py:class:`~ckan.plugins.interfaces.IDatasetForm` plugins
            associate themselves with different dataset types and provide custom
            dataset handling behaviour for these types
        :type type: string
        :param resources: the dataset's resources, see
            :py:func:`resource_create` for the format of resource dictionaries
            (optional)
        :type resources: list of resource dictionaries
        :param tags: the dataset's tags, see :py:func:`tag_create` for the format
            of tag dictionaries (optional)
        :type tags: list of tag dictionaries
        :param extras: the dataset's extras (optional), extras are arbitrary
            (key: value) metadata items that can be added to datasets, each extra
            dictionary should have keys ``'key'`` (a string), ``'value'`` (a
            string)
        :type extras: list of dataset extra dictionaries
        :param plugin_data: private package data belonging to plugins.
            Only sysadmin users may set this value. It should be a dict that can
            be dumped into JSON, and plugins should namespace their data with the
            plugin name to avoid collisions with other plugins, eg::
    
                {
                    "name": "test-dataset",
                    "plugin_data": {
                        "plugin1": {"key1": "value1"},
                        "plugin2": {"key2": "value2"}
                    }
                }
        :type plugin_data: dict
        :param relationships_as_object: see :py:func:`package_relationship_create`
            for the format of relationship dictionaries (optional)
        :type relationships_as_object: list of relationship dictionaries
        :param relationships_as_subject: see :py:func:`package_relationship_create`
            for the format of relationship dictionaries (optional)
        :type relationships_as_subject: list of relationship dictionaries
        :param groups: the groups to which the dataset belongs (optional), each
            group dictionary should have one or more of the following keys which
            identify an existing group:
            ``'id'`` (the id of the group, string), or ``'name'`` (the name of the
            group, string),  to see which groups exist
            call :py:func:`~ckan.logic.action.get.group_list`
        :type groups: list of dictionaries
        :param owner_org: the id of the dataset's owning organization, see
            :py:func:`~ckan.logic.action.get.organization_list` or
            :py:func:`~ckan.logic.action.get.organization_list_for_user` for
            available values. This parameter can be made optional if the config
            option :ref:`ckan.auth.create_unowned_dataset` is set to ``True``.
        :type owner_org: string
    
        :returns: the newly created dataset (unless 'return_id_only' is set to True
                  in the context, in which case just the dataset id will
                  be returned)
        :rtype: dictionary
    
        '''
        model = context['model']
        user = context['user']
    
        if 'type' not in data_dict:
            package_plugin = lib_plugins.lookup_package_plugin()
            try:
                # use first type as default if user didn't provide type
                package_type = package_plugin.package_types()[0]
            except (AttributeError, IndexError):
                package_type = 'dataset'
                # in case a 'dataset' plugin was registered w/o fallback
                package_plugin = lib_plugins.lookup_package_plugin(package_type)
            data_dict['type'] = package_type
        else:
            package_plugin = lib_plugins.lookup_package_plugin(data_dict['type'])
    
        schema: Schema = context.get(
            'schema') or package_plugin.create_package_schema()
    
        _check_access('package_create', context, data_dict)
    
        if 'api_version' not in context:
            # check_data_dict() is deprecated. If the package_plugin has a
            # check_data_dict() we'll call it, if it doesn't have the method we'll
            # do nothing.
            check_data_dict = getattr(package_plugin, 'check_data_dict', None)
            if check_data_dict:
                try:
                    check_data_dict(data_dict, schema)
                except TypeError:
                    # Old plugins do not support passing the schema so we need
                    # to ensure they still work
                    package_plugin.check_data_dict(data_dict)
    
        data, errors = lib_plugins.plugin_validate(
            package_plugin, context, data_dict, schema, 'package_create')
        log.debug('package_create validate_errs=%r user=%s package=%s data=%r',
                  errors, context.get('user'),
                  data.get('name'), data_dict)
    
        if errors:
            model.Session.rollback()
>           raise ValidationError(errors)
E           ckan.logic.ValidationError: None - {'resources': [{'id': ['Resource id already exists.']}]}

.../logic/action/create.py:203: ValidationError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

- Additional layout changes for the sidebar stages/pages.
@JVickery-TBS
Copy link
Copy Markdown
Contributor

@wardi sooo I think the HTML and CSS stuff is done, the issue (idk if its an issue or not) is that if you Add a Resource when making a dataset with missing fields, it will still created the Resource, assuming you have put all the fields in correctly. But the dataset will still be draft. I think thats fine? The specific issue is that in our schemas we have a required metadata field with the same id as a resource metadata field. So if you miss the dataset one, the error may popup on your Resource form.

- Fix stages sidebar template call for pd types.
- Fix a11y issues in the webform pages.
@JVickery-TBS JVickery-TBS changed the title OPEN-4034: form pages for dataset type Dataset Scheming Form Pages [OPEN-4034] Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants