Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Admin Tools App #389

Open
goztrk opened this issue Sep 26, 2023 · 0 comments
Open

Admin Tools App #389

goztrk opened this issue Sep 26, 2023 · 0 comments

Comments

@goztrk
Copy link
Contributor

goztrk commented Sep 26, 2023

Problem

Each project requires some Admin page that has specific tools to only project admins/operators.
Up until now we were building separate pages for each project with same base operations which causes repetitive tasks - doing same thing over and over again.

Requirements

  • Same look, feel on every project.
  • Following aspects should be develop in a way that it should be very easy to implement on the project side:
    • Listing records: A Table with the support of pagination, sorting, filtering, searching
    • Actions column on tables: If a list requires some operations, it should have an actions column
    • Record info page
    • Record edit page

Solution

Thought process

Feel free to modify this. I am throwing what comes to my mind freely.
My goal is to achieve ability to create new tools without needing to write any React app in a fast pace.
This feature will be only usable by admins and operators so there is no need to worry about being UI perfect.

Entry point view

  • URL Path must be r'/admintools(/.*?)?' and it must be last item in urlpatterns.
  • Should be single.
  • Guarded with @company_employee_required decorator
  • Template should not extend from project base.html. Must act like a separate thing.
  • Template should load React application which will operate as SPA (Single Page Application)

API endpoints:

  • URL Path must be r'/admintools/api/...'
  • A config end point for React app should be exists: r'/admintools/api/app_config'

React App should automatically generate pages, navigation menu items from config and incoming JSON data for specific pages.

Idea for ADMIN_TOOL_LINKS

@dataclass
class AdminToolLinkGroup:
    name: str
    icon: str
    links: List[AdminToolLink]

    def add_link(self, link: AdminToolLink):
        link.group = self
        self.links.append(link)

    def json_encode(self):
        # Standard converting to dict operation

@dataclass
class AdminToolLink:
    name: str
    group: Optional[AdminToolLinkGroup]
    icon: str
    view_type: str   # Type of page. Table list, info page or edit/create form
    api_url: str  # Most pages requires a API endpoint to interract

    @property
    def link(self):
        # An util function encode string to URL safe string
        url = f'{self.group.name}/{self.name}' if self.group else self.name
        value = f'{ADMIN_TOOL_ROOT_URL}/{url}'
        return value

    def json_encode(self):
        # standart converting to dict operation

Another Idea for admintools wrap url function of Django when adding new API end points:

admintools_api_url will add extra params to a global variable and will return url() function of Django as a result.
app_config view will use this global variable to build paths and send to page.

urlpatterns = [
    admintools_api_url(
        r'^some_url$',
        views.SomeAPI.as_view(),
        name='some_url',
        icon='fas fa-user',
        group_name='Users',
        page_type='list',   # Instead of this, the page type can be sent with `OPTIONS` HTTP method?
        # Whatever needed for React side
    ),
]

Idea for app_config endpoint:

@company_employee_required
def api_config(request):
    # Or maybe make it generatable from API endpoints?
    from admintools.constants.links import ADMIN_TOOLS_LINKS

    paths = generate_paths(ADMIN_TOOLS_LINKS)

    response = json_response_okay({
        'paths': paths
        # Other needed information like current user info
        # a boolean variable to determine to show django-admin link
    })
    return response

In the React root component: config will be fetched, paths will be used for:

  • Generating routes for react-router
  • Generating dashboard links
  • Generating navigation links
  • Generating sidebar links for groups

Idea for listing records:
Every decision should be made in API endpoint. React should generate the table using variables provided from API JSON response

# Sample JSON response that should be generated from API
response = json_response_okay({
    'header_columns': [
        {
            'slug': 'id',
            'name': 'ID',
            'sortable': true,
            'filterable': true,
        },
        {
            'slug': 'created_at',
            'name': 'Registration Date',
            'sortable': true,
            'filterable': true,
            'cast': 'date',  # will use `new Date(date).toLocaleDateString()` in JS side
        },
        # ...
    ],
    'item_actions': [
        {
            'icon': 'fas fa-pencil',
            'operation': 'link',
            'url': '/admintools/users/{id}',
            'url_replace': 'id',  # can be omitted or set to `False` if not wanted
        },
        {
            'icon': 'fas fa-trash',
            'operation': 'delete',  # This will generate a link with a confirm modal
            'url': '/admintools/api/users/{id}',
            'url_replace': 'id'  # can be omitted or set to `False` if not wanted
        },
    ],
    'data': [],
    'total_count': 0,
    'page': 1,
    'page_size': 1,
    'total_pages': 1,
})

Idea for record editing:
Validation schema should also be provided from API end point:

# When a form page opens, React will request information on form using 'OPTIONS' HTTP method
# Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS

# OPTIONS response:
response = json_response_okay({
    'fields': [
        {
            'name': 'username',
            'label': 'Username',
            'field': 'text-input',
            validation: []   # This should be something that we can convert to `zod` validation schema.
        },
    ],
})

Then the end point GET method should provide the values if its an edit page. If it is a create page either React should not make a API call or API endpoint should return an empty JSON.

API Endpoint Structure

Each API endpoint must have OPTIONS HTTP method defined. When React app gets table-list as type it should make another request to same endpoint with GET HTTP method to fetch the data.

OPTIONS call can be cached and can be re-used as long as React App keeps opened.

class SomeAPI(AdminToolsBaseAPI):
    def options(self, request):
        # This method should be inside `AdminToolsBaseAPI` it can be overridden if necessary
        response = json_response_okay({
            'type': 'table-list',  # Other options are: info, upsert (a general term used to do update or insert operations)
            # Some other options needed to build the page...
        })
        return response

Tools to use for React

  • MUI because it looks nice, easy. Developing components with it also easy.
  • react-router for building routes
  • zod validation NPM package. Works very good with TypeScript
  • conform to integrate zod schemas to React forms.
  • TypeScript for better error catching
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

No branches or pull requests

1 participant