npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@cundi/refine-xaf

v1.0.5

Published

Integration SDK for XAF backend and Refine frontend

Downloads

610

Readme

@cundi/refine-xaf

This is an SDK integrating XAF backend with Refine frontend, including core logic for Authentication (Auth Provider), Data Access (Data Provider), and a complete UI component library.

Features

  • Auth Provider: Handles login, logout, Token management, and permission checks.
  • Data Provider: Data access layer designed specifically for XAF OData.
  • UI Components:
    • Header: Application header including user menu and theme toggle (Dark/Light Mode).
    • LoginPage: Standard login page.
    • SmartList, RelatedList: Highly encapsulated generic list and detail components. (Note: To use defaultVisible prop, import @cundi/refine-xaf/dist/antd-column-ext in your app entry)
    • TiptapEditor: Rich text editor with support for Images, Tables, Tasks, Math (LaTeX), YouTube, Emoji, Highlight, and Text Color.
    • DrawioEditor: Draw.io diagram editor with i18n language sync support.
    • ApplicationUser: Complete user management (List, Create, Edit, Role Assignment).
    • PermissionPolicyRole: Complete role and permission management.

How to use in a new project

1. Initialize Project

It is recommended to use the official tool to create a standard Refine + Vite + Ant Design project:

npm create refine-app@latest my-project
# Recommended options:
# Backend: Custom JSON REST (will be replaced later)
# UI Framework: Ant Design
# Authentication: None (will use SDK later)

2. Install SDK

Install this SDK in your project directory:

# If in the same level as packages folder (monorepo structure)
npm install ../packages/refine-xaf

# Or use the published package name
# npm install @cundi/refine-xaf

3. Setup Environment Variables (.env)

Create a .env file in the project root directory and specify the backend API location.

Note: SDK's httpClient (used for Auth) defaults to reading VITE_API_URL. OData endpoints usually need the /odata suffix.

VITE_API_URL=https://localhost:7087/api

4. Setup App.tsx

Modify src/App.tsx to import components and logic from the SDK:

import React from "react";
import { BrowserRouter, Routes, Route, Outlet } from "react-router-dom";
import { App as AntdApp, ConfigProvider, theme } from "antd";
import { Refine, Authenticated } from "@refinedev/core";
import { ThemedLayout, ErrorComponent, RefineThemes, useNotificationProvider } from "@refinedev/antd";
import routerProvider, { NavigateToResource, CatchAllNavigate, UnsavedChangesNotifier, DocumentTitleHandler } from "@refinedev/react-router";
import "@refinedev/antd/dist/reset.css";

// 1. Import SDK
import {
    authProvider,
    dataProvider,
    Header,
    LoginPage,
    ApplicationUserList,
    ApplicationUserCreate,
    ApplicationUserEdit,
    RoleList,
    RoleCreate,
    RoleEdit,
    ColorModeContextProvider,
    useColorMode
} from "@cundi/refine-xaf";

// 2. Setup API URL (Raw URL for Auth, /odata for Data)
const API_URL = import.meta.env.VITE_API_URL;

const InnerApp: React.FC = () => {
    const { mode } = useColorMode();

    return (
        <BrowserRouter>
            <ConfigProvider
                theme={{
                    ...RefineThemes.Blue,
                    algorithm: mode === "dark" ? theme.darkAlgorithm : theme.defaultAlgorithm,
                }}
            >
                <AntdApp>
                    <Refine
                        authProvider={authProvider}
                        // 3. Setup Data Provider (Note the /odata suffix)
                        dataProvider={dataProvider(API_URL + "/odata")}
                        routerProvider={routerProvider}
                        notificationProvider={useNotificationProvider}
                        resources={[
                            {
                                name: "dashboard",
                                list: "/",
                                meta: { label: "Dashboard" }
                            },
                            {
                                name: "ApplicationUser",
                                list: "/ApplicationUsers",
                                create: "/ApplicationUsers/create",
                                edit: "/ApplicationUsers/edit/:id",
                                meta: { label: "Users" }
                            },
                            {
                                name: "PermissionPolicyRole",
                                list: "/PermissionPolicyRoles",
                                create: "/PermissionPolicyRoles/create",
                                edit: "/PermissionPolicyRoles/edit/:id",
                                meta: { label: "Roles" }
                            }
                        ]}
                    >
                        <Routes>
                            <Route
                                element={
                                    <Authenticated key="authenticated-routes" fallback={<CatchAllNavigate to="/login" />}>
                                        <ThemedLayout Header={Header}>
                                            <Outlet />
                                        </ThemedLayout>
                                    </Authenticated>
                                }
                            >
                                <Route index element={<div>Welcome to Dashboard</div>} />
                                
                                {/* 4. Setup pages provided by SDK */}
                                <Route path="/ApplicationUsers">
                                    <Route index element={<ApplicationUserList />} />
                                    <Route path="create" element={<ApplicationUserCreate />} />
                                    <Route path="edit/:id" element={<ApplicationUserEdit />} />
                                </Route>

                                <Route path="/PermissionPolicyRoles">
                                    <Route index element={<RoleList />} />
                                    <Route path="create" element={<RoleCreate />} />
                                    <Route path="edit/:id" element={<RoleEdit />} />
                                </Route>
                            </Route>

                            <Route
                                element={
                                    <Authenticated key="auth-pages" fallback={<Outlet />}>
                                        <NavigateToResource resource="dashboard" />
                                    </Authenticated>
                                }
                            >
                                <Route path="/login" element={<LoginPage />} />
                            </Route>
                        </Routes>
                        <UnsavedChangesNotifier />
                        <DocumentTitleHandler />
                    </Refine>
                </AntdApp>
            </ConfigProvider>
        </BrowserRouter>
    );
};

