v.0.17

2023.04.03

The package shimoku-api-python is no longer maintained

To get the new version 🤖

pip install --upgrade shimoku-api-python

This is a major version that comes with a new module and a whole new infrastructure!

Improvements

  • Annotated Chart - A new type of chart has been added! This chart allows users to interactively change their data across a timeline. In the frontend, users can click inside the chart to display a modal with options to add a point or two to the timeline, as well as add an annotation for that point.

    The chart requires a separate dataset for each series to plot, and it needs the y-field-name specified for each of them. All datasets must have the same name for the x-field and for the annotations field. The x-field values must be of type Date or convertible to it, the y-field must be integers, and the annotation field values must be strings.

    The modal that appears includes a slider to select the value that the user wants to add. This can be configured with the slider_config parameter, where the max value can be defined, and also the defaultValue. Labels can be added to the slider values using the slider_marks parameter.

    An example on how to use it would be:

    data1 = [
        {'date': '2022-01-01', 'Value [1]': 3},
        {'date': '2022-03-01', 'Value [1]': 7, 'Annotation': 'Value [1] rapid increase'},
        {'date': '2022-04-01', 'Value [1]': 7},
        {'date': '2022-07-01', 'Value [1]': 8},
        {'date': '2022-08-01', 'Value [1]': 9},
        {'date': '2022-12-01', 'Value [1]': 5},
    ]
    data2 = [
        {'date': '2021-12-31', 'Value [2]': 6},
        {'date': '2022-01-02', 'Value [2]': 9},
        {'date': '2022-02-01', 'Value [2]': 7},
        {'date': '2022-03-01', 'Value [2]': 8},
        {'date': '2022-04-01', 'Value [2]': 9},
        {'date': '2022-05-01', 'Value [2]': 7},
        {'date': '2022-06-01', 'Value [2]': 8, 'Annotation': 'Value [2] oscillation'},
        {'date': '2022-07-01', 'Value [2]': 9},
        {'date': '2022-08-01', 'Value [2]': 8},
    ]
    
    s.plt.annotated_chart(
        menu_path='Annotated Chart',
        order=7, x='date', y=['Value [1]', 'Value [2]'], annotation='Annotation',
        data=[data1, data2], slider_config={'max': 100, 'defaultValue': 50},
        slider_marks=[('Low', 15), ('Medium', 50), ('High', 85)]
    )

    resulting in:

    When clicking in the chart the modal appears like so:

    It lets the user select a date range and the value of the point. Also it lets the user write an annotation in the bottom text field.

    If we use the following values:

    The result in the chart is:

  • Before getting the logs of an activities run was done in a very cumbersome way, now it has a dedicated method:

    s.activity.get_run_logs(
        menu_path: str, 
        activity_name: str, 
        run_id: str
    ) -> Dict

  • A new module has been added that introduces a new navigation element: dashboards! A dashboard is an element that groups apps together and it will show as the first path element in the sidebar:

    This new element not only serves as an extended hierarchy, but it also permits a lot of new features, one of the most flashy ones being dashboards embedding, which in the future will permit inserting public dashboards in external pages.

    The module provides the following methods:

    # Sets the business for the whole module
    s.dashboard.set_business(business_id: str)
    
    # Creates a dashboard and return it's dictionary representation
    s.dashboard.create_dashboard(
        dashboard_name: str, order: Optional[int] = None, 
        public_permission: Optional[Dict] = None, is_disabled: bool = False
    ) -> Dict
    
    # Gets a dashboard, if the dashboard does not exit it returns None
    s.dashboard.get_dashboard(
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None
    ) -> Optional[Dict]
    
    # Deletes the specified dashboard, if it exists
    s.dashboard.delete_dashboard(
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None
    )
    
    # Updates the specified dashboard fields, if it exists
    s.dashboard.update_dashboard(
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None,
        name: Optional[str] = None, order: Optional[int] = None,
        public_permission: Optional[str] = None, is_disabled: Optional[bool] = None
    )
    
    # Adds an app to a specified dashboard, this creates a link object
    s.dashboard.add_app_in_dashboard(
        app_id: str, dashboard_name: Optional[str] = None,
        dashboard_id: Optional[str] = None
    )
    
    # Gets all the business dashboards
    s.dashboard.get_dashboards() -> List[Dict]
    
    # Gets all the app_id's for a specified dashboard
    s.dashboard.get_dashboard_app_ids(
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None
    ) -> List[str]
    
    # Deletes the link between a given app and a given dashboard
    s.dashboard.remove_app_from_dashboard(
        app_id: str, dashboard_name: Optional[str] = None,
        dashboard_id: Optional[str] = None
    )
    
    # Deletes all business dashboards, id any dashboard has apps it returns an error
    s.dashboard.delete_all_business_dashboards()

    When referencing a dashboard, it can be done by its name or by its UUID. That's why all functions have optional parameters for the dashboard's name or its ID, but one of them must be provided, or an error will be returned.

    The module is useful for managing dashboards at a low level, in case some customization is needed or more information is required, but the most common use case is through the plotting module, which takes care of the apps' inclusion in dashboards automatically. For an app to be seen, it needs to be included in a dashboard, so if the user does not specify which dashboard to use, the SDK will take the name of the app being created and add the app to the dashboard: {app_name} dashboard.

    To specify the dashboard's name, the plotting module provides the method:

                         s.plt.set_dashboard(dashboard_name: str)

    This way, all apps created through the plotting module after calling this method will be included in the same dashboard.

    An example on how to use this function is:

    s.plt.set_dashboard('Dashboard groupping apps')
    data_ = {
            "footer": "Hello random people",
            "header": "True",
            "val": "359K",
            "alignment": "left",
            "icon": "Line/subscriptions",
            "color": "warning"
    }
    
    s.plt.indicator(
        data=data_,
        menu_path='SubGroup 1/sublevel 1',
        order=14,
        value='val',
        header='header',
        footer='footer',
        align='alignment',
        icon='icon',
        color='color',
        rows_size=1, cols_size=4,
    )
    
    s.plt.indicator(
        data=data_,
        menu_path='SubGroup 2/sublevel 1',
        order=14,
        value='val',
        header='header',
        footer='footer',
        align='alignment',
        icon='icon',
        color='color',
        rows_size=1, cols_size=4,
    )

    The result is:

    It is possible that when using the set_dashboard function the dashboard name is not show correctly in the sidebar, that might be because the code is reusing a previous app which allready belonged to a dashboard. The SDK will only create a dashboard when the app is being created so when an app is modified the dashboard will have the same name, to solve this we present two options:

    • One way would be deleting the app (or app link) of the created app and then deleting the dashboard, because dashboards with apps can not be deleted. The fastest way would be to use:

      s.app.delete_all_business_apps()
      s.dashboard.delete_all_business_dashboards()

      This way you can delete all contents of a business, in case your business has lots of apps or dashboards. Beware of deleting apps with activities, as it will return an error.

    • The other way would be to rename the dashboard, with the update function:

      s.dashboard.update_dashboard(
          dashboard_name=previous_dashboard_name, name=new_dashboard_name
      )

  • New methods to manage roles have been added! A role can be created from the SDK and can be later added to the desired users, providing a customization level to the platform's security. Some users might have restricted access to business apps, while others may have access to data modifications or activity executions.

    The roles can be managed from the following modules:

    s.app, s.dashboard, s.business

    The module from which the method is called will define the level of permission that the user with that role will have. If a user is granted a superior level of permission, they will have access to the lower levels too.

    The fields of the role object and it's permited values are:

    • 'role': str (it's the role's name)

      • 'permission': ['READ', 'WRITE']

      • 'target': ['GROUP', 'USER']

      • 'resource': ['DATA', 'DATA_EXECUTION', 'USER_MANAGEMENT', 'BUSINESS_INFO']

    Each module has the following methods:

    • Business:

      s.business.create_role(
          business_id: str, role_name: str, 
          resource: Optional[str] = None, permission: Optional[str] = None, 
          target: Optional[str] = None
      )
      s.business.get_roles(business_id: str)
      s.business.get_roles_by_name(business_id: str, role_name: str)
      s.business.delete_role(business_id: str, role_id: str)

    • Dashboard:

      (The dashboards can be referenced either by name or id)

      s.dashboard.create_role(
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None,
        resource: Optional[str] = None, role_name: Optional[str] = None,
        permission: Optional[str] = None, target: Optional[str] = None
      )
      s.dashboard.get_roles(
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None
      )
      s.business.get_roles_by_name(role_name: str, 
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None
      )
      s.business.delete_role(role_id: str, 
        dashboard_name: Optional[str] = None, dashboard_id: Optional[str] = None
      )

    • App:

      s.app.create_role(
          business_id: str, app_id: str,
          role_name: str, resource: Optional[str] = None, 
          permission: Optional[str] = None, target: Optional[str] = None
      )
      s.app.get_roles(business_id: str, app_id: str)
      s.app.get_roles_by_name(business_id: str, app_id: str, role_name: str)
      s.app.delete_role(business_id: str, app_id: str, role_id: str)

    An example on how to create, read and delete a role using the dashboards module is:

    dashboard_name = 'roles_dashboard'
    s.dashboard.create_dashboard(dashboard_name=dashboard_name)
    
    role = s.dashboard.create_role(dashboard_name=dashboard_name, role_name='test_role')
    
    assert role['role'] == 'test_role'
    assert role['permission'] == 'READ'
    assert role['resource'] == 'BUSINESS_INFO'
    assert role['target'] == 'GROUP'
    
    roles = s.dashboard.get_roles(dashboard_name=dashboard_name)
    
    assert len(roles) == 1
    assert roles[0]['role'] == 'test_role'
    
    s.dashboard.delete_role(dashboard_name=dashboard_name, role_id=role['id'])
    
    assert len(s.dashboard.get_roles(dashboard_name=dashboard_name)) == 0
    
    s.dashboard.create_role(
        dashboard_name=dashboard_name, 
        role_name='test_role', permission='WRITE',
        resource='DATA', target='USER'
    )

Last updated