{"id":30144145,"url":"https://github.com/icerockdev/admin-toolkit","last_synced_at":"2025-08-11T07:38:18.991Z","repository":{"id":42165333,"uuid":"250431121","full_name":"icerockdev/admin-toolkit","owner":"icerockdev","description":"Toolkit to create admin panels - part of BOKO libs","archived":false,"fork":false,"pushed_at":"2023-01-27T00:56:33.000Z","size":17457,"stargazers_count":6,"open_issues_count":15,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-05-07T05:04:00.729Z","etag":null,"topics":["admin","administration","frontend","material-ui","mobx","react"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/icerockdev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-27T03:29:36.000Z","updated_at":"2023-09-08T18:05:06.000Z","dependencies_parsed_at":"2023-02-15T03:46:05.489Z","dependency_job_id":null,"html_url":"https://github.com/icerockdev/admin-toolkit","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/icerockdev/admin-toolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fadmin-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fadmin-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fadmin-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fadmin-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/icerockdev","download_url":"https://codeload.github.com/icerockdev/admin-toolkit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icerockdev%2Fadmin-toolkit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269849595,"owners_count":24485153,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-11T02:00:10.019Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["admin","administration","frontend","material-ui","mobx","react"],"created_at":"2025-08-11T07:38:16.045Z","updated_at":"2025-08-11T07:38:18.973Z","avatar_url":"https://github.com/icerockdev.png","language":"TypeScript","readme":"# IceRock Development Admin Toolkit\n\nThis is a tool for building admin panels, that can be installed as npm dependency.\n\n[DEMO](https://icerockdev.github.io/admin-toolkit/ 'DEMO')\n\n## Installation\n`yarn add icerockdev-admin-toolkit`\n\nor\n\n`npm i -S icerockdev-admin-toolkit`\n\n## Usage\n```typescript\nimport React from 'react';\nimport { Application } from 'admin-toolkit';\nimport config from './config';\n\nexport const App = () =\u003e \u003cApplication config={config} /\u003e;\n```\n\n## Config\nThe app is built on extendable classes. You can write your own autherntification by extending AuthProvider class. Creating complex pages should be made by extending Page class.\n\n```typescript\nconst config = new Config({\n  logo: '', // logo url\n  auth: new AuthProvider(authProviderOptions),\n  pages: [new Page(pageOptions), new Entity(entityOptions)],\n  theme, // custom theme options (see below)\n});\n```\n\n#### Hooks\nUse `useConfig()` hook inside of components to get current `Config` instance with all data.\n\n#### i18n\nConfig options:\n\n- `i18nDefaultLanguage` - Default language in admin panel\n- `i18nLanguages` - Array of supported languages\n- `i18nUseBrowserLanguageDetector` - Enable automatically detect language by browser \n- `i18nResourcesContext` - Instance of Webpack's `RequireContext` with specified folder for loading translations\n\nFor enable languages support you need create translations files in `~/locales` folder (in sources root).\n\nFolders structure example:\n```text\nlocales/\n├── en\n│   ├── buttons.json\n│   ├── common.json\n│   └── messages.json\n└── ru\n    ├── buttons.json\n    ├── common.json\n    └── messages.json\n```\n\nFilename is a namespace of translations. Default namespace is \"common\". For example you can call `t('common:Sign In')` or is same `t('Sign In')`, other namespaces messages calls only with namespace, example: `t('buttons:Cancel')`.\n\nFor mor info check out the [i18next documentation](https://www.i18next.com/) and [react-i18next documentation](https://react.i18next.com/).\n\n## AuthProvider\n`AuthProvider` is extendable class. You can override its metods for your needs. The app decides user authentication status by checking its token field, but you can override this behaviour in your own class, like this done in `JWTAuthProvider`.\n\n#### Options:\n```javascript\nnew AuthProvider({\n  authRequestFn: (email, password) =\u003e\n    Promise.resolve({\n      user: {\n        email: 'user@example.com',\n        username: 'username',\n        token: 'SAMPLE_TOKEN',\n        role: 'user',\n      },\n      error: '',\n    }),\n  authPasswRestoreFn: (email) =\u003e\n    Promise.resolve({\n      error: '',\n    }),\n  persist: true, //store beetween sessions\n  router: FC, // optional\n  signIn: FC, // optional\n  signUp: FC, // optional\n  forgotPassword: FC, // optional\n  resetPassword: FC, // optional\n  layout: FC, // optional\n});\n```\n\n#### Customization\nOverride these components to customize guest user interface:\n- `router` - global router for unauthorized users. Avoid changing it\n- `signIn`, `signUp`, `forgotPassword`, `resetPassword` - specific components for each step of authorization\n- `layout` - wrapper for all components. By default it's `VerticalAuthLayout`.\n\nTIP: use `const config = useConfig()` react hook to get current `config` inside each component. \n\n## JWTAuthProvider\n\nJWTAuthProvider is extension of AuthProvider, but it has `tokenRefreshFn` to fetch renewed access token, using refresh token. Also, authRequestFn returns `tokens` field with access and refresh token pair:\n\n```javascript\nnew AuthProvider({\n  authRequestFn: (email, password) =\u003e (\n    Promise.resolve({\n      user: {\n        email: 'user@example.com',\n        username: 'username',\n        role: 'user'\n      },\n\t  tokens: {\n\t\taccess: 'accessToken',\n\t\trefresh: 'refreshToken',\n\t  },\n      error: ''\n    })\n  ),\n  authPasswRestoreFn: (email) =\u003e (\n    Promise.resolve({\n      error: '',\n    })\n  ),\n  tokenRefreshFn: (refresh) =\u003e (\n  \tPromise.resolve({\n\t\taccess: 'newAccessToken',\n\t\trefresh: 'newRefreshToken',\n\t}),\n  ),\n  persist: true, //store beetween sessions\n});\n```\n\n#### Methods and values:\n- `auth.user` - current user info\n- `auth.withToken: (req, args) =\u003e Promise\u003cany\u003e` - wrapper for callbacks, which used to add `token` value to function arguments\n- `auth.logout: () =\u003e void` - function to log user out\n- `auth.isLogged: boolean` - computed field to decide if user is logged in\n\n## Page\nPage class is for rendering pages inside the app. You can extend it to create more complex pages, like this done in Entity class.\n\n#### Options:\n\n```javascript\nnew Page({\n  title: 'Sample page',\n  menu: {\n    enabled: true,\n    url: '/test',\n    label: 'Sample page',\n  },\n  roles: {\n    // who can access this page\n    list: ['admin', 'manager'],\n  },\n});\n```\n\n#### Methods and values:\n\n- `page.canList: boolean` - if page can be viewed by current user\n- `page.onMount: (page: Page) =\u003e void` - method, called on mount\n- `page.onUnmount: (page: Page) =\u003e void` - method, called before unmount\n- `page.output: ReactElement` - react component, that renders page content\n\n#### Hooks\n\nUse `const page = usePage()` inside components to get current page\n\n#### Extending:\n\nJust extend Page class and add your functionality. Override output, onMount, onUnmount methods to create your own content behaviour.\n\n## Entity\n\nEntity is used to display list of some database entities, view their details and edit them. The Entity class extends Page one.\n\n#### Options\n\n```typescript\nnew Entity({\n  ...pageOptions,\n  title: 'Sample entity',\n  editable: true,\n  viewable: true,\n  creatable: true,\n  exportable: true,\n  api: {\n    get: { url: '/get', method: 'get' },\n    list: { url: '/list', method: 'get' },\n    update: { url: '/update', method: 'patch' },\n    create: { url: '/create', method: 'post' },\n  },\n  menu: {\n    enabled: true,\n    label: 'Sample entity',\n    url: '/entity',\n  },\n  references: {\n    status: {\n      getMany: async () =\u003e {\n        return {\n          1: 'variant 1',\n          2: 'variant 2',\n        };\n      },\n    },\n  },\n  fields: [\n    {\n      name: 'type',\n      label: 'Тип',\n      sortable: true,\n      type: 'custom', // see Fields below\n      component: EntityTypeField,\n    },\n    {\n      name: 'status',\n      label: 'Статус',\n      sortable: true,\n      filterable: true,\n      type: 'referenceSelect',\n      required: true,\n    },\n  ],\n  getItemsFn, // see getItemsFn below\n  fetchItemsFn, // see fetchItemsFn below\n  updateItemsFn, // see updateItemsFn below\n  createItemsFn, // see createItemsFn below\n});\n```\n\n#### Methods and values\n(extends Page methods and values)\n- `entity.canView: boolean` - if entity can be viewed by current user\n- `entity.canEdit: boolean` - if entity can be edited by current user\n- `entity.canCreate: boolean` - if entity can be created by current user\n- `entity.output` - component, that renders entity page and contains router for list, view, edit and create pages\n- `entity.List`, `entity.Viewer`, `entity.Editor`, `entity.Creator` - overridable components for viewing, editing and creating item\n- `entity.ListHead`, `entity.ListBody`, `entity.ListFooter` - overridable parts of `entity.List` component\n- `entity.EditorHead`, `entity.EditorBody`, `entity.EditorFooter` - overridable parts of `entity.Editor` component\n- `entity.ViewerHead`, `entity.ViewerHeadButtons`, `entity.ViewerBody`, `entity.ViewerFooter` - overridable parts of `entity.Viewer` component\n- `entity.ListExtra` - if not null, renders entity list as accordeons, expanding by click with ListExtra's component as accordeon content\n- `entity.CreatorHead`, `entity.CreatorHeadButtons`, `entity.CreatorBody`, `entity.CreatorFooter` - overridable parts of `entity.Creator` component\n- `entity.isLoading: boolean` - is item currently loading / updating\n- `entity.items: number` - how many items per page should be displayed in view list\n- `entity.itemsPerPage: number[]` - available options for items\n- `entity.page: number` - current page\n- `entity.exportData` - used to export data in preferred format (currently .csv)\n- `entity.setFiltersWindowHash`, `getFiltersFromHash` - syncing filters with page url using url hash\n\n#### Hooks\nUse `const entity = useEntity()` inside components to get current entity\n\n#### Entity fields\nEntity.fields is an array of objects. Every field can has following types: `string`, `date`, `boolean`, `select`, `phone`, `richtext`, `base64image`. `custom` or `referenceSelect`.\n\nEvery field is rendered by predefined or custom component, which accepts common options. `isEditing` prop tells component to render in view (when it's in a table or in entity preview) or editor (when it's in editor or acting as filter field).\n\n- `name: string,` - field name is it comes from the api\n- `label?: string,` - field label (or name will be used)\n- `title?: true,` - is this a title for entity\n- `type: string` - field type\n- `sortable?: boolean;` - can we sort by this field\n- `filterable?: boolean;` - can we filter by this field\n- `required?: boolean;` - is this field required. Used for basic validation\n- `validator?: (val: any) =\u003e boolean;` - custom validator\n- `options?: Record\u003cany, any\u003e;` - options, passed for `custom` component or { [value]: key } for `select` component\n- `component?: FC\u003cany\u003e;` - React Component to render field. Only for `custom` fields\n- `hideInList?: boolean;` - do not render in table of entities\n- `hideInEdit?: boolean;` - do not render in editor form\n- `hideInCreate?: boolean;` - do not render in creator form\n- `hideInExport?: boolean;` - do not export field in CSV\n\n#### Custom Fields\n```typescript\n  const customField: IEntityField = {\n    name: \"type\", \n    label: \"Тип\",\n    sortable: true,\n    type: \"custom\",\n    component: EntityTypeField,\n  }\n```\n\nCustom fields are rendered by React Component specified in `component` prop. Custom field component options are:\n\n- `value: any` - field value for current component\n- `handler: (value: any) =\u003e void` - function, that changes value\n- `label: string` - human readable label\n- `error: string` - error (if any)\n- `isEditing: boolean` - view or edit mode\n- `options: Record\u003cany, any\u003e` - options\n- `data: Record\u003cstring, any\u003e` - values for all the fields of current Entity\n- `fields: EntityField[]` - description of all fields\n- `withToken: (req, args) =\u003e Promise\u003cany\u003e` - function, that wraps requests with current user credentials (see `AuthProvider`)\n\n#### Reference fields\n```typescript\n\t{\n    name: 'status',\n    label: 'Статус',\n    sortable: true,\n    filterable: true,\n    type: 'referenceSelect',\n    required: true,\n\t},\n```\n\nThe Entity should has ```references``` to fetch data, that will match reference fields data:\n```typescript\n  references: {\n    status: { // name should match the one in fields\n      getMany: async () =\u003e {\n        return {\n          1: 'variant 1',\n          2: 'variant 2',\n          3: 'variant 3',\n        };\n      },\n    },\n  },\n```\n\n#### Data fetching functions\n\n`getItemsFn` - fetches entity by id.\n\n```typescript\ntype IEntityGetFunction = ({\n  url: string;\n  token?: string;\n  id: any;\n}) =\u003e Promise\u003c{\n  data: Record\u003cstring, any\u003e;\n  error?: string\n}\u003e\n```\n\n`fetchItemsFn` - fetches entities list.\n\n```typescript\ntype IEntityFetchFunction = ({\n  url: string;\n  page?: number;\n  filter?: { name?: string; value?: any };\n  sortBy: string;\n  sortDir: string; // 'ASC' or 'DESC'\n  count?: number;\n  token?: string;\n}) =\u003e Promise\u003c{\n  data: {\n    list: Record\u003cstring, any\u003e[];\n    totalCount?: number;\n  };\n  error?: string;\n}\u003e\n```\n\n`updateItemsFn` - updates entity after editing.\n\n```typescript\ntype IEntityUpdateFunction = ({\n  url: string;\n  id: any;\n  token?: string;\n  data: Record\u003cstring, any\u003e;\n}) =\u003e Promise\u003c{\n  data: Record\u003cstring, any\u003e; // updated data\n  error?: string;\n}\u003e\n```\n\n`createItemsFn` - creates new entity.\n\n```typescript\ntype IEntityCreateFunction = ({\n  url: string;\n  token?: string;\n  data: Record\u003cstring, any\u003e;\n}) =\u003e Promise\u003c{\n  data: Record\u003cstring, any\u003e; // updated data\n  error?: string;\n}\u003e\n```\n\nThrowing `UNAUTHORIZED` error will cause AuthProvider/JWTAuthProvider token update or logout, depending on result.\n\n#### Auth wrappers for Entity\n\nEach entity has a link to config via `this.parent`. You can access tokens by hitting `this.parent.auth`, but you'd better use `this.parent.auth.withToken(fn, args)` in your own entity methods.\n\n`withToken` will add `token` arg to list of fn arguments, so you can pass it as auth header.\n\n## Theming\n\nSee https://material-ui.com/customization/theming/. To change colors, fonts, spacing, create your own theme and add it to config as `theme` prop:\n\n```typescript\nimport { createMuiTheme } from '@material-ui/core/styles';\n\nexport default createMuiTheme({\n  palette: {\n    primary: {\n      main: '#d20c0a',\n    },\n  },\n  typography: {\n    fontFamily: '\"Roboto\", \"Helvetica\", \"Arial\", \"sans-serif\"',\n  },\n});\n```\n\n## Experimental feature\nWe've started implementing `Page` type called `Feature` to make more customizable kind of entity\nadministration with better typing support for incoming data.\n\nHere's the brief info about it:\n\n```typescript\nconst feature = new Feature\u003cFields\u003e('Feature title', '/feature', options);\n```\n\n### Field types\nData types for all incoming data should be described:\n```\nexport interface Fields {\n    name: string,\n    age: number,\n}\n```\n\n### Feature Options\n```\nconst featureOptions: FeatureOptions\u003cFields\u003e = {\n    fields: FeatureField\u003cFields\u003e[];\n    features: FeatureFeatures;\n    containers?: FeatureRendererProps['containers'];\n    components?: FeatureRendererProps['components'];\n    api?: FeatureApiProps\u003cFields\u003e;    \n    permissions?: Partial\u003cRecord\u003cFeatureFeature, UserRole[]\u003e\u003e;\n    getItemTitle?: (fields: Fields) =\u003e string;    \n}\n```\n\n- `fields` - list of `FeatureField` (see below) \n- `features` - what kind of views should this feature have\n- `containers` - and `components` - are list of components, what can be overriden (or default ones will be used)\n- `api` - is an api props, describing how to interact with backend\n- `permissions` - is a dictionary of `feature` and list of user roles\n- `getItemTitle` - is a function, that returns each item's title at views, breadcrumbs and etc.\n\n### Hooks \nUse `const feature = useFeature()` to get current `Feature` instance inside any of components, inputs, etc.\n\n### Customizing views\nYou can theme app by overriding `containers` and `components`. \n\n#### Containers \nSimply a dictionary of `list`, `read`, `create` and `update` to React Functional Component. Use hooks to access\ncurrent feature data.\n\n#### Components\nAll of Feature's containers is separated by zones, you can override each of them. Use just simple Functional Components\nwithout any props, get current data by using `useFeature` react hook.\n\n##### List components\nReact.FC components can be specified for: `wrapper`, `header`, `title`, `buttons`, `filters`, `table`, `pagination`, `footer`, `container`\n  \n##### Read, Update and Create components:\nReact.FC components can be specified for: `wrapper`, `header`, `footer`, `title`, `buttons`, `breadcrumbs`, `content`, `submit`, `container`\n\n### Fields\nUnlike in `Entity`, all fields in `Feature` are described by `FeatureField` class and its successors.\nBuilt-in field types are: `DateField`, `IntegerField`, `ReferenceField`, `SelectField` and `StringField`.\n\nEach of them has it's own options and `FeatureField`'s common ones. Create your own field\ntypes by overriding any of that field classes.\n\n```\nconst age = new IntegerField\u003cFields\u003e('age', {\n    label: 'Age',\n    accuracy: 2,\n    features: {\n      sort: true,\n      filter: true,\n    },\n    defaultValue: 21,\n});\n```\n\nSee [src/example/feature/fields.ts](src/example/pages/feature/fields.ts) for more examples.\n\n## Publishing\n\nUse `npm login` or `yarn login` and then `npm publish` or `yarn publish`.\nDon't forget to increase package version each time you commit changes.\n\n## License\n\n    Copyright 2020 IceRock MAG Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficerockdev%2Fadmin-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficerockdev%2Fadmin-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficerockdev%2Fadmin-toolkit/lists"}