const App: React.FC = () => {
    return (
        <ColorModeContextProvider>
            <InnerApp />
        </ColorModeContextProvider>
    );
};

export default App;

Building Custom CRUD Pages

To create CRUD pages for your own XAF business objects (e.g., DemoObject), follow these patterns (reference cundiweb/src/pages/demo-objects for complete examples).

List Page

Use the SmartList component to quickly build a feature-rich list view with search capabilities.

import { SmartList } from "@cundi/refine-xaf";
import { Table, Checkbox, Space } from "antd";
import { EditButton, ShowButton, DeleteButton, DateField } from "@refinedev/antd";

export const DemoObjectList = () => {
    return (
        // searchFields prop enables the search bar for specified columns
        <SmartList searchFields={["Name", "StringValue"]}>
            <Table.Column dataIndex="Name" title="Name" sorter defaultVisible />
            <Table.Column dataIndex="StringValue" title="String Value" sorter />
            <Table.Column 
                dataIndex="BoolValue" 
                title="Boolean" 
                render={(value) => <Checkbox checked={value} disabled />} 
            />
            {/* Standard Ant Design Table.Column configuration */}
            <Table.Column
                title="Actions"
                dataIndex="actions"
                render={(_, record) => (
                    <Space>
                        <EditButton hideText size="small" recordItemId={record.Oid} />
                        <ShowButton hideText size="small" recordItemId={record.Oid} />
                        <DeleteButton hideText size="small" recordItemId={record.Oid} />
                    </Space>
                )}
            />
        </SmartList>
    );
};

Create/Edit Page

Use standard Refine hooks (useForm) combined with Ant Design Form components. For file uploads (like Images), use the Base64Upload component provided by the SDK.

import { Create, useForm } from "@refinedev/antd"; // or Edit
import { Base64Upload } from "@cundi/refine-xaf";
import { Form, Input, Switch } from "antd";

export const DemoObjectCreate = () => {
    const { formProps, saveButtonProps } = useForm();

    return (
        <Create saveButtonProps={saveButtonProps}>
            <Form {...formProps} layout="vertical">
                <Form.Item
                    label="Name"
                    name={["Name"]}
                    rules={[{ required: true }]}
                >
                    <Input />
                </Form.Item>
                
                {/* Image upload example */}
                <Form.Item label="Image" name={["ImageValue"]}>
                    <Base64Upload />
                </Form.Item>

                <Form.Item 
                    label="Active" 
                    name={["Active"]} 
                    valuePropName="checked"
                >
                    <Switch />
                </Form.Item>
            </Form>
        </Create>
    );
};

DrawioEditor Usage

Use the DrawioEditor component for Draw.io diagram editing with automatic i18n language synchronization.

import { DrawioEditor } from "@cundi/refine-xaf";
import { Form } from "antd";

// Basic usage in a form
<Form.Item
    label="Diagram"
    name={["DiagramXml"]}
    trigger="onChange"
    getValueFromEvent={(value) => value}
>
    <DrawioEditor height={600} />
</Form.Item>

// Props:
// - value?: string          - XML format diagram data
// - onChange?: (xml) => void - Callback when content changes
// - disabled?: boolean      - Read-only mode (hides save button)
// - height?: number|string  - Editor height (default: 500)
// - autosave?: boolean      - Enable autosave (default: true)

Development and Publishing

  1. Install Dependencies: npm install
  2. Build SDK: npm run build
  3. Development Mode: npm run dev (watch mode)
  4. Run Tests: npm run test
  5. Test Coverage: npm run test:coverage

Utilities

The SDK provides several utility functions:

Password Utilities

import { generatePassword, validatePasswordStrength } from "@cundi/refine-xaf";

// Generate a secure random password
const password = generatePassword(16); // Optional length, default 12

// Validate password strength
const result = validatePasswordStrength(password);
if (result.isValid) {
    console.log("Password is strong!");
}

JWT Parsing

import { parseJwt } from "@cundi/refine-xaf";

const token = localStorage.getItem("refine-auth");
const claims = parseJwt(token);
console.log(claims.sub, claims.exp);

Changelog

v1.0.5 (Latest)

  • Added DrawioEditor component for Draw.io diagram editing
  • DrawioEditor supports automatic i18n language synchronization
  • Added react-drawio dependency

v1.0.4

  • Fixed refineXafTranslations export (was missing from main index)
  • Fixed i18n translations for dashboard page

v1.0.3

  • Added Dashboard page translations
  • Fixed internationalization in template

v1.0.2

  • Fixed defaultVisible type definition for SmartList. Consumers must add import "@cundi/refine-xaf/dist/antd-column-ext"; to their entry file (e.g., App.tsx) to enable this feature.

v1.0.1

  • Added generatePassword and validatePasswordStrength utilities
  • Added retry mechanism to httpClient (exponential backoff)
  • Improved SmartList performance with useMemo
  • Extracted TiptapEditor styles to separate CSS file
  • Enhanced environment variable validation for Keycloak
  • Added Jest test framework