این README رو جایگزین قبلی کن. importها با ساختار جدید هماهنگه: utils, pagination, layout, core, table. چون ظاهراً README قبلی هم مثل خیلی از READMEها بیشتر آرزو بود تا واقعیت.
uikit
کتابخانهی مشترک React برای استفاده بین پروژههای BI.
این پکیج به چند entry جدا تقسیم شده تا پروژهها فقط همان بخشی را import کنند که لازم دارند و مجبور نباشند برای یک helper ساده، dependencyهای سنگین مثل Chakra، Keycloak یا React Query نصب کنند.
نصب
yarn add git+https://git.d.aiengines.ir/bi/uikit.git
یا اگر branch/tag خاصی لازم داری:
yarn add git+https://git.d.aiengines.ir/bi/uikit.git#main
آپدیت
yarn upgrade uikit
اگر از git dependency استفاده میکنی و نسخه جدید نگرفتی، lockfile را هم بررسی کن:
yarn remove uikit
yarn add git+https://git.d.aiengines.ir/bi/uikit.git
ساختار importها
| مسیر | کاربرد | dependency اضافی |
|---|---|---|
uikit |
خروجی سبک، فعلاً فقط utils | ندارد |
uikit/utils |
helperهای ساده مثل تبدیل عدد | ندارد |
uikit/pagination |
کامپوننتهای pagination | Chakra + React + react-icons |
uikit/layout |
کامپوننتهای layout مثل Header | Chakra + React |
uikit/core |
API، BiProvider، Keycloak، Permission | Chakra + React Query + Axios + Keycloak |
uikit/table |
DataTable | Chakra + TanStack Table + Pagination |
استفاده از utils
برای helperهای ساده نیازی به نصب هیچ dependency اضافهای نیست.
import { toFaDigits, toEnDigits, toFaNumber } from "uikit/utils";
toFaDigits(123456); // ۱۲۳۴۵۶
toEnDigits("۱۲۳۴۵۶"); // 123456
toFaNumber(123456); // عدد فارسیشده
همچنین چون root package فقط utils را export میکند، این هم قابل استفاده است:
import { toFaDigits } from "uikit";
استفاده از pagination
اگر از pagination استفاده میکنی، این dependencyها باید در پروژه نصب باشند:
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion react-icons
استفاده:
import { Pagination, LightPagination, SimplePagination } from "uikit/pagination";
function Page() {
return (
<Pagination
currentPage={1}
totalCount={100}
totalPages={5}
onPageChange={(page) => console.log(page)}
/>
);
}
استفاده از Header
Header داخل مسیر uikit/layout قرار دارد.
dependencyهای لازم:
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
استفاده:
import { Header } from "uikit/layout";
function AppHeader() {
return (
<Header>
<Header.BrandSection>
<Header.Logo src="/logo.png" />
<Header.Brand>
<Header.Title>عنوان سامانه</Header.Title>
<Header.Description>توضیح کوتاه سامانه</Header.Description>
</Header.Brand>
</Header.BrandSection>
<Header.Bi />
</Header>
);
}
اجزای موجود:
<Header />
<Header.BrandSection />
<Header.Logo />
<Header.Brand />
<Header.Title />
<Header.Description />
<Header.Bi />
استفاده از core
بخش core شامل این موارد است:
- API config
createApiBiProvider- Keycloak
- Permission
- React Query provider
- Chakra provider
برای استفاده از core این dependencyها باید در پروژه نصب باشند:
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-query axios keycloak-js
استفاده از BiProvider
import { BiProvider } from "uikit/core";
export default function App() {
return (
<BiProvider
apiBaseUrl="https://api.example.com"
keycloakClientId="front-client"
permissionClientId="permission-client"
>
<YourApp />
</BiProvider>
);
}
BiProvider به صورت داخلی این کارها را انجام میدهد:
- تنظیم base url برای API
- راهاندازی Keycloak در صورت فعال بودن
- گرفتن permissionها در صورت فعال بودن
- اضافه کردن
ChakraProvider - اضافه کردن
QueryClientProvider - اضافه کردن فونت و theme داخلی
- فعال کردن اختیاری
UpdateChecker
props مربوط به BiProvider
| Prop | توضیح |
|---|---|
apiBaseUrl |
آدرس اصلی API |
keycloakClientId |
client id مربوط به Keycloak |
permissionClientId |
client id مربوط به Permission |
loading |
کامپوننت loading هنگام init شدن Keycloak یا Permission |
updateChecker |
فعال یا غیرفعال کردن بررسی آپدیت |
updateCheckerProps |
props مربوط به UpdateChecker |
keycloakUrl |
آدرس Keycloak |
keycloakRealm |
realm مربوط به Keycloak |
permissionUrl |
آدرس API مربوط به permission |
keycloakEnabled |
فعال یا غیرفعال کردن Keycloak به صورت دستی |
permissionEnabled |
فعال یا غیرفعال کردن Permission به صورت دستی |
مقدارهای پیشفرض BiProvider
keycloakUrl = "https://auth.ibagher.ir";
keycloakRealm = "bi";
permissionUrl = "https://api.d.aiengines.ir/user_api/v1/permissions/list";
updateChecker = false;
نکته: اگر keycloakClientId داده شود، Keycloak فعال میشود. اگر permissionClientId داده شود، Permission فعال میشود.
برای کنترل دستی:
<BiProvider
apiBaseUrl="https://api.example.com"
keycloakEnabled={false}
permissionEnabled={false}
>
<YourApp />
</BiProvider>
UpdateChecker
به صورت پیشفرض updateChecker خاموش است.
برای فعال کردن:
<BiProvider
apiBaseUrl="https://api.example.com"
keycloakClientId="front-client"
permissionClientId="permission-client"
updateChecker
>
<YourApp />
</BiProvider>
اگر updateChecker را فعال میکنی، پروژه باید فایل version تولید کند. معمولاً باید یک اسکریپت مثل write-version.js در root پروژه داشته باشی و در package.json پروژه target، قبل از build اجرا شود.
نمونه:
{
"scripts": {
"prebuild": "node write-version.js",
"build": "next build"
}
}
استفاده از API پایه
import { api, fetcher, configureApi, getApi } from "uikit/core";
اگر از BiProvider استفاده میکنی، معمولاً نیازی نیست دستی configureApi را صدا بزنی، چون BiProvider این کار را انجام میدهد.
نمونه استفاده مستقیم:
import { api } from "uikit/core";
const response = await api.get("/users");
یا:
import { fetcher } from "uikit/core";
const data = await fetcher("/users");
استفاده از createApi
createApi برای ساختن یک API ساده بر پایه React Query استفاده میشود.
import { createApi } from "uikit/core";
export const profileApi = createApi({
key: "profile",
url: "/content/rokn/profiles",
actions: {
update: {
method: "patch",
url: (id) => `/content/rokn/profiles/${id}`,
},
delete: {
method: "delete",
},
generate: {
method: "post",
url: "/content/rokn/generate/profile",
},
updateImages: {
method: "post",
url: (id) => `/content/rokn/profile-update/${id}/images`,
body: ({ formData }) => formData,
},
},
});
گرفتن لیست
const { data, isLoading, error } = profileApi.useGet({
page: 1,
size: 20,
is_confirmed: true,
});
این request ساخته میشود:
GET /content/rokn/profiles?page=1&size=20&is_confirmed=true
اجرای action
const updateProfile = profileApi.useAction("update");
await updateProfile.mutateAsync({
id: 10,
username: "new_username",
});
در این حالت:
PATCH /content/rokn/profiles/10
body:
{
username: "new_username"
}
id به صورت پیشفرض از body حذف میشود، چون برای ساختن URL استفاده شده است.
action با همان URL اصلی
اگر action همان URL اصلی را لازم دارد، نیازی نیست url را دوباره بنویسی.
export const identityGenerateApi = createApi({
key: "identity-generate",
url: "/content/rokn/identity-generate/logs",
actions: {
delete: {
method: "delete",
},
},
});
یعنی:
DELETE /content/rokn/identity-generate/logs
action با FormData
const updateImages = profileApi.useAction("updateImages");
const formData = new FormData();
formData.append("image", file);
await updateImages.mutateAsync({
id: 10,
formData,
});
در تعریف action:
updateImages: {
method: "post",
url: (id) => `/content/rokn/profile-update/${id}/images`,
body: ({ formData }) => formData,
}
body مشخص میکند چه چیزی واقعاً به عنوان body ارسال شود.
استفاده از Keycloak
import {
getKeycloakToken,
loginKeycloak,
logoutKeycloak,
updateKeycloakToken,
} from "uikit/core";
const token = getKeycloakToken();
await updateKeycloakToken(30);
loginKeycloak();
logoutKeycloak({
redirectUri: window.location.origin,
});
استفاده از Permission
import { Can, usePermission } from "uikit/core";
function Page() {
const { can, cannot, permissions } = usePermission();
return (
<>
{can("users:list") && <div>لیست کاربران</div>}
<Can perm="users:create" fallback={null}>
<button>ایجاد کاربر</button>
</Can>
</>
);
}
نکته: prop کامپوننت Can برابر perm است.
<Can perm="users:list">
<UsersList />
</Can>
استفاده از DataTable
DataTable داخل مسیر uikit/table قرار دارد.
dependencyهای لازم:
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-table react-icons
استفاده:
import { DataTable } from "uikit/table";
function UsersTable({ data, columns }) {
return (
<DataTable
data={data}
columns={columns}
page={1}
size={20}
pagination={{
totalCount: 100,
totalPages: 5,
}}
onPageChange={(page) => console.log(page)}
getRowId={(row) => String(row.id)}
enableSelection
showIndex
>
<DataTable.Topbar>
<DataTable.Title>لیست کاربران</DataTable.Title>
<DataTable.Spacer />
<DataTable.Actions>
<DataTable.SelectAll />
</DataTable.Actions>
</DataTable.Topbar>
<DataTable.Content>
<DataTable.Table />
<DataTable.Pagination />
</DataTable.Content>
</DataTable>
);
}
dependencyهای پیشنهادی بر اساس نیاز
فقط utils
نیازی به نصب dependency اضافه نیست.
yarn add git+https://git.d.aiengines.ir/bi/uikit.git
pagination یا layout
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion react-icons
برای layout معمولاً react-icons لازم نیست، ولی اگر پروژه از pagination هم استفاده میکند، نصبش کن.
core
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-query axios keycloak-js
table
yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion @tanstack/react-table react-icons
نکات مهم توسعه
بعد از تغییر فایلها، build بگیر:
yarn build
فایلهای خروجی مورد انتظار:
dist/index.js
dist/utils.js
dist/pagination.js
dist/layout.js
dist/core.js
dist/table.js
اگر entry جدید اضافه شد، باید هم در vite.config.js و هم در package.json > exports ثبت شود.
قانون کلی
هر چیزی که dependency سنگین ندارد:
uikit/utils
هر چیزی که UI سبک است و Chakra میخواهد:
uikit/pagination
uikit/layout
هر چیزی که مربوط به API، auth، permission و provider است:
uikit/core
هر چیزی که مربوط به table است:
uikit/table
Root package یعنی:
uikit
باید سبک بماند و فقط چیزهایی مثل utils را export کند.