This commit is contained in:
bwnyasse
2026-01-10 21:22:35 -05:00
parent 90455d9181
commit d43a14ee0c
116 changed files with 41323 additions and 19 deletions

View File

@@ -0,0 +1,8 @@
VITE_HARNESS_FIREBASE_API_KEY="your-api-key"
VITE_HARNESS_FIREBASE_AUTH_DOMAIN="your-auth-domain"
VITE_HARNESS_FIREBASE_PROJECT_ID="your-project-id"
VITE_HARNESS_FIREBASE_STORAGE_BUCKET="your-storage-bucket"
VITE_HARNESS_FIREBASE_MESSAGING_SENDER_ID="your-messaging-sender-id"
VITE_HARNESS_FIREBASE_APP_ID="your-app-id"
VITE_HARNESS_ENVIRONMENT="dev"
VITE_API_BASE_URL="http://localhost:8080"

24
internal/api-harness/.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,16 @@
# React + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## React Compiler
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
## Expanding the ESLint configuration
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.

View File

@@ -0,0 +1,17 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": false,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
}
}

View File

@@ -0,0 +1,29 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
extends: [
js.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
rules: {
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
},
},
])

View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>internal-api-harness</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
}
}
}

6667
internal/api-harness/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
{
"name": "internal-api-harness",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@dataconnect/generated": "file:src/dataconnect-generated",
"@radix-ui/react-collapsible": "^1.1.12",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slot": "^1.2.4",
"axios": "^1.13.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"firebase": "^12.6.0",
"lucide-react": "^0.553.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"react-firebase-hooks": "^5.1.1",
"react-router-dom": "^7.9.6",
"shadcn-ui": "^0.9.5",
"tailwind-merge": "^3.4.0",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@types/node": "^24.10.1",
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2",
"@vitejs/plugin-react": "^5.1.0",
"autoprefixer": "^10.4.22",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.18",
"vite": "^7.2.2"
}
}

View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="200 180 280 140" style="enable-background:new 0 0 500 500;" xml:space="preserve">
<style type="text/css">
.st0{fill:#24303B;}
.st1{fill:#002FE3;}
</style>
<g>
<path class="st1" d="M459.81,202.55c-5.03,0.59-9.08,4.49-10.36,9.38l-15.99,59.71l-16.24-56.3
c-1.68-5.92-6.22-10.86-12.19-12.34c-1.58-0.39-3.11-0.54-4.64-0.49h-0.15c-1.53-0.05-3.11,0.1-4.64,0.49
c-5.97,1.48-10.51,6.42-12.24,12.34l-3.6,12.53l-11.35,39.38l-7.9-27.54c-10.76-37.5-48.56-62.23-88.38-55.32
c-33.26,5.82-57.05,35.68-56.99,69.48v0.79c0,4.34,0.39,8.73,1.13,13.18c0.18,1.02,0.37,2.03,0.6,3.03
c1.84,8.31,10.93,12.73,18.49,8.8v0c5.36-2.79,7.84-8.89,6.42-14.77c-0.85-3.54-1.28-7.23-1.23-11.03
c0-25.02,20.48-45.5,45.55-45.2c7.6,0.1,15.59,2.07,23.59,6.37c13.52,7.3,23.15,20.18,27.34,34.94l13.32,46.34
c1.73,5.97,6.22,11,12.24,12.58c9.62,2.62,19-3.06,21.51-12.04l16.09-56.7l0.2-0.1l16.09,56.85c1.63,5.68,5.87,10.41,11.55,11.99
c9.13,2.57,18.11-2.66,20.67-11.2l24.13-79.6C475.35,209.85,468.64,201.56,459.81,202.55z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,42 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}

View File

@@ -0,0 +1,45 @@
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Layout from "./components/Layout";
import Login from "./pages/Login";
import Home from "./pages/Home";
import GenerateImage from "./pages/GenerateImage";
import ApiPlaceholder from "./pages/ApiPlaceholder";
import GetMe from "./pages/auth/GetMe";
import SendEmail from "./pages/core/SendEmail";
import EntityTester from "./pages/EntityTester";
import InvokeLLM from "./pages/core/InvokeLLM";
import UploadFile from "./pages/core/UploadFile";
import UploadPrivateFile from "./pages/core/UploadPrivateFile";
import CreateSignedUrl from "./pages/core/CreateSignedUrl";
function App() {
return (
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
{/* Auth APIs */}
<Route path="/auth/me" element={<GetMe />} />
<Route path="/auth/update-me" element={<ApiPlaceholder title="Update Me" />} />
{/* Core APIs */}
<Route path="/core/send-email" element={<SendEmail />} />
<Route path="/core/invoke-llm" element={<InvokeLLM />} />
<Route path="/core/upload-file" element={<UploadFile />} />
<Route path="/core/upload-private-file" element={<UploadPrivateFile />} />
<Route path="/core/create-signed-url" element={<CreateSignedUrl />} />
<Route path="/core/extract-data" element={<ApiPlaceholder title="Extract Data from File" />} />
<Route path="/core/generate-image" element={<GenerateImage />} />
{/* Entity APIs */}
<Route path="/entities" element={<EntityTester />} />
</Route>
</Routes>
</Router>
);
}
export default App;

View File

@@ -0,0 +1,22 @@
import axios from "axios";
import { auth } from "../firebase";
const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL, // You will need to add this to your .env file
});
apiClient.interceptors.request.use(
async (config) => {
const user = auth.currentUser;
if (user) {
const token = await user.getIdToken();
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
export default apiClient;

View File

@@ -0,0 +1,513 @@
import apiClient from './client';
import { auth, dataConnect } from '../firebase';
import { signOut } from 'firebase/auth';
import * as dcSdk from '@dataconnect/generated'; // listEvents, createEvent, etc.
// --- Auth Module ---
const authModule = {
/**
* Fetches the currently authenticated user's profile from the backend.
* @returns {Promise<object>} The user profile.
*/
me: async () => {
const { data } = await apiClient.get('/auth/me');
return data;
},
/**
* Logs the user out.
* @param {string} [redirectUrl] - Optional URL to redirect to after logout.
*/
logout: async (redirectUrl) => {
await signOut(auth);
if (redirectUrl) {
window.location.href = redirectUrl;
}
},
/**
* Checks if a user is currently authenticated.
* @returns {boolean} True if a user is authenticated.
*/
isAuthenticated: () => {
return !!auth.currentUser;
},
};
// --- Core Integrations Module ---
const coreIntegrationsModule = {
/**
* Sends an email.
* @param {object} params - { to, subject, body }
* @returns {Promise<object>} API response.
*/
SendEmail: async (params) => {
const { data } = await apiClient.post('/sendEmail', params);
return data;
},
/**
* Invokes a large language model.
* @param {object} params - { prompt, response_json_schema, file_urls }
* @returns {Promise<object>} API response.
*/
InvokeLLM: async (params) => {
const { data } = await apiClient.post('/invokeLLM', params);
return data;
},
/**
* Uploads a public file.
* @param {File} file - The file to upload.
* @returns {Promise<object>} API response with file_url.
*/
UploadFile: async ({ file }) => {
const formData = new FormData();
formData.append('file', file);
const { data } = await apiClient.post('/uploadFile', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return data;
},
/**
* Uploads a private file.
* @param {File} file - The file to upload.
* @returns {Promise<object>} API response with file_uri.
*/
UploadPrivateFile: async ({ file }) => {
const formData = new FormData();
formData.append('file', file);
const { data } = await apiClient.post('/uploadPrivateFile', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return data;
},
/**
* Creates a temporary signed URL for a private file.
* @param {object} params - { file_uri, expires_in }
* @returns {Promise<object>} API response with signed_url.
*/
CreateFileSignedUrl: async (params) => {
const { data } = await apiClient.post('/createSignedUrl', params);
return data;
},
};
// --- Entities Module ---
// Based on docs/07-reference-base44-api-export.md
/*const entityNames = [
"User", "Event", "Staff", "Vendor", "VendorRate", "Invoice", "Business",
"Certification", "Team", "Conversation", "Message", "ActivityLog",
"Enterprise", "Sector", "Partner", "Order", "Shift"
];
const entitiesModule = {};
entityNames.forEach(entityName => {
// This factory creates a standard set of CRUD-like methods for each entity.
// It assumes a consistent RESTful endpoint structure: /entities/{EntityName}/{method}
entitiesModule[entityName] = {
get: async (params) => {
const { data } = await apiClient.get(`/entities/${entityName}/get`, { params });
return data;
},
create: async (params) => {
const { data } = await apiClient.post(`/entities/${entityName}/create`, params);
return data;
},
update: async (params) => {
const { data } = await apiClient.post(`/entities/${entityName}/update`, params);
return data;
},
delete: async (params) => {
const { data } = await apiClient.post(`/entities/${entityName}/delete`, params);
return data;
},
filter: async (params) => {
const { data } = await apiClient.post(`/entities/${entityName}/filter`, params);
return data;
},
list: async () => {
// Assuming a 'filter' with no params can act as 'list'
const { data } = await apiClient.post(`/entities/${entityName}/filter`, {});
return data;
}
};
});*/
const dataconnectEntityConfig = {
User: {
list: 'listUsers',
get: 'getUserById',
create: 'createUser',
update: 'updateUser',
delete: 'deleteUser',
filter: 'filterUsers',
},
Event: {
list: 'listEvents',
create: 'createEvent',
get: 'getEventById',
update: 'updateEvent',
delete: 'deleteEvent',
filter: 'filterEvents',
},
Staff: {
list: 'listStaff',
create: 'createStaff',
get: 'getStaffById',
update: 'updateStaff',
delete: 'deleteStaff',
filter: 'filterStaff',
},
Vendor: {
list: 'listVendor',
get: 'getVendorById',
create: 'createVendor',
update: 'updateVendor',
delete: 'deleteVendor',
filter: 'filterVendors',
},
VendorRate: {
list: 'listVendorRate',
get: 'getVendorRateById',
create: 'createVendorRate',
update: 'updateVendorRate',
delete: 'deleteVendorRate',
filter: 'filterVendorRates',
},
VendorDefaultSetting:{
list: 'listVendorDefaultSettings',
get: 'getVendorDefaultSettingById',
create: 'createVendorDefaultSetting',
update: 'updateVendorDefaultSetting',
delete: 'deleteVendorDefaultSetting',
filter: 'filterVendorDefaultSettings',
},
Invoice:{
list: 'listInvoice',
get: 'getInvoiceById',
create: 'createInvoice',
update: 'updateInvoice',
delete: 'deleteInvoice',
filter: 'filterInvoices',
},
Business:{
list: 'listBusiness',
get: 'getBusinessById',
create: 'createBusiness',
update: 'updateBusiness',
delete: 'deleteBusiness',
filter: 'filterBusiness',
},
Certification:{
list: 'listCertification',
get: 'getCertificationById',
create: 'createCertification',
update: 'updateCertification',
delete: 'deleteCertification',
filter: 'filterCertification',
},
Team:{
list: 'listTeam',
get: 'getTeamById',
create: 'createTeam',
update: 'updateTeam',
delete: 'deleteTeam',
filter: 'filterTeam',
},
TeamMember: {
list: 'listTeamMember',
get: 'getTeamMemberById',
create: 'createTeamMember',
update: 'updateTeamMember',
delete: 'deleteTeamMember',
filter: 'filterTeamMember',
},
TeamHub: {
list: 'listTeamHub',
get: 'getTeamHubById',
create: 'createTeamHub',
update: 'updateTeamHub',
delete: 'deleteTeamHub',
filter: 'filterTeamHub',
},
TeamMemberInvite: {
list: 'listTeamMemberInvite',
get: 'getTeamMemberInviteById',
create: 'createTeamMemberInvite',
update: 'updateTeamMemberInvite',
delete: 'deleteTeamMemberInvite',
filter: 'filterTeamMemberInvite',
},
Conversation:{
list: 'listConversation',
get: 'getConversationById',
create: 'createConversation',
update: 'updateConversation',
delete: 'deleteConversation',
filter: 'filterConversation',
},
Message:{
list: 'listMessage',
get: 'getMessageById',
create: 'createMessage',
update: 'updateMessage',
delete: 'deleteMessage',
filter: 'filterMessage',
},
ActivityLog:{
list: 'listActivityLog',
get: 'getActivityLogById',
create: 'createActivityLog',
update: 'updateActivityLog',
delete: 'deleteActivityLog',
filter: 'filterActivityLog',
},
Enterprise:{
list: 'listEnterprise',
get: 'getEnterpriseById',
create: 'createEnterprise',
update: 'updateEnterprise',
delete: 'deleteEnterprise',
filter: 'filterEnterprise',
},
Sector:{
},
Partner:{
},
Order:{
list: 'listOrder',
get: 'getOrderById',
create: 'UpdateOrder',
update: 'updateEnterprise',
delete: 'deleteEnterprise',
filter: 'filterOrder',
},
Shift:{
}
};
// Helper for methods not implemented
const notImplemented = (entityName, method) => async () => {
throw new Error(`${entityName}.${method} is not implemented yet for Data Connect`);
};
// --- Entities Module ( Data Connect, without REST Base44) ---
const entitiesModule = {};
Object.entries(dataconnectEntityConfig).forEach(([entityName, ops]) => {
entitiesModule[entityName] = {
get: notImplemented(entityName, 'get'),
update: notImplemented(entityName, 'update'),
delete: notImplemented(entityName, 'delete'),
filter: notImplemented(entityName, 'filter'),
list: notImplemented(entityName, 'list'),
create: notImplemented(entityName, 'create'),
// list
...(ops.list && {
list: async (params) => {
const fn = dcSdk[ops.list];
if (typeof fn !== 'function') {
throw new Error(
`Data Connect operation "${ops.list}" not found for entity "${entityName}".`
);
}
return fn(dataConnect);
},
}),
// create
...(ops.create && {
create: async (params) => {
const fn = dcSdk[ops.create];
if (typeof fn !== 'function') {
throw new Error(
`Data Connect operation "${ops.create}" not found for entity "${entityName}".`
);
}
const { data } = params ?? {};
if (!data) {
throw new Error(
`${entityName}.create expects a payload like { data: { ...fields } }`
);
}
return fn(dataConnect, data);
},
}),
//get
...(ops.get && {
get: async (params) => {
const fn = dcSdk[ops.get];
if (typeof fn !== 'function') {
throw new Error(
`Data Connect operation "${ops.get}" not found for entity "${entityName}".`
);
}
if (!params || typeof params !== 'object') {
throw new Error(`${entityName}.get expects an object of variables (e.g. { id })`);
}
return fn(dataConnect, params);
},
}),
//update
...(ops.update && {
update: async (params) => {
const fn = dcSdk[ops.update];
if (typeof fn !== 'function') {
throw new Error(
`Data Connect operation "${ops.update}" not found for entity "${entityName}".`
);
}
if (!params || typeof params !== 'object') {
throw new Error(
`${entityName}.update expects an object of variables matching the GraphQL mutation`
);
}
const { id, data } = params;
if (!id) {
throw new Error(`${entityName}.update requires an "id" field`);
}
if (!data || typeof data !== 'object') {
throw new Error(
`${entityName}.update requires a "data" object with the fields to update`
);
}
const vars = { id, ...data };
return fn(dataConnect, vars);
},
}),
// delete
...(ops.delete && {
delete: async (params) => {
const fn = dcSdk[ops.delete];
if (typeof fn !== 'function') {
throw new Error(
`Data Connect operation "${ops.delete}" not found for entity "${entityName}".`
);
}
if (!params || typeof params !== 'object') {
throw new Error(
`${entityName}.delete expects an object like { id }`
);
}
const { id } = params;
if (!id) {
throw new Error(`${entityName}.delete requires an "id" field`);
}
// Data Connect solo espera { id } como variables
return fn(dataConnect, { id });
},
}),
// filter
...(ops.filter && {
filter: async (params) => {
const fn = dcSdk[ops.filter];
if (typeof fn !== 'function') {
throw new Error(
`Data Connect operation "${ops.filter}" not found for entity "${entityName}".`
);
}
if (!params) {
if (ops.list) {//if no params, call to list()
const listFn = dcSdk[ops.list];
if (typeof listFn !== 'function') {
throw new Error(
`Data Connect operation "${ops.list}" not found for entity "${entityName}".`
);
}
return listFn(dataConnect);
}
throw new Error(`${entityName}.filter expects params or a list operation`);
}
const rawFilters = params.filters ?? params;
const variables = {};
for (const [key, value] of Object.entries(rawFilters)) {//cleaning undefined/null/'' values
if (value !== undefined && value !== null && value !== '') {
variables[key] = value;
}
}
// if no valid filters, call to list()
if (Object.keys(variables).length === 0) {
if (ops.list) {
const listFn = dcSdk[ops.list];
if (typeof listFn !== 'function') {
throw new Error(
`Data Connect operation "${ops.list}" not found for entity "${entityName}".`
);
}
return listFn(dataConnect);
}
throw new Error(`${entityName}.filter received no valid filters and no list operation`);
}
return fn(dataConnect, variables);
},
}),
};
});
// --- Main SDK Export ---
export const krowSDK = {
auth: authModule,
integrations: {
Core: coreIntegrationsModule,
},
entities: entitiesModule,
};

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -0,0 +1,38 @@
const ApiResponse = ({ response, error, loading }) => {
if (loading) {
return (
<div className="mt-4">
<h3 className="text-lg font-semibold text-slate-800 mb-2">Response</h3>
<div className="bg-slate-100 border border-slate-200 rounded-lg p-4">
<p className="text-slate-500">Loading...</p>
</div>
</div>
);
}
if (error) {
return (
<div className="mt-4">
<h3 className="text-lg font-semibold text-red-800 mb-2">Error</h3>
<pre className="bg-red-50 border border-red-200 text-red-700 rounded-lg p-4 text-sm whitespace-pre-wrap">
{JSON.stringify(error, null, 2)}
</pre>
</div>
);
}
if (response) {
return (
<div className="mt-4">
<h3 className="text-lg font-semibold text-slate-800 mb-2">Response</h3>
<pre className="bg-slate-100 border border-slate-200 rounded-lg p-4 text-sm whitespace-pre-wrap">
{JSON.stringify(response, null, 2)}
</pre>
</div>
);
}
return null;
};
export default ApiResponse;

View File

@@ -0,0 +1,125 @@
import { Link, Navigate, Outlet, useLocation } from "react-router-dom";
import { useAuthState } from "react-firebase-hooks/auth";
import { auth } from "../firebase";
import { krowSDK } from "@/api/krowSDK";
import { Button } from "@/components/ui/button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { ChevronDown } from "lucide-react";
import { useState } from "react";
const navLinks = {
auth: [
{ path: "/auth/me", title: "Get Me" },
{ path: "/auth/update-me", title: "Update Me" },
],
core: [
{ path: "/core/send-email", title: "Send Email" },
{ path: "/core/invoke-llm", title: "Invoke LLM" },
{ path: "/core/upload-file", title: "Upload File" },
{ path: "/core/upload-private-file", title: "Upload Private File" },
{ path: "/core/create-signed-url", title: "Create Signed URL" },
{ path: "/core/extract-data", title: "Extract Data from File" },
{ path: "/core/generate-image", title: "Generate Image" },
],
entities: [
{ path: "/entities", title: "Entity API Tester" }
]
};
const NavSection = ({ title, links }) => {
const location = useLocation();
const [isOpen, setIsOpen] = useState(true);
const navLinkClasses = (path) =>
`flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors ${
location.pathname === path
? "bg-slate-200 text-slate-900"
: "text-slate-600 hover:bg-slate-100"
}`;
return (
<Collapsible open={isOpen} onOpenChange={setIsOpen}>
<CollapsibleTrigger className="w-full">
<div className="flex items-center justify-between px-3 py-2">
<h2 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">
{title}
</h2>
<ChevronDown className={`w-4 h-4 text-slate-400 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
</div>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-1">
{links.map((api) => (
<Link key={api.path} to={api.path} className={navLinkClasses(api.path)}>
{api.title}
</Link>
))}
</CollapsibleContent>
</Collapsible>
);
}
const Layout = () => {
const [user, loading] = useAuthState(auth);
const location = useLocation();
if (loading) {
return (
<div className="flex items-center justify-center h-screen">
<div>Loading...</div>
</div>
);
}
if (!user) {
return <Navigate to="/login" />;
}
const handleLogout = () => {
krowSDK.auth.logout();
};
return (
<div className="flex h-screen bg-slate-50">
{/* Sidebar */}
<aside className="w-72 bg-white border-r border-slate-200 flex flex-col">
<div className="p-6 border-b border-slate-200">
<div className="flex items-center space-x-3">
<img src="/logo.svg" alt="Krow Logo" className="h-12 w-12" />
<div>
<h1 className="text-xl font-bold text-slate-900">KROW</h1>
<p className="text-xs text-slate-500">API Test Harness ({import.meta.env.VITE_HARNESS_ENVIRONMENT})</p>
</div>
</div>
</div>
<nav className="flex-1 overflow-y-auto p-4 space-y-2">
<NavSection title="Auth" links={navLinks.auth} />
<NavSection title="Core Integrations" links={navLinks.core} />
<NavSection title="Entities" links={navLinks.entities} />
</nav>
<div className="p-4 border-t border-slate-200">
<div className="text-sm text-slate-600 truncate mb-2" title={user.email}>{user.email}</div>
<Button onClick={handleLogout} className="w-full">
Logout
</Button>
</div>
</aside>
{/* Main Content */}
<main className="flex-1 overflow-y-auto">
<div className="p-8">
<Outlet />
</div>
</main>
</div>
);
};
export default Layout;

View File

@@ -0,0 +1,120 @@
import { useState } from "react";
import apiClient from "../api/client";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
const ServiceTester = ({ serviceName, serviceDescription, endpoint, fields }) => {
const [formData, setFormData] = useState({});
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const handleChange = (e) => {
const { name, value, files } = e.target;
if (files) {
setFormData({ ...formData, [name]: files[0] });
} else {
setFormData({ ...formData, [name]: value });
}
};
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
setResponse(null);
const data = new FormData();
for (const key in formData) {
data.append(key, formData[key]);
}
try {
const res = await apiClient.post(endpoint, data);
setResponse(res.data);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<div className="max-w-4xl mx-auto">
<div className="mb-8">
<h1 className="text-3xl font-bold text-slate-900">{serviceName}</h1>
<p className="text-slate-600 mt-1">{serviceDescription}</p>
</div>
<form onSubmit={handleSubmit}>
<Card>
<CardHeader>
<CardTitle>Parameters</CardTitle>
<CardDescription>
Fill in the required parameters to execute the service.
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
{fields.map((field) => (
<div key={field.name} className="grid w-full max-w-sm items-center gap-1.5">
<Label htmlFor={field.name}>{field.label}</Label>
{field.type === "textarea" ? (
<Textarea
id={field.name}
name={field.name}
onChange={handleChange}
placeholder={field.placeholder}
/>
) : (
<Input
id={field.name}
name={field.name}
type={field.type}
onChange={handleChange}
placeholder={field.placeholder}
/>
)}
</div>
))}
</CardContent>
<CardFooter>
<Button type="submit" disabled={loading}>
{loading ? "Executing..." : "Execute"}
</Button>
</CardFooter>
</Card>
</form>
{response && (
<div className="mt-8">
<h2 className="text-xl font-bold text-slate-900 mb-2">Response</h2>
<Card>
<CardContent className="p-4">
<pre className="text-sm overflow-x-auto bg-slate-900 text-white p-4 rounded-md">
{JSON.stringify(response, null, 2)}
</pre>
</CardContent>
</Card>
</div>
)}
{error && (
<div className="mt-8">
<h2 className="text-xl font-bold text-red-600 mb-2">Error</h2>
<Card className="border-red-500">
<CardContent className="p-4">
<pre className="text-sm overflow-x-auto bg-red-50 text-red-800 p-4 rounded-md">
{JSON.stringify(error, null, 2)}
</pre>
</CardContent>
</Card>
</div>
)}
</div>
);
};
export default ServiceTester;

View File

@@ -0,0 +1,48 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props} />
);
})
Button.displayName = "Button"
export { Button, buttonVariants }

View File

@@ -0,0 +1,50 @@
import * as React from "react"
import { cn } from "@/lib/utils"
const Card = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("rounded-xl border bg-card text-card-foreground shadow", className)}
{...props} />
))
Card.displayName = "Card"
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props} />
))
CardHeader.displayName = "CardHeader"
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("font-semibold leading-none tracking-tight", className)}
{...props} />
))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props} />
))
CardDescription.displayName = "CardDescription"
const CardContent = React.forwardRef(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props} />
))
CardFooter.displayName = "CardFooter"
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

View File

@@ -0,0 +1,11 @@
"use client"
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
const Collapsible = CollapsiblePrimitive.Root
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
export { Collapsible, CollapsibleTrigger, CollapsibleContent }

View File

@@ -0,0 +1,19 @@
import * as React from "react"
import { cn } from "@/lib/utils"
const Input = React.forwardRef(({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
ref={ref}
{...props} />
);
})
Input.displayName = "Input"
export { Input }

View File

@@ -0,0 +1,16 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva } from "class-variance-authority";
import { cn } from "@/lib/utils"
const labelVariants = cva(
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
)
const Label = React.forwardRef(({ className, ...props }, ref) => (
<LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
))
Label.displayName = LabelPrimitive.Root.displayName
export { Label }

View File

@@ -0,0 +1,105 @@
"use client"
import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { ChevronDown } from "lucide-react"
import { cn } from "@/lib/utils"
const Select = SelectPrimitive.Root
const SelectGroup = SelectPrimitive.Group
const SelectValue = SelectPrimitive.Value
const SelectTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDown className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
const SelectContent = React.forwardRef(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName
const SelectLabel = React.forwardRef(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName
const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<ChevronDown className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName
const SelectSeparator = React.forwardRef(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
}

View File

@@ -0,0 +1,18 @@
import * as React from "react"
import { cn } from "@/lib/utils"
const Textarea = React.forwardRef(({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className
)}
ref={ref}
{...props} />
);
})
Textarea.displayName = "Textarea"
export { Textarea }

View File

@@ -0,0 +1,9 @@
{
"description": "A set of guides for interacting with the generated firebase dataconnect sdk",
"mcpServers": {
"firebase": {
"command": "npx",
"args": ["-y", "firebase-tools@latest", "experimental:mcp"]
}
}
}

View File

@@ -0,0 +1,62 @@
# Setup
If the user hasn't already installed the SDK, always run the user's node package manager of choice, and install the package in the directory ../package.json.
For more information on where the library is located, look at the connector.yaml file.
```ts
import { initializeApp } from 'firebase/app';
initializeApp({
// fill in your project config here using the values from your Firebase project or from the `firebase_get_sdk_config` tool from the Firebase MCP server.
});
```
Then, you can run the SDK as needed.
```ts
import { ... } from '@dataconnect/generated';
```
## React
### Setup
The user should make sure to install the `@tanstack/react-query` package, along with `@tanstack-query-firebase/react` and `firebase`.
Then, they should initialize Firebase:
```ts
import { initializeApp } from 'firebase/app';
initializeApp(firebaseConfig); /* your config here. To generate this, you can use the `firebase_sdk_config` MCP tool */
```
Then, they should add a `QueryClientProvider` to their root of their application.
Here's an example:
```ts
import { initializeApp } from 'firebase/app';
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const firebaseConfig = {
/* your config here. To generate this, you can use the `firebase_sdk_config` MCP tool */
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
// Create a TanStack Query client instance
const queryClient = new QueryClient();
function App() {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<MyApplication />
</QueryClientProvider>
)
}
render(<App />, document.getElementById('root'));
```

View File

@@ -0,0 +1,109 @@
# Basic Usage
Always prioritize using a supported framework over using the generated SDK
directly. Supported frameworks simplify the developer experience and help ensure
best practices are followed.
### React
For each operation, there is a wrapper hook that can be used to call the operation.
Here are all of the hooks that get generated:
```ts
import { useCreateMessage, useUpdateMessage, useDeleteMessage, useCreateStaff, useUpdateStaff, useDeleteStaff, useListTeamMemberInvite, useGetTeamMemberInviteById, useFilterTeamMemberInvite, useCreateVendor } from '@dataconnect/generated/react';
// The types of these hooks are available in react/index.d.ts
const { data, isPending, isSuccess, isError, error } = useCreateMessage(createMessageVars);
const { data, isPending, isSuccess, isError, error } = useUpdateMessage(updateMessageVars);
const { data, isPending, isSuccess, isError, error } = useDeleteMessage(deleteMessageVars);
const { data, isPending, isSuccess, isError, error } = useCreateStaff(createStaffVars);
const { data, isPending, isSuccess, isError, error } = useUpdateStaff(updateStaffVars);
const { data, isPending, isSuccess, isError, error } = useDeleteStaff(deleteStaffVars);
const { data, isPending, isSuccess, isError, error } = useListTeamMemberInvite();
const { data, isPending, isSuccess, isError, error } = useGetTeamMemberInviteById(getTeamMemberInviteByIdVars);
const { data, isPending, isSuccess, isError, error } = useFilterTeamMemberInvite(filterTeamMemberInviteVars);
const { data, isPending, isSuccess, isError, error } = useCreateVendor(createVendorVars);
```
Here's an example from a different generated SDK:
```ts
import { useListAllMovies } from '@dataconnect/generated/react';
function MyComponent() {
const { isLoading, data, error } = useListAllMovies();
if(isLoading) {
return <div>Loading...</div>
}
if(error) {
return <div> An Error Occurred: {error} </div>
}
}
// App.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import MyComponent from './my-component';
function App() {
const queryClient = new QueryClient();
return <QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
}
```
## Advanced Usage
If a user is not using a supported framework, they can use the generated SDK directly.
Here's an example of how to use it with the first 5 operations:
```js
import { createMessage, updateMessage, deleteMessage, createStaff, updateStaff, deleteStaff, listTeamMemberInvite, getTeamMemberInviteById, filterTeamMemberInvite, createVendor } from '@dataconnect/generated';
// Operation CreateMessage: For variables, look at type CreateMessageVars in ../index.d.ts
const { data } = await CreateMessage(dataConnect, createMessageVars);
// Operation UpdateMessage: For variables, look at type UpdateMessageVars in ../index.d.ts
const { data } = await UpdateMessage(dataConnect, updateMessageVars);
// Operation DeleteMessage: For variables, look at type DeleteMessageVars in ../index.d.ts
const { data } = await DeleteMessage(dataConnect, deleteMessageVars);
// Operation CreateStaff: For variables, look at type CreateStaffVars in ../index.d.ts
const { data } = await CreateStaff(dataConnect, createStaffVars);
// Operation UpdateStaff: For variables, look at type UpdateStaffVars in ../index.d.ts
const { data } = await UpdateStaff(dataConnect, updateStaffVars);
// Operation DeleteStaff: For variables, look at type DeleteStaffVars in ../index.d.ts
const { data } = await DeleteStaff(dataConnect, deleteStaffVars);
// Operation listTeamMemberInvite:
const { data } = await ListTeamMemberInvite(dataConnect);
// Operation getTeamMemberInviteById: For variables, look at type GetTeamMemberInviteByIdVars in ../index.d.ts
const { data } = await GetTeamMemberInviteById(dataConnect, getTeamMemberInviteByIdVars);
// Operation filterTeamMemberInvite: For variables, look at type FilterTeamMemberInviteVars in ../index.d.ts
const { data } = await FilterTeamMemberInvite(dataConnect, filterTeamMemberInviteVars);
// Operation CreateVendor: For variables, look at type CreateVendorVars in ../index.d.ts
const { data } = await CreateVendor(dataConnect, createVendorVars);
```

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
{"type":"module"}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
{
"name": "@dataconnect/generated",
"version": "1.0.0",
"author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)",
"description": "Generated SDK For krow-connector",
"license": "Apache-2.0",
"engines": {
"node": " >=18.0"
},
"typings": "index.d.ts",
"module": "esm/index.esm.js",
"main": "index.cjs.js",
"browser": "esm/index.esm.js",
"exports": {
".": {
"types": "./index.d.ts",
"require": "./index.cjs.js",
"default": "./esm/index.esm.js"
},
"./react": {
"types": "./react/index.d.ts",
"require": "./react/index.cjs.js",
"import": "./react/esm/index.esm.js",
"default": "./react/esm/index.esm.js"
},
"./package.json": "./package.json"
},
"peerDependencies": {
"firebase": "^11.3.0 || ^12.0.0",
"@tanstack-query-firebase/react": "^2.0.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,970 @@
import { createMessageRef, updateMessageRef, deleteMessageRef, createStaffRef, updateStaffRef, deleteStaffRef, listTeamMemberInviteRef, getTeamMemberInviteByIdRef, filterTeamMemberInviteRef, createVendorRef, updateVendorRef, deleteVendorRef, createActivityLogRef, updateActivityLogRef, deleteActivityLogRef, createAssignmentRef, updateAssignmentRef, deleteAssignmentRef, createCertificationRef, updateCertificationRef, deleteCertificationRef, listCertificationRef, getCertificationByIdRef, filterCertificationRef, listConversationRef, getConversationByIdRef, filterConversationRef, createShiftRef, updateShiftRef, deleteShiftRef, listShiftRef, getShiftByIdRef, filterShiftRef, createTeamHubRef, updateTeamHubRef, deleteTeamHubRef, listEnterpriseRef, getEnterpriseByIdRef, filterEnterpriseRef, listInvoiceRef, getInvoiceByIdRef, filterInvoicesRef, createOrderRef, updateOrderRef, deleteOrderRef, createSectorRef, updateSectorRef, deleteSectorRef, listTeamMemberRef, getTeamMemberByIdRef, filterTeamMemberRef, createUserRef, updateUserRef, deleteUserRef, listUsersRef, getUserByIdRef, filterUsersRef, listVendorDefaultSettingsRef, getVendorDefaultSettingByIdRef, filterVendorDefaultSettingsRef, listAssignmentRef, getAssignmentByIdRef, filterAssignmentRef, listEventsRef, getEventByIdRef, filterEventsRef, listMessageRef, getMessageByIdRef, filterMessageRef, listSectorRef, getSectorByIdRef, filterSectorRef, listStaffRef, getStaffByIdRef, filterStaffRef, createTeamMemberInviteRef, updateTeamMemberInviteRef, deleteTeamMemberInviteRef, createVendorDefaultSettingRef, updateVendorDefaultSettingRef, deleteVendorDefaultSettingRef, createVendorRateRef, updateVendorRateRef, deleteVendorRateRef, createEnterpriseRef, updateEnterpriseRef, deleteEnterpriseRef, listOrderRef, getOrderByIdRef, filterOrderRef, createPartnerRef, updatePartnerRef, deletePartnerRef, listPartnerRef, getPartnerByIdRef, filterPartnerRef, createTeamMemberRef, updateTeamMemberRef, deleteTeamMemberRef, listVendorRef, getVendorByIdRef, filterVendorsRef, listWorkforceRef, getWorkforceByIdRef, filterWorkforceRef, listActivityLogRef, getActivityLogByIdRef, filterActivityLogRef, createConversationRef, updateConversationRef, deleteConversationRef, createInvoiceRef, updateInvoiceRef, deleteInvoiceRef, listTeamRef, getTeamByIdRef, filterTeamRef, listVendorRateRef, getVendorRateByIdRef, filterVendorRatesRef, createBusinessRef, updateBusinessRef, deleteBusinessRef, listTeamHubRef, getTeamHubByIdRef, filterTeamHubRef, createEventRef, updateEventRef, deleteEventRef, createTeamRef, updateTeamRef, deleteTeamRef, createWorkforceRef, updateWorkforceRef, deleteWorkforceRef, listBusinessRef, getBusinessByIdRef, filterBusinessRef, connectorConfig } from '../../esm/index.esm.js';
import { validateArgs, CallerSdkTypeEnum } from 'firebase/data-connect';
import { useDataConnectQuery, useDataConnectMutation, validateReactArgs } from '@tanstack-query-firebase/react/data-connect';
export function useCreateMessage(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createMessageRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateMessage(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateMessageRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteMessage(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteMessageRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateStaff(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createStaffRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateStaff(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateStaffRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteStaff(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteStaffRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listTeamMemberInviteRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetTeamMemberInviteById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamMemberInviteByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterTeamMemberInvite(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamMemberInviteRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateVendor(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createVendorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateVendor(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateVendorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteVendor(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteVendorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateActivityLog(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createActivityLogRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateActivityLog(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateActivityLogRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteActivityLog(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteActivityLogRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateAssignment(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createAssignmentRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateAssignment(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateAssignmentRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteAssignment(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteAssignmentRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateCertification(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createCertificationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateCertification(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateCertificationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteCertification(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteCertificationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListCertification(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listCertificationRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetCertificationById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getCertificationByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterCertification(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterCertificationRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListConversation(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listConversationRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetConversationById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getConversationByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterConversation(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterConversationRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateShift(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createShiftRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateShift(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateShiftRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteShift(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteShiftRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListShift(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listShiftRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetShiftById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getShiftByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterShift(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterShiftRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateTeamHub(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamHubRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateTeamHub(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamHubRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteTeamHub(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamHubRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListEnterprise(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listEnterpriseRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetEnterpriseById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getEnterpriseByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterEnterprise(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterEnterpriseRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListInvoice(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listInvoiceRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetInvoiceById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getInvoiceByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterInvoices(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterInvoicesRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateOrder(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createOrderRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateOrder(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateOrderRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteOrder(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteOrderRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateSector(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createSectorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateSector(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateSectorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteSector(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteSectorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListTeamMember(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listTeamMemberRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetTeamMemberById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamMemberByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterTeamMember(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamMemberRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateUser(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createUserRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateUser(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateUserRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteUser(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteUserRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListUsers(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listUsersRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetUserById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getUserByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterUsers(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterUsersRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListVendorDefaultSettings(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listVendorDefaultSettingsRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetVendorDefaultSettingById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getVendorDefaultSettingByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterVendorDefaultSettings(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterVendorDefaultSettingsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListAssignment(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listAssignmentRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetAssignmentById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getAssignmentByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterAssignment(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterAssignmentRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListEvents(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = listEventsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetEventById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getEventByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterEvents(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterEventsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListMessage(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listMessageRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetMessageById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getMessageByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterMessage(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterMessageRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListSector(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listSectorRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetSectorById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getSectorByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterSector(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterSectorRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListStaff(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listStaffRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetStaffById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getStaffByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterStaff(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterStaffRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamMemberInviteRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamMemberInviteRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamMemberInviteRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateVendorDefaultSetting(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createVendorDefaultSettingRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateVendorDefaultSetting(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateVendorDefaultSettingRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteVendorDefaultSetting(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteVendorDefaultSettingRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateVendorRate(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createVendorRateRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateVendorRate(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateVendorRateRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteVendorRate(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteVendorRateRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateEnterprise(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createEnterpriseRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateEnterprise(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateEnterpriseRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteEnterprise(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteEnterpriseRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListOrder(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listOrderRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetOrderById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getOrderByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterOrder(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterOrderRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreatePartner(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createPartnerRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdatePartner(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updatePartnerRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeletePartner(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deletePartnerRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListPartner(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listPartnerRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetPartnerById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getPartnerByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterPartner(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterPartnerRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateTeamMember(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamMemberRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateTeamMember(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamMemberRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteTeamMember(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamMemberRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListVendor(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listVendorRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetVendorById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getVendorByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterVendors(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterVendorsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListWorkforce(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listWorkforceRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetWorkforceById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getWorkforceByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterWorkforce(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterWorkforceRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListActivityLog(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listActivityLogRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetActivityLogById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getActivityLogByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterActivityLog(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterActivityLogRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateConversation(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createConversationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateConversation(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateConversationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteConversation(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteConversationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateInvoice(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createInvoiceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateInvoice(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateInvoiceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteInvoice(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteInvoiceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListTeam(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = listTeamRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetTeamById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterTeam(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListVendorRate(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listVendorRateRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetVendorRateById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getVendorRateByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterVendorRates(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterVendorRatesRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateBusiness(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createBusinessRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateBusiness(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateBusinessRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteBusiness(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteBusinessRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListTeamHub(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listTeamHubRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetTeamHubById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamHubByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterTeamHub(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamHubRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateEvent(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createEventRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateEvent(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateEventRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteEvent(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteEventRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateTeam(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateTeam(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteTeam(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useCreateWorkforce(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createWorkforceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useUpdateWorkforce(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateWorkforceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useDeleteWorkforce(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteWorkforceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useListBusiness(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listBusinessRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useGetBusinessById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getBusinessByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
export function useFilterBusiness(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterBusinessRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}

View File

@@ -0,0 +1 @@
{"type":"module"}

View File

@@ -0,0 +1,970 @@
const { createMessageRef, updateMessageRef, deleteMessageRef, createStaffRef, updateStaffRef, deleteStaffRef, listTeamMemberInviteRef, getTeamMemberInviteByIdRef, filterTeamMemberInviteRef, createVendorRef, updateVendorRef, deleteVendorRef, createActivityLogRef, updateActivityLogRef, deleteActivityLogRef, createAssignmentRef, updateAssignmentRef, deleteAssignmentRef, createCertificationRef, updateCertificationRef, deleteCertificationRef, listCertificationRef, getCertificationByIdRef, filterCertificationRef, listConversationRef, getConversationByIdRef, filterConversationRef, createShiftRef, updateShiftRef, deleteShiftRef, listShiftRef, getShiftByIdRef, filterShiftRef, createTeamHubRef, updateTeamHubRef, deleteTeamHubRef, listEnterpriseRef, getEnterpriseByIdRef, filterEnterpriseRef, listInvoiceRef, getInvoiceByIdRef, filterInvoicesRef, createOrderRef, updateOrderRef, deleteOrderRef, createSectorRef, updateSectorRef, deleteSectorRef, listTeamMemberRef, getTeamMemberByIdRef, filterTeamMemberRef, createUserRef, updateUserRef, deleteUserRef, listUsersRef, getUserByIdRef, filterUsersRef, listVendorDefaultSettingsRef, getVendorDefaultSettingByIdRef, filterVendorDefaultSettingsRef, listAssignmentRef, getAssignmentByIdRef, filterAssignmentRef, listEventsRef, getEventByIdRef, filterEventsRef, listMessageRef, getMessageByIdRef, filterMessageRef, listSectorRef, getSectorByIdRef, filterSectorRef, listStaffRef, getStaffByIdRef, filterStaffRef, createTeamMemberInviteRef, updateTeamMemberInviteRef, deleteTeamMemberInviteRef, createVendorDefaultSettingRef, updateVendorDefaultSettingRef, deleteVendorDefaultSettingRef, createVendorRateRef, updateVendorRateRef, deleteVendorRateRef, createEnterpriseRef, updateEnterpriseRef, deleteEnterpriseRef, listOrderRef, getOrderByIdRef, filterOrderRef, createPartnerRef, updatePartnerRef, deletePartnerRef, listPartnerRef, getPartnerByIdRef, filterPartnerRef, createTeamMemberRef, updateTeamMemberRef, deleteTeamMemberRef, listVendorRef, getVendorByIdRef, filterVendorsRef, listWorkforceRef, getWorkforceByIdRef, filterWorkforceRef, listActivityLogRef, getActivityLogByIdRef, filterActivityLogRef, createConversationRef, updateConversationRef, deleteConversationRef, createInvoiceRef, updateInvoiceRef, deleteInvoiceRef, listTeamRef, getTeamByIdRef, filterTeamRef, listVendorRateRef, getVendorRateByIdRef, filterVendorRatesRef, createBusinessRef, updateBusinessRef, deleteBusinessRef, listTeamHubRef, getTeamHubByIdRef, filterTeamHubRef, createEventRef, updateEventRef, deleteEventRef, createTeamRef, updateTeamRef, deleteTeamRef, createWorkforceRef, updateWorkforceRef, deleteWorkforceRef, listBusinessRef, getBusinessByIdRef, filterBusinessRef, connectorConfig } = require('../index.cjs.js');
const { validateArgs, CallerSdkTypeEnum } = require('firebase/data-connect');
const { useDataConnectQuery, useDataConnectMutation, validateReactArgs } = require('@tanstack-query-firebase/react/data-connect');
exports.useCreateMessage = function useCreateMessage(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createMessageRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateMessage = function useUpdateMessage(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateMessageRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteMessage = function useDeleteMessage(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteMessageRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateStaff = function useCreateStaff(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createStaffRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateStaff = function useUpdateStaff(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateStaffRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteStaff = function useDeleteStaff(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteStaffRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListTeamMemberInvite = function useListTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listTeamMemberInviteRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetTeamMemberInviteById = function useGetTeamMemberInviteById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamMemberInviteByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterTeamMemberInvite = function useFilterTeamMemberInvite(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamMemberInviteRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateVendor = function useCreateVendor(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createVendorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateVendor = function useUpdateVendor(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateVendorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteVendor = function useDeleteVendor(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteVendorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateActivityLog = function useCreateActivityLog(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createActivityLogRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateActivityLog = function useUpdateActivityLog(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateActivityLogRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteActivityLog = function useDeleteActivityLog(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteActivityLogRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateAssignment = function useCreateAssignment(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createAssignmentRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateAssignment = function useUpdateAssignment(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateAssignmentRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteAssignment = function useDeleteAssignment(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteAssignmentRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateCertification = function useCreateCertification(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createCertificationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateCertification = function useUpdateCertification(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateCertificationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteCertification = function useDeleteCertification(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteCertificationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListCertification = function useListCertification(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listCertificationRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetCertificationById = function useGetCertificationById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getCertificationByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterCertification = function useFilterCertification(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterCertificationRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListConversation = function useListConversation(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listConversationRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetConversationById = function useGetConversationById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getConversationByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterConversation = function useFilterConversation(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterConversationRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateShift = function useCreateShift(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createShiftRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateShift = function useUpdateShift(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateShiftRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteShift = function useDeleteShift(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteShiftRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListShift = function useListShift(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listShiftRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetShiftById = function useGetShiftById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getShiftByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterShift = function useFilterShift(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterShiftRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateTeamHub = function useCreateTeamHub(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamHubRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateTeamHub = function useUpdateTeamHub(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamHubRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteTeamHub = function useDeleteTeamHub(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamHubRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListEnterprise = function useListEnterprise(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listEnterpriseRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetEnterpriseById = function useGetEnterpriseById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getEnterpriseByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterEnterprise = function useFilterEnterprise(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterEnterpriseRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListInvoice = function useListInvoice(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listInvoiceRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetInvoiceById = function useGetInvoiceById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getInvoiceByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterInvoices = function useFilterInvoices(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterInvoicesRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateOrder = function useCreateOrder(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createOrderRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateOrder = function useUpdateOrder(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateOrderRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteOrder = function useDeleteOrder(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteOrderRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateSector = function useCreateSector(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createSectorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateSector = function useUpdateSector(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateSectorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteSector = function useDeleteSector(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteSectorRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListTeamMember = function useListTeamMember(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listTeamMemberRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetTeamMemberById = function useGetTeamMemberById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamMemberByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterTeamMember = function useFilterTeamMember(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamMemberRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateUser = function useCreateUser(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createUserRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateUser = function useUpdateUser(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateUserRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteUser = function useDeleteUser(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteUserRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListUsers = function useListUsers(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listUsersRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetUserById = function useGetUserById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getUserByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterUsers = function useFilterUsers(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterUsersRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListVendorDefaultSettings = function useListVendorDefaultSettings(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listVendorDefaultSettingsRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetVendorDefaultSettingById = function useGetVendorDefaultSettingById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getVendorDefaultSettingByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterVendorDefaultSettings = function useFilterVendorDefaultSettings(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterVendorDefaultSettingsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListAssignment = function useListAssignment(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listAssignmentRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetAssignmentById = function useGetAssignmentById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getAssignmentByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterAssignment = function useFilterAssignment(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterAssignmentRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListEvents = function useListEvents(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = listEventsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetEventById = function useGetEventById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getEventByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterEvents = function useFilterEvents(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterEventsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListMessage = function useListMessage(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listMessageRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetMessageById = function useGetMessageById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getMessageByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterMessage = function useFilterMessage(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterMessageRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListSector = function useListSector(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listSectorRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetSectorById = function useGetSectorById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getSectorByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterSector = function useFilterSector(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterSectorRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListStaff = function useListStaff(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listStaffRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetStaffById = function useGetStaffById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getStaffByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterStaff = function useFilterStaff(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterStaffRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateTeamMemberInvite = function useCreateTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamMemberInviteRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateTeamMemberInvite = function useUpdateTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamMemberInviteRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteTeamMemberInvite = function useDeleteTeamMemberInvite(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamMemberInviteRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateVendorDefaultSetting = function useCreateVendorDefaultSetting(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createVendorDefaultSettingRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateVendorDefaultSetting = function useUpdateVendorDefaultSetting(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateVendorDefaultSettingRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteVendorDefaultSetting = function useDeleteVendorDefaultSetting(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteVendorDefaultSettingRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateVendorRate = function useCreateVendorRate(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createVendorRateRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateVendorRate = function useUpdateVendorRate(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateVendorRateRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteVendorRate = function useDeleteVendorRate(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteVendorRateRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateEnterprise = function useCreateEnterprise(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createEnterpriseRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateEnterprise = function useUpdateEnterprise(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateEnterpriseRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteEnterprise = function useDeleteEnterprise(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteEnterpriseRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListOrder = function useListOrder(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listOrderRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetOrderById = function useGetOrderById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getOrderByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterOrder = function useFilterOrder(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterOrderRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreatePartner = function useCreatePartner(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createPartnerRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdatePartner = function useUpdatePartner(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updatePartnerRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeletePartner = function useDeletePartner(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deletePartnerRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListPartner = function useListPartner(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listPartnerRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetPartnerById = function useGetPartnerById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getPartnerByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterPartner = function useFilterPartner(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterPartnerRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateTeamMember = function useCreateTeamMember(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamMemberRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateTeamMember = function useUpdateTeamMember(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamMemberRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteTeamMember = function useDeleteTeamMember(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamMemberRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListVendor = function useListVendor(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listVendorRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetVendorById = function useGetVendorById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getVendorByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterVendors = function useFilterVendors(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterVendorsRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListWorkforce = function useListWorkforce(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listWorkforceRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetWorkforceById = function useGetWorkforceById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getWorkforceByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterWorkforce = function useFilterWorkforce(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterWorkforceRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListActivityLog = function useListActivityLog(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listActivityLogRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetActivityLogById = function useGetActivityLogById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getActivityLogByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterActivityLog = function useFilterActivityLog(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterActivityLogRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateConversation = function useCreateConversation(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createConversationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateConversation = function useUpdateConversation(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateConversationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteConversation = function useDeleteConversation(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteConversationRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateInvoice = function useCreateInvoice(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createInvoiceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateInvoice = function useUpdateInvoice(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateInvoiceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteInvoice = function useDeleteInvoice(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteInvoiceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListTeam = function useListTeam(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = listTeamRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetTeamById = function useGetTeamById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterTeam = function useFilterTeam(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListVendorRate = function useListVendorRate(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listVendorRateRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetVendorRateById = function useGetVendorRateById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getVendorRateByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterVendorRates = function useFilterVendorRates(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterVendorRatesRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateBusiness = function useCreateBusiness(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createBusinessRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateBusiness = function useUpdateBusiness(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateBusinessRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteBusiness = function useDeleteBusiness(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteBusinessRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListTeamHub = function useListTeamHub(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listTeamHubRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetTeamHubById = function useGetTeamHubById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getTeamHubByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterTeamHub = function useFilterTeamHub(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterTeamHubRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateEvent = function useCreateEvent(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createEventRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateEvent = function useUpdateEvent(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateEventRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteEvent = function useDeleteEvent(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteEventRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateTeam = function useCreateTeam(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createTeamRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateTeam = function useUpdateTeam(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateTeamRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteTeam = function useDeleteTeam(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteTeamRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useCreateWorkforce = function useCreateWorkforce(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return createWorkforceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useUpdateWorkforce = function useUpdateWorkforce(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return updateWorkforceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useDeleteWorkforce = function useDeleteWorkforce(dcOrOptions, options) {
const { dc: dcInstance, vars: inputOpts } = validateArgs(connectorConfig, dcOrOptions, options);
function refFactory(vars) {
return deleteWorkforceRef(dcInstance, vars);
}
return useDataConnectMutation(refFactory, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useListBusiness = function useListBusiness(dcOrOptions, options) {
const { dc: dcInstance, options: inputOpts } = validateReactArgs(connectorConfig, dcOrOptions, options);
const ref = listBusinessRef(dcInstance);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useGetBusinessById = function useGetBusinessById(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, true);
const ref = getBusinessByIdRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}
exports.useFilterBusiness = function useFilterBusiness(dcOrVars, varsOrOptions, options) {
const { dc: dcInstance, vars: inputVars, options: inputOpts } = validateReactArgs(connectorConfig, dcOrVars, varsOrOptions, options, true, false);
const ref = filterBusinessRef(dcInstance, inputVars);
return useDataConnectQuery(ref, inputOpts, CallerSdkTypeEnum.GeneratedReact);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
{
"name": "@dataconnect/generated-react",
"version": "1.0.0",
"author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)",
"description": "Generated SDK For krow-connector",
"license": "Apache-2.0",
"engines": {
"node": " >=18.0"
},
"typings": "index.d.ts",
"main": "index.cjs.js",
"module": "esm/index.esm.js",
"browser": "esm/index.esm.js",
"peerDependencies": {
"@tanstack-query-firebase/react": "^2.0.0"
}
}

View File

@@ -0,0 +1,20 @@
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getDataConnect } from 'firebase/data-connect';
import { connectorConfig } from '@dataconnect/generated';
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: import.meta.env.VITE_HARNESS_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_HARNESS_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_HARNESS_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_HARNESS_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_HARNESS_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_HARNESS_FIREBASE_APP_ID
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const dataConnect = getDataConnect(app, connectorConfig);
export const auth = getAuth(app);

View File

@@ -0,0 +1,76 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

View File

@@ -0,0 +1,6 @@
import { clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs) {
return twMerge(clsx(inputs))
}

View File

@@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)

View File

@@ -0,0 +1,13 @@
const ApiPlaceholder = ({ title }) => {
return (
<div>
<h1 className="text-3xl font-bold text-slate-900 mb-4">{title}</h1>
<div className="bg-slate-100 border border-slate-200 rounded-lg p-8 text-center">
<p className="text-slate-500">This page is a placeholder for the "{title}" API test harness.</p>
<p className="text-slate-500 mt-2">Implementation is pending.</p>
</div>
</div>
);
};
export default ApiPlaceholder;

View File

@@ -0,0 +1,190 @@
import { useState, useMemo } from "react";
import { krowSDK } from "@/api/krowSDK";
import { Button } from "@/components/ui/button";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import ApiResponse from "@/components/ApiResponse";
import { Textarea } from "@/components/ui/textarea";
import { Label } from "@/components/ui/label";
const entityNames = Object.keys(krowSDK.entities).sort();
const getPrettifiedJSON = (entity, method) => {
// Basic placeholder payloads. A more advanced SDK could provide detailed examples.
const payloads = {
get: { id: "some-id" },
create: { data: { property: "value" } },
update: { id: "some-id", data: { property: "new-value" } },
delete: { id: "some-id" },
filter: { where: { property: { _eq: "value" } } },
list: {}
};
return JSON.stringify(payloads[method] || {}, null, 2);
};
const EntityTester = () => {
const [selectedEntity, setSelectedEntity] = useState(null);
const [selectedMethod, setSelectedMethod] = useState(null);
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [jsonInput, setJsonInput] = useState("");
const [jsonError, setJsonError] = useState(null);
const availableMethods = useMemo(() => {
if (!selectedEntity) return [];
return Object.keys(krowSDK.entities[selectedEntity]);
}, [selectedEntity]);
const handleEntityChange = (entity) => {
setSelectedEntity(entity);
setSelectedMethod(null);
setJsonInput("");
setJsonError(null);
setResponse(null);
setError(null);
};
const handleMethodSelect = (method) => {
setSelectedMethod(method);
setJsonInput(getPrettifiedJSON(selectedEntity, method));
setJsonError(null);
setResponse(null);
setError(null);
};
const handleJsonInputChange = (e) => {
setJsonInput(e.target.value);
try {
JSON.parse(e.target.value);
setJsonError(null);
} catch (err) {
setJsonError("Invalid JSON format");
}
};
const executeApi = async () => {
if (!selectedEntity || !selectedMethod || jsonError) return;
setLoading(true);
setResponse(null);
setError(null);
try {
const params = JSON.parse(jsonInput);
const sdkMethod = krowSDK.entities[selectedEntity][selectedMethod];
const res = await sdkMethod(params);
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
const renderMethodForm = () => {
if (!selectedMethod) {
return (
<div className="mt-4 p-4 text-center text-slate-500 bg-slate-50 rounded-lg">
<p>Select a method to begin.</p>
</div>
);
}
return (
<div className="space-y-4 mt-6">
<h3 className="text-lg font-semibold text-slate-800">
Parameters for <code className="bg-slate-100 p-1 rounded text-sm">/{selectedEntity}/{selectedMethod}</code>
</h3>
{/*
This is a textarea for JSON input. A more advanced implementation could
dynamically generate a form based on the expected parameters of each
SDK method, but that requires metadata about each method's signature
which is not currently available in the mock client.
*/}
<div className="space-y-2">
<Label htmlFor="params">JSON Payload</Label>
<Textarea
id="params"
name="params"
value={jsonInput}
onChange={handleJsonInputChange}
rows={8}
className={`font-mono text-sm ${jsonError ? 'border-red-500 focus-visible:ring-red-500' : ''}`}
/>
{jsonError && <p className="text-xs text-red-600">{jsonError}</p>}
</div>
<Button onClick={executeApi} disabled={loading || !!jsonError}>
{loading ? "Executing..." : "Execute"}
</Button>
</div>
);
};
return (
<div>
<header className="mb-8">
<h1 className="text-3xl font-bold text-slate-900">Entity API Tester</h1>
<p className="text-slate-600 mt-1">
Select an entity and method, provide the required parameters in JSON format, and execute the API call.
</p>
</header>
<Card className="shadow-sm">
<CardHeader>
<CardTitle>API Configuration</CardTitle>
<CardDescription>Choose a Base44 entity and method to interact with.</CardDescription>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 items-start">
<div className="col-span-1">
<Label>Entity</Label>
<Select onValueChange={handleEntityChange} value={selectedEntity || ""}>
<SelectTrigger>
<SelectValue placeholder="Select an entity" />
</SelectTrigger>
<SelectContent>
{entityNames.map(entity => (
<SelectItem key={entity} value={entity}>{entity}</SelectItem>
))}
</SelectContent>
</Select>
</div>
{selectedEntity && (
<div className="col-span-2">
<Label>Method</Label>
<div className="flex flex-wrap items-center gap-2 pt-2">
{availableMethods.map(method => (
<Button
key={method}
variant={selectedMethod === method ? "default" : "outline"}
size="sm"
onClick={() => handleMethodSelect(method)}
>
{method}
</Button>
))}
</div>
</div>
)}
</div>
{renderMethodForm()}
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
export default EntityTester;

View File

@@ -0,0 +1,28 @@
import ServiceTester from "@/components/ServiceTester";
const GenerateImage = () => {
const fields = [
{
name: "prompt",
label: "Prompt",
type: "textarea",
placeholder: "Enter a prompt for the image",
},
{
name: "file",
label: "File",
type: "file",
},
];
return (
<ServiceTester
serviceName="Generate Image"
serviceDescription="Test the Generate Image service"
endpoint="/generate-image"
fields={fields}
/>
);
};
export default GenerateImage;

View File

@@ -0,0 +1,31 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
const Home = () => {
return (
<div className="max-w-4xl mx-auto">
<div className="mb-8">
<h1 className="text-3xl font-bold text-slate-900">Welcome to KROW API Test Harness</h1>
<p className="text-slate-600 mt-1">
Your dedicated tool for rapid and authenticated testing of KROW backend services.
</p>
</div>
<Card>
<CardHeader>
<CardTitle>Get Started</CardTitle>
<CardDescription>
Use the sidebar navigation to select an API category and then choose a specific endpoint to test.
</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm text-slate-700">
This tool automatically handles Firebase authentication, injecting the necessary ID tokens into your API requests.
Simply log in, select an API, provide the required parameters, and execute to see the raw JSON response.
</p>
</CardContent>
</Card>
</div>
);
};
export default Home;

View File

@@ -0,0 +1,37 @@
import { GoogleAuthProvider, signInWithPopup, setPersistence, browserLocalPersistence } from "firebase/auth";
import { useAuthState } from "react-firebase-hooks/auth";
import { Navigate } from "react-router-dom";
import { auth } from "../firebase";
import { Button } from "@/components/ui/button";
const Login = () => {
const [user, loading] = useAuthState(auth);
const handleGoogleLogin = async () => {
const provider = new GoogleAuthProvider();
try {
await setPersistence(auth, browserLocalPersistence);
await signInWithPopup(auth, provider);
} catch (error) {
console.error("Error signing in with Google", error);
}
};
if (loading) {
return <div>Loading...</div>;
}
// If user is logged in, redirect to the home page
if (user) {
return <Navigate to="/" />;
}
// If no user, show the login button
return (
<div className="flex items-center justify-center h-screen">
<Button onClick={handleGoogleLogin}>Sign in with Google</Button>
</div>
);
};
export default Login;

View File

@@ -0,0 +1,49 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import ApiResponse from "@/components/ApiResponse";
import { krowSDK } from "@/api/krowSDK";
const GetMe = () => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const handleGetMe = async () => {
setLoading(true);
setError(null);
setResponse(null);
try {
const res = await krowSDK.auth.me();
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<div>
<h1 className="text-3xl font-bold text-slate-900 mb-4">Get Me</h1>
<p className="text-slate-600 mb-6">Fetches the currently authenticated user's profile.</p>
<Card className="max-w-2xl">
<CardHeader>
<CardTitle>Test `/auth/me`</CardTitle>
</CardHeader>
<CardContent>
<Button onClick={handleGetMe} disabled={loading}>
{loading ? "Loading..." : "Execute"}
</Button>
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
// We need to re-import Card components because they are not globally available.
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
export default GetMe;

View File

@@ -0,0 +1,74 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import ApiResponse from "@/components/ApiResponse";
import { krowSDK } from "@/api/krowSDK";
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card";
const CreateSignedUrl = () => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [formData, setFormData] = useState({
file_uri: "gs://your-bucket/private-file.pdf",
expires_in: 3600,
});
const handleChange = (e) => {
const { id, value } = e.target;
setFormData(prev => ({ ...prev, [id]: value }));
};
const handleCreateUrl = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
setResponse(null);
try {
const params = {
...formData,
expires_in: parseInt(formData.expires_in, 10),
};
const res = await krowSDK.integrations.Core.CreateFileSignedUrl(params);
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<div>
<h1 className="text-3xl font-bold text-slate-900 mb-4">Create Signed URL</h1>
<p className="text-slate-600 mb-6">Tests the `integrations.Core.CreateFileSignedUrl` endpoint.</p>
<Card className="max-w-2xl">
<CardHeader>
<CardTitle>Test `/createSignedUrl`</CardTitle>
<CardDescription>Creates a temporary access URL for a private file stored in GCS.</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleCreateUrl} className="space-y-4">
<div>
<Label htmlFor="file_uri">File URI</Label>
<Input id="file_uri" value={formData.file_uri} onChange={handleChange} />
</div>
<div>
<Label htmlFor="expires_in">Expires In (seconds)</Label>
<Input id="expires_in" type="number" value={formData.expires_in} onChange={handleChange} />
</div>
<Button type="submit" disabled={loading}>
{loading ? "Creating..." : "Create Signed URL"}
</Button>
</form>
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
export default CreateSignedUrl;

View File

@@ -0,0 +1,81 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import ApiResponse from "@/components/ApiResponse";
import { krowSDK } from "@/api/krowSDK";
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
const InvokeLLM = () => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [formData, setFormData] = useState({
prompt: "Extract the total amount from the attached invoice.",
response_json_schema: JSON.stringify({ type: "object", properties: { total_amount: { type: "number" } } }, null, 2),
file_urls: "https://example.com/invoice.pdf",
});
const handleChange = (e) => {
const { id, value } = e.target;
setFormData(prev => ({ ...prev, [id]: value }));
};
const handleInvokeLLM = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
setResponse(null);
try {
const params = {
...formData,
response_json_schema: JSON.parse(formData.response_json_schema),
file_urls: formData.file_urls.split(',').map(url => url.trim()),
};
const res = await krowSDK.integrations.Core.InvokeLLM(params);
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<div>
<h1 className="text-3xl font-bold text-slate-900 mb-4">Invoke LLM</h1>
<p className="text-slate-600 mb-6">Tests the `integrations.Core.InvokeLLM` endpoint.</p>
<Card className="max-w-2xl">
<CardHeader>
<CardTitle>Test `/invokeLLM`</CardTitle>
<CardDescription>Calls a large language model (e.g., Vertex AI).</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleInvokeLLM} className="space-y-4">
<div>
<Label htmlFor="prompt">Prompt</Label>
<Textarea id="prompt" value={formData.prompt} onChange={handleChange} rows={4} />
</div>
<div>
<Label htmlFor="response_json_schema">Response JSON Schema</Label>
<Textarea id="response_json_schema" value={formData.response_json_schema} onChange={handleChange} rows={6} className="font-mono" />
</div>
<div>
<Label htmlFor="file_urls">File URLs (comma-separated)</Label>
<Input id="file_urls" value={formData.file_urls} onChange={handleChange} />
</div>
<Button type="submit" disabled={loading}>
{loading ? "Invoking..." : "Invoke LLM"}
</Button>
</form>
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
export default InvokeLLM;

View File

@@ -0,0 +1,75 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import ApiResponse from "@/components/ApiResponse";
import { krowSDK } from "@/api/krowSDK";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
const SendEmail = () => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [formData, setFormData] = useState({
to: "test@example.com",
subject: "Test Email from Harness",
body: "This is a test email.",
});
const handleChange = (e) => {
const { id, value } = e.target;
setFormData(prev => ({ ...prev, [id]: value }));
};
const handleSendEmail = async (e) => {
e.preventDefault();
setLoading(true);
setError(null);
setResponse(null);
try {
const res = await krowSDK.integrations.Core.SendEmail(formData);
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<div>
<h1 className="text-3xl font-bold text-slate-900 mb-4">Send Email</h1>
<p className="text-slate-600 mb-6">Tests the `integrations.Core.SendEmail` endpoint.</p>
<Card className="max-w-2xl">
<CardHeader>
<CardTitle>Test `/sendEmail`</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSendEmail} className="space-y-4">
<div>
<Label htmlFor="to">To</Label>
<Input id="to" type="email" value={formData.to} onChange={handleChange} />
</div>
<div>
<Label htmlFor="subject">Subject</Label>
<Input id="subject" value={formData.subject} onChange={handleChange} />
</div>
<div>
<Label htmlFor="body">Body</Label>
<Textarea id="body" value={formData.body} onChange={handleChange} rows={5} />
</div>
<Button type="submit" disabled={loading}>
{loading ? "Sending..." : "Send Email"}
</Button>
</form>
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
export default SendEmail;

View File

@@ -0,0 +1,67 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import ApiResponse from "@/components/ApiResponse";
import { krowSDK } from "@/api/krowSDK";
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card";
const UploadFile = () => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [file, setFile] = useState(null);
const handleFileChange = (e) => {
setFile(e.target.files[0]);
};
const handleUpload = async (e) => {
e.preventDefault();
if (!file) {
setError({ message: "Please select a file to upload." });
return;
}
setLoading(true);
setError(null);
setResponse(null);
try {
const res = await krowSDK.integrations.Core.UploadFile({ file });
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<div>
<h1 className="text-3xl font-bold text-slate-900 mb-4">Upload Public File</h1>
<p className="text-slate-600 mb-6">Tests the `integrations.Core.UploadFile` endpoint for public files.</p>
<Card className="max-w-2xl">
<CardHeader>
<CardTitle>Test `/uploadFile`</CardTitle>
<CardDescription>Handles multipart/form-data upload to GCS and returns a public URL.</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleUpload} className="space-y-4">
<div>
<Label htmlFor="file">File</Label>
<Input id="file" type="file" onChange={handleFileChange} />
</div>
<Button type="submit" disabled={loading || !file}>
{loading ? "Uploading..." : "Upload File"}
</Button>
</form>
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
export default UploadFile;

View File

@@ -0,0 +1,67 @@
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import ApiResponse from "@/components/ApiResponse";
import { krowSDK } from "@/api/krowSDK";
import { Card, CardHeader, CardTitle, CardContent, CardDescription } from "@/components/ui/card";
const UploadPrivateFile = () => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const [file, setFile] = useState(null);
const handleFileChange = (e) => {
setFile(e.target.files[0]);
};
const handleUpload = async (e) => {
e.preventDefault();
if (!file) {
setError({ message: "Please select a file to upload." });
return;
}
setLoading(true);
setError(null);
setResponse(null);
try {
const res = await krowSDK.integrations.Core.UploadPrivateFile({ file });
setResponse(res);
} catch (err) {
setError(err.response?.data || err.message);
} finally {
setLoading(false);
}
};
return (
<div>
<h1 className="text-3xl font-bold text-slate-900 mb-4">Upload Private File</h1>
<p className="text-slate-600 mb-6">Tests the `integrations.Core.UploadPrivateFile` endpoint.</p>
<Card className="max-w-2xl">
<CardHeader>
<CardTitle>Test `/uploadPrivateFile`</CardTitle>
<CardDescription>Handles multipart/form-data upload to GCS and returns a secure gs:// URI.</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleUpload} className="space-y-4">
<div>
<Label htmlFor="file">File</Label>
<Input id="file" type="file" onChange={handleFileChange} />
</div>
<Button type="submit" disabled={loading || !file}>
{loading ? "Uploading..." : "Upload File"}
</Button>
</form>
</CardContent>
</Card>
<ApiResponse response={response} error={error} loading={loading} />
</div>
);
};
export default UploadPrivateFile;

View File

@@ -0,0 +1,96 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)'
},
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
card: {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))'
},
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))'
},
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))'
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))'
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))'
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))'
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))'
},
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
chart: {
'1': 'hsl(var(--chart-1))',
'2': 'hsl(var(--chart-2))',
'3': 'hsl(var(--chart-3))',
'4': 'hsl(var(--chart-4))',
'5': 'hsl(var(--chart-5))'
},
sidebar: {
DEFAULT: 'hsl(var(--sidebar-background))',
foreground: 'hsl(var(--sidebar-foreground))',
primary: 'hsl(var(--sidebar-primary))',
'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
accent: 'hsl(var(--sidebar-accent))',
'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
border: 'hsl(var(--sidebar-border))',
ring: 'hsl(var(--sidebar-ring))'
}
},
keyframes: {
'accordion-down': {
from: {
height: '0'
},
to: {
height: 'var(--radix-accordion-content-height)'
}
},
'accordion-up': {
from: {
height: 'var(--radix-accordion-content-height)'
},
to: {
height: '0'
}
}
},
animation: {
'accordion-down': 'accordion-down 0.2s ease-out',
'accordion-up': 'accordion-up 0.2s ease-out'
}
}
},
plugins: [require("tailwindcss-animate")],
}

View File

@@ -0,0 +1,17 @@
import path from "path"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
headers: {
"Cross-Origin-Opener-Policy": "same-origin-allow-popups",
},
},
})

View File

@@ -0,0 +1,5 @@
[
"1b2e22bdec8f6493bf71ee535b6db6b4b5cd2d373f0ffb25524e229f3b5b7f5f",
"e075ff357ef35be2d55b0e383d59c5256980c492ada7ab84c84b2bb5ac26a73f",
"994b31c1aef3d59fe59bc3b8e1dec860a6fb3c73cbf41bdf45028e2c1ecbcf7a"
]

View File

@@ -0,0 +1,145 @@
[
{
"title": "Applications",
"iconColorClass": "bg-primary-100",
"iconPath": "assets/images/icon-applications.svg",
"links": [
{
"title": "Control Tower",
"url": "https://krow-workforce-dev.web.app",
"badge": "Dev",
"badgeColorClass": "bg-blue-500",
"containerClass": "bg-gradient-to-r from-blue-50 to-blue-100 hover:from-blue-100 hover:to-blue-200",
"iconClass": "w-2 h-2 bg-blue-500 rounded-full",
"textHoverClass": "group-hover:text-blue-700"
},
{
"title": "Control Tower",
"url": "https://krow-workforce-staging.web.app",
"badge": "Staging",
"badgeColorClass": "bg-amber-500",
"containerClass": "bg-gradient-to-r from-amber-50 to-amber-100 hover:from-amber-100 hover:to-amber-200",
"iconClass": "w-2 h-2 bg-amber-500 rounded-full",
"textHoverClass": "group-hover:text-amber-700"
}
]
},
{
"title": "Legacy Mobile Apps",
"iconColorClass": "bg-green-100",
"iconPath": "assets/images/icon-legacy-mobile-apps.svg",
"links": [
{
"title": "Google Play Store",
"url": "https://play.google.com/store/apps/dev?id=9163719228191263405&hl=en",
"badge": "Live",
"badgeColorClass": "bg-green-500",
"containerClass": "bg-gradient-to-r from-green-50 to-emerald-100 hover:from-green-100 hover:to-emerald-200",
"iconPath": "assets/images/icon-google-play.svg",
"textHoverClass": "group-hover:text-green-700"
},
{
"title": "Apple App Store",
"url": "https://apps.apple.com/us/developer/thinkloops-llc/id1719034287",
"badge": "Live",
"badgeColorClass": "bg-gray-700",
"containerClass": "bg-gradient-to-r from-gray-50 to-gray-100 hover:from-gray-100 hover:to-gray-200",
"iconPath": "assets/images/icon-apple-app-store.svg",
"textHoverClass": "group-hover:text-gray-700"
}
]
},
{
"title": "Cloud Infrastructure",
"iconColorClass": "bg-purple-100",
"iconPath": "assets/images/icon-cloud-infrastructure.svg",
"links": [
{
"title": "Firebase Console",
"url": "https://console.firebase.google.com/project/krow-workforce-dev/overview",
"badge": "Dev",
"badgeColorClass": "bg-blue-500",
"containerClass": "bg-gradient-to-r from-blue-50 to-indigo-100 hover:from-blue-100 hover:to-indigo-200",
"iconPath": "assets/images/icon-firebase-console.svg",
"textHoverClass": "group-hover:text-indigo-700"
},
{
"title": "Firebase Console",
"url": "https://console.firebase.google.com/project/krow-workforce-staging/overview",
"badge": "Staging",
"badgeColorClass": "bg-amber-500",
"containerClass": "bg-gradient-to-r from-amber-50 to-orange-100 hover:from-amber-100 hover:to-orange-200",
"iconPath": "assets/images/icon-firebase-console.svg",
"textHoverClass": "group-hover:text-orange-700"
},
{
"title": "Google Cloud",
"url": "https://console.cloud.google.com/welcome/new?project=krow-workforce-dev",
"badge": "Dev",
"badgeColorClass": "bg-blue-500",
"containerClass": "bg-gradient-to-r from-blue-50 to-cyan-100 hover:from-blue-100 hover:to-cyan-200",
"iconPath": "assets/images/icon-google-cloud.svg",
"textHoverClass": "group-hover:text-cyan-700"
},
{
"title": "Google Cloud",
"url": "https://console.cloud.google.com/welcome/new?project=krow-workforce-staging",
"badge": "Staging",
"badgeColorClass": "bg-amber-500",
"containerClass": "bg-gradient-to-r from-amber-50 to-yellow-100 hover:from-amber-100 hover:to-yellow-200",
"iconPath": "assets/images/icon-google-cloud.svg",
"textHoverClass": "group-hover:text-yellow-700"
}
]
},
{
"title": "Design",
"iconColorClass": "bg-pink-100",
"iconPath": "assets/images/icon-design.svg",
"links": [
{
"title": "Staff App Figma File",
"url": "https://www.figma.com/design/HfNpoYOpkfUu2lgDMp4xQK/KROW-Staff-App-Revamp?node-id=0-1&t=4TLUeCIWf7I1TTGQ-1",
"badge": "Design",
"badgeColorClass": "bg-pink-500",
"containerClass": "bg-gradient-to-r from-pink-50 to-rose-100 hover:from-pink-100 hover:to-rose-200",
"iconPath": "assets/images/icon-figma.svg",
"textHoverClass": "group-hover:text-pink-700"
},
{
"title": "Staff App Preview",
"url": "https://9000-firebase-studio-1764098159606.cluster-oe5pskshnfducslpwllk6difqk.cloudworkstations.dev/",
"badge": "Preview",
"badgeColorClass": "bg-purple-500",
"containerClass": "bg-gradient-to-r from-purple-50 to-fuchsia-100 hover:from-purple-100 hover:to-fuchsia-200",
"iconPath": "assets/images/icon-preview.svg",
"textHoverClass": "group-hover:text-purple-700"
}
]
},
{
"title": "Resources",
"iconColorClass": "bg-indigo-100",
"iconPath": "assets/images/icon-resources.svg",
"links": [
{
"title": "GitHub Repository",
"subtitle": "View source code",
"url": "https://github.com/Oloodi/krow-workforce",
"containerClass": "bg-gradient-to-r from-gray-50 to-slate-100 hover:from-gray-100 hover:to-slate-200",
"iconPath": "assets/images/icon-github.svg",
"textHoverClass": "group-hover:text-gray-700",
"arrowIcon": true
},
{
"title": "Team Communication",
"subtitle": "Google Chat",
"url": "https://chat.google.com/",
"containerClass": "bg-gradient-to-r from-green-50 to-teal-100 hover:from-green-100 hover:to-teal-200",
"iconPath": "assets/images/icon-chat.svg",
"textHoverClass": "group-hover:text-teal-700",
"arrowIcon": true
}
]
}
]

View File

@@ -0,0 +1,67 @@
graph TB
Title["<b>KROW - Cloud Architecture</b><br/>Production Solution"]
subgraph Prototype[" "]
Proto["🔧 Current KROW Prototype<br/>(Demo Only)"]
end
Title --> Prototype
Title --> Production
subgraph Production["🏢 KROW - PRODUCTION ARCHITECTURE"]
subgraph GCP["☁️ Google Cloud Platform - US Regions"]
subgraph Auth["🔐 Authentication"]
Firebase["Firebase Auth<br/>• MFA<br/>• OAuth 2.0"]
end
subgraph Backend["⚙️ Backend"]
Functions["Cloud Functions<br/>• Serverless<br/>• Auto-scaling"]
API["API Gateway<br/>• Secure APIs<br/>• Rate limiting"]
end
subgraph Data["💾 Data Storage"]
Firestore["Firestore/Cloud SQL<br/>• Encrypted at rest<br/>• Auto backup"]
Storage["Cloud Storage<br/>• Encrypted<br/>• Access control"]
end
subgraph Security["🛡️ Security"]
IAM["Cloud IAM<br/>• Access control<br/>• Least privilege"]
Logs["Logging & Monitoring<br/>• Audit trails<br/>• Real-time alerts"]
end
end
subgraph Compliance["✅ COMPLIANCE"]
GDPR["📋 GDPR Ready<br/>• US data hosting<br/>• User rights<br/>• Data portability"]
SOC2["🏆 SOC 2 Ready<br/>• Google certified<br/>• Security controls<br/>• Full audit trails"]
end
end
Users["👥 End Users"]
Proto -.->|Migration vers| Production
Users --> Auth
Auth --> API
API --> Functions
Functions --> Firestore
Functions --> Storage
IAM --> Auth
IAM --> Backend
IAM --> Data
Logs --> Security
GCP --> GDPR
GCP --> SOC2
style Prototype fill:#FFF3CD,stroke:#856404,stroke-width:2px,stroke-dasharray: 5 5
style Proto fill:#FFF3CD,stroke:#856404
style Title fill:#1976D2,stroke:#0D47A1,stroke-width:3px,color:#FFFFFF
style Production fill:#D4EDDA,stroke:#155724,stroke-width:3px
style GCP fill:#E3F2FD,stroke:#1976D2,stroke-width:2px
style Auth fill:#E8F5E9,stroke:#2E7D32
style Backend fill:#E8F5E9,stroke:#2E7D32
style Data fill:#E8F5E9,stroke:#2E7D32
style Security fill:#FFE0B2,stroke:#E65100
style Compliance fill:#F3E5F5,stroke:#6A1B9A,stroke-width:2px
style GDPR fill:#E1BEE7,stroke:#6A1B9A
style SOC2 fill:#E1BEE7,stroke:#6A1B9A

View File

@@ -0,0 +1,70 @@
sequenceDiagram
participant Client as 🏢 Client App
participant Backend as 🌐 Backend API
participant Admin as ⚙️ KROW Admin
participant Staff as 👥 Staff App
%% Event Creation
Note over Client,Backend: 1. Event & Shift Creation
Client->>Backend: Create Event with Shifts & Positions
Backend-->>Client: Event Created (Draft)
Client->>Backend: Publish Event
Backend-->>Client: Event Published
%% Staff Assignment
Note over Admin,Backend: 2. Staff Assignment
Admin->>Backend: View Available Events
Backend-->>Admin: Event List
Admin->>Backend: Assign Staff to Shift
Backend-->>Admin: Assignment Confirmed
Backend->>Staff: Notification: New Shift Assigned
%% Shift Acceptance
Note over Staff,Backend: 3. Shift Acceptance
Staff->>Backend: View Shift Details
Backend-->>Staff: Shift Information
Staff->>Backend: Accept Shift
Backend-->>Staff: Shift Confirmed
Backend->>Client: Notification: Staff Confirmed
%% Clock In
Note over Client,Staff: 4. Clock In - Day of Event
Client->>Client: Generate QR Code for Event
Staff->>Staff: Scan QR Code
Staff->>Backend: Clock In Request (via QR)
Backend-->>Staff: Clock In Confirmed
Backend->>Client: Notification: Staff Clocked In
Client->>Backend: (Alternative) Manual Clock In
Backend-->>Client: Manual Clock In Confirmed
%% Shift Active
Note over Staff: 5. Shift In Progress
Staff->>Staff: View Real-time Timer
%% Clock Out
Note over Client,Staff: 6. Clock Out - End of Shift
Staff->>Staff: Scan QR Code
Staff->>Backend: Clock Out Request (via QR)
Backend-->>Staff: Clock Out Confirmed
Backend-->>Staff: Shift Status: Completed
Backend->>Client: Notification: Staff Clocked Out
%% Rating & Invoicing
Note over Client,Backend: 7. Post-Shift Activities
Client->>Backend: Rate Staff Performance
Backend-->>Client: Rating Recorded
Backend->>Backend: Generate Invoice
Backend->>Client: Invoice Created
Client->>Backend: Review & Approve Invoice
Backend-->>Client: Invoice Approved
%% Payment
Note over Staff,Backend: 8. Staff Payment
Backend->>Staff: Payment Processed
Staff->>Backend: View Earnings & Payment History
Backend-->>Staff: Payment Details
alt Payment Dispute
Staff->>Backend: Contest Payment Amount
Backend-->>Staff: Dispute Opened
end

View File

@@ -0,0 +1,61 @@
graph TB
subgraph "Actors"
Staff[👥 Staff/Employee]
Client[🏢 Client/Business]
Admin[⚙️ KROW Admin]
end
subgraph "KROW Staff App"
SA_Auth[Authentication & Onboarding]
SA_Shifts[Shift Management]
SA_Earnings[Earnings & Payments]
SA_Profile[Profile Management]
end
subgraph "KROW Client App"
CA_Events[Event Creation]
CA_Staff[Staff Management]
CA_Time[Time Tracking - QR Code]
CA_Invoice[Invoicing]
end
subgraph "Backend System"
API[Backend API]
DB[(Database)]
end
%% Staff interactions
Staff -->|Registers & Manages Profile| SA_Auth
Staff -->|Views & Accepts Shifts| SA_Shifts
Staff -->|Scans QR Code - Clock In/Out| SA_Shifts
Staff -->|Tracks Earnings| SA_Earnings
Staff -->|Updates Skills & Documents| SA_Profile
%% Client interactions
Client -->|Creates Events & Shifts| CA_Events
Client -->|Views Assigned Staff| CA_Staff
Client -->|Generates QR Code| CA_Time
Client -->|Manual Clock In/Out| CA_Time
Client -->|Rates Staff| CA_Staff
Client -->|Reviews & Approves Invoices| CA_Invoice
%% Admin interactions
Admin -->|Assigns Staff to Shifts| API
Admin -->|Validates Staff Profiles| API
%% App to Backend connections
SA_Auth -.->|Profile Data| API
SA_Shifts -.->|Shift Status Updates| API
SA_Earnings -.->|Payment Data| API
SA_Profile -.->|User Data| API
CA_Events -.->|Event & Shift Data| API
CA_Staff -.->|Staff Ratings| API
CA_Time -.->|Time Records| API
CA_Invoice -.->|Invoice Data| API
API <-->|Data Storage & Retrieval| DB
style Staff fill:#e1f5ff
style Client fill:#fff4e1
style Admin fill:#f0e1ff

View File

@@ -0,0 +1,40 @@
graph LR
START[💼 Shift<br/>Completed<br/>& Rated]
START --> CALC[📊 INTERNAL<br/><br/>Calculate Invoice<br/>• Hours worked<br/>• Rates × Hours<br/>• Overtime calc<br/>• Platform fees<br/>• Tax amounts]
CALC --> GENERATE[📄 INTERNAL<br/><br/>Generate Invoice<br/>• Create PDF<br/>• Invoice number<br/>• Line items<br/>• Due date]
GENERATE --> SAVE[💾 INTERNAL<br/><br/>Save to Database<br/>• Store invoice<br/>• Status: pending<br/>• Track history]
SAVE --> SEND[📧 API INTEGRATION<br/><br/>SendGrid<br/>• Send email<br/>• Track delivery<br/>• Reliable inbox]
SEND --> CLIENT[📱 Client<br/>Reviews<br/>Invoice]
CLIENT --> DECISION{Approve or<br/>Dispute?}
DECISION -->|⚠️ Dispute| DISPUTE[🔧 INTERNAL<br/><br/>Handle Dispute<br/>• Admin reviews<br/>• Adjustments<br/>• Re-calculate]
DISPUTE --> SAVE
DECISION -->|✅ Approve| PAY[💳 API INTEGRATION<br/><br/>Stripe<br/>• Credit card<br/>• ACH transfer<br/>• Payment tracking]
PAY --> CONFIRM[💾 INTERNAL<br/><br/>Update Status<br/>• Mark as paid<br/>• Record payment<br/>• Update reports]
CONFIRM --> PAYOUT[💰 API INTEGRATION<br/><br/>Stripe Connect<br/>• Pay staff<br/>• Direct deposit<br/>• Automated]
PAYOUT --> RECORD[📊 INTERNAL<br/><br/>Track Payments<br/>• Staff earnings<br/>• Payment history<br/>• Reports]
RECORD --> DONE[✅ Complete]
style START fill:#E1F5FF
style CALC fill:#FFF9E6,stroke:#F9A825,stroke-width:3px
style GENERATE fill:#FFF9E6,stroke:#F9A825,stroke-width:3px
style SAVE fill:#FFF9E6,stroke:#F9A825,stroke-width:3px
style DISPUTE fill:#FFF9E6,stroke:#F9A825,stroke-width:3px
style CONFIRM fill:#FFF9E6,stroke:#F9A825,stroke-width:3px
style RECORD fill:#FFF9E6,stroke:#F9A825,stroke-width:3px
style SEND fill:#E3F2FD,stroke:#1976D2,stroke-width:3px
style PAY fill:#E3F2FD,stroke:#1976D2,stroke-width:3px
style PAYOUT fill:#E3F2FD,stroke:#1976D2,stroke-width:3px
style DONE fill:#90EE90

View File

@@ -0,0 +1,24 @@
graph TD
subgraph KROW Mobile Applications
direction LR
Mobile_Client[<b>Mobile Client App</b><br>Flutter]
Mobile_Staff[<b>Mobile Staff App</b><br>Flutter]
end
subgraph Firebase Backend Services - GCP
direction TB
Auth[Firebase Authentication]
DataConnect[<b>Firebase Data Connect</b><br>GraphQL API &<br>Generated SDKs]
SQL_DB[<b>Cloud SQL for PostgreSQL</b><br><i>Managed by Data Connect</i>]
end
Mobile_Client -- "Authenticates with" --> Auth
Mobile_Client -- "Calls API via generated SDK" --> DataConnect
Mobile_Staff -- "Authenticates with" --> Auth
Mobile_Staff -- "Calls API via generated SDK" --> DataConnect
DataConnect -- "Manages & Queries" --> SQL_DB
style Mobile_Client fill:#eef,stroke:#333,stroke-width:2px
style Mobile_Staff fill:#eef,stroke:#333,stroke-width:2px

View File

@@ -0,0 +1,29 @@
graph LR
subgraph Base44 Environment
direction TB
Client[Client] -- Modifies --> B44_UI[<b>Base44 Visual Builder</b><br><i>Features:</i><br>- Event Management<br>- Staff Directory<br>- Vendor Onboarding]
B44_UI --> B44_Backend[<b>Base44 Backend</b><br>Provides Entity Schemas<br>& SDK Operations]
B44_Backend --> B44_DB[Base44 Database]
end
subgraph Firebase Ecosystem - GCP
direction TB
KROW_FE[<b>KROW Frontend</b><br>Vite/React + TanStack Query<br><i>From Export</i>]
subgraph Firebase Services
direction TB
Auth[Firebase Authentication]
DataConnect[<b>Firebase Data Connect</b><br>GraphQL API &<br>Generated SDKs]
SQL_DB[<b>Cloud SQL for PostgreSQL</b><br><i>Managed by Data Connect</i>]
end
KROW_FE -- "Uses" --> Auth
KROW_FE -- "Calls Queries/Mutations via SDK" --> DataConnect
DataConnect -- "Manages & Queries" --> SQL_DB
end
B44_UI -- "<b>UI Code Export</b><br>(React Components)" --> KROW_FE
style Client fill:#f9f,stroke:#333,stroke-width:2px
style B44_UI fill:#ffe,stroke:#333,stroke-width:2px
style KROW_FE fill:#eef,stroke:#333,stroke-width:2px

View File

@@ -0,0 +1,32 @@
sequenceDiagram
participant Staff as Staff Member
participant App as KROW Staff App
participant Client as Client
participant Backend as Backend
Staff->>App: Opens shift and taps "Clock In"
activate App
App->>App: **1. Geofencing Check (GPS) BEFORE scan**
alt Proximity Validated
App->>Client: Requests QR Code
Client-->>Staff: Presents QR Code
Staff->>App: Scans the code
App->>Backend: Validates Clock In with eventId
Backend-->>App: Confirmation
App->>Staff: Displays "Clock In Successful"
else Proximity Failed (GPS bug, too far)
App->>Staff: Displays "Error: You are too far"
end
deactivate App
loop Continuous Monitoring DURING the shift
App->>App: **2. Checks GPS position (anti-fraud)**
opt Staff member leaves the > 500m area
App->>Backend: Notifies area exit
Backend-->>App: Triggers a "Force Clock-Out"
end
end
%% Clock Out process follows a similar logic (Geofencing + QR Code) %%

View File

@@ -0,0 +1,110 @@
[
{
"path": "assets/diagrams/architectures/0-infra-compliance.mermaid",
"title": "Infrastructure & Compliance",
"type": "mermaid",
"icon": "bi-shield-check"
},
{
"path": "assets/diagrams/architectures/1-core-workflow.mermaid",
"title": "Core Workflow",
"type": "mermaid",
"icon": "bi-diagram-3"
},
{
"path": "assets/diagrams/architectures/2-high-level-architecture.mermaid",
"title": "High-Level Architecture",
"type": "mermaid",
"icon": "bi-diagram-3"
},
{
"path": "assets/diagrams/architectures/3-invoice-workflow-simple.mermaid",
"title": "Invoice Workflow (Simple)",
"type": "mermaid",
"icon": "bi-receipt"
},
{
"path": "assets/diagrams/architectures/4-mobile-app-architecture.mermaid",
"title": "Mobile App Architecture",
"type": "mermaid",
"icon": "bi-phone"
},
{
"path": "assets/diagrams/architectures/5-web-app-architecture.mermaid",
"title": "Web App Architecture",
"type": "mermaid",
"icon": "bi-window"
},
{
"path": "assets/diagrams/architectures/6-geofencing-clockin-clockout.mermaid",
"title": "Geofencing Clock-In/Out",
"type": "mermaid",
"icon": "bi-geo-alt"
},
{
"path": "assets/diagrams/roadmap/roadmap.mermaid",
"title": "Project Roadmap",
"type": "mermaid",
"icon": "bi-calendar-check"
},
{
"path": "assets/diagrams/legacy/staff-mobile-application/overview.mermaid",
"title": "Legacy App Overview",
"type": "mermaid",
"icon": "bi-phone"
},
{
"path": "assets/diagrams/legacy/staff-mobile-application/use-case-flowchart.mermaid",
"title": "Legacy App Use Cases",
"type": "mermaid",
"icon": "bi-diagram-2"
},
{
"path": "assets/diagrams/legacy/staff-mobile-application/api-map.mermaid",
"title": "Legacy App API Map",
"type": "mermaid",
"icon": "bi-phone"
},
{
"path": "assets/diagrams/legacy/staff-mobile-application/use-case-flows.mermaid",
"title": "Legacy App Use Cases BE Chart",
"type": "mermaid",
"icon": "bi-diagram-2"
},
{
"path": "assets/diagrams/legacy/staff-mobile-application/backend-architecture.mermaid",
"title": "Legacy App Backend Architecture",
"type": "mermaid",
"icon": "bi-diagram-2"
},
{
"path": "assets/diagrams/legacy/client-mobile-application/overview.mermaid",
"title": "Legacy App Overview",
"type": "mermaid",
"icon": "bi-phone"
},
{
"path": "assets/diagrams/legacy/client-mobile-application/use-case-flowchart.mermaid",
"title": "Legacy App Use Cases",
"type": "mermaid",
"icon": "bi-diagram-2"
},
{
"path": "assets/diagrams/legacy/client-mobile-application/api-map.mermaid",
"title": "Legacy App API Map",
"type": "mermaid",
"icon": "bi-phone"
},
{
"path": "assets/diagrams/legacy/client-mobile-application/use-case-flows.mermaid",
"title": "Legacy App Use Cases BE Chart",
"type": "mermaid",
"icon": "bi-diagram-2"
},
{
"path": "assets/diagrams/legacy/client-mobile-application/backend-architecture.mermaid",
"title": "Legacy App Backend Architecture",
"type": "mermaid",
"icon": "bi-diagram-2"
}
]

View File

@@ -0,0 +1,55 @@
flowchart TD
subgraph "GraphQL API"
direction LR
subgraph "Queries"
Q1[getEvents]
Q2[getEventDetails]
Q3[getInvoices]
Q4[getInvoiceDetails]
Q5[getNotifications]
Q6[getNotificationDetails]
Q7[getProfile]
Q8[getAssignedStaff]
end
subgraph "Mutations"
M1[createEvent]
M2[updateProfile]
M3[rateStaff]
M4[clockIn]
M5[clockOut]
M6[uploadProfilePicture]
end
end
subgraph "Firebase"
direction LR
subgraph "Firestore Collections"
FS1[events]
FS2[invoices]
FS3[notifications]
FS4[users]
end
subgraph "Firebase Storage"
FB1[Profile Pictures]
end
end
Q1 --> FS1
Q2 --> FS1
Q3 --> FS2
Q4 --> FS2
Q5 --> FS3
Q6 --> FS3
Q7 --> FS4
Q8 --> FS1
Q8 --> FS4
M1 --> FS1
M2 --> FS4
M3 --> FS1
M3 --> FS4
M4 --> FS1
M5 --> FS1
M6 --> FB1

View File

@@ -0,0 +1,28 @@
flowchart TD
subgraph "Client"
A[Flutter App]
end
subgraph "Backend"
B[GraphQL Server - Node.js]
C[Firebase]
end
subgraph "Firebase Services"
C1[Firebase Auth]
C2[Firebase Firestore]
C3[Firebase Storage]
end
A -- "GraphQL Queries/Mutations" --> B
A -- "Authentication" --> C1
B -- "Data Operations" --> C2
B -- "File Operations" --> C3
C1 -- "User Tokens" --> A
C2 -- "Data" --> B
C3 -- "Files" --> B
B -- "Data/Files" --> A

View File

@@ -0,0 +1,65 @@
flowchart TD
subgraph "App Initialization"
A[main.dart] --> B(KrowApp);
B --> C{MaterialApp.router};
C --> D[Initial Route: /];
end
subgraph "Authentication Flow"
D --> E(SplashRoute);
E --> F{SplashRedirectGuard};
F -- Authenticated --> G(HomeRoute);
F -- Unauthenticated/Error --> H(SignInFlowRoute);
end
subgraph "Sign-In/Welcome Flow"
H --> I[WelcomeRoute];
I --> J[SignInRoute];
J --> K[ResetPassRoute];
L[Deeplink with oobCode] --> M[EnterNewPassRoute];
J -- Forgot Password --> K;
I -- Sign In --> J;
end
subgraph "Main Application (Home)"
G --> G_Tabs((Bottom Navigation));
G_Tabs -- Events --> Events;
G_Tabs -- Invoices --> Invoices;
G_Tabs -- Notifications --> Notifications;
G_Tabs -- Profile --> Profile;
G_Tabs -- Create Event --> CreateEvent;
end
subgraph "Events Flow"
Events[EventsFlow] --> Events_List(EventsListMainRoute);
Events_List --> Events_Event_Details(EventDetailsRoute);
Events_Event_Details --> Events_Assigned_Staff(AssignedStaffRoute);
Events_Assigned_Staff --> Events_Clock_Manual(ClockManualRoute);
Events_Event_Details --> Events_Rate_Staff(RateStaffRoute);
end
subgraph "Create Event Flow"
CreateEvent[CreateEventFlow] --> Create_Event_Edit(CreateEventRoute);
Create_Event_Edit --> Create_Event_Preview(EventDetailsRoute);
end
subgraph "Invoice Flow"
Invoices[InvoiceFlow] --> Invoice_List(InvoicesListMainRoute);
Invoice_List --> Invoice_Details(InvoiceDetailsRoute);
Invoice_Details --> Invoice_Event_Details(EventDetailsRoute);
end
subgraph "Notifications Flow"
Notifications[NotificationFlow] --> Notification_List(NotificationsListRoute);
Notification_List --> Notification_Details(NotificationDetailsRoute);
end
subgraph "Profile Flow"
Profile[ProfileFlow] --> Profile_Preview(ProfilePreviewRoute);
Profile_Preview --> Profile_Edit(PersonalInfoRoute);
end
style F fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#bbf,stroke:#333,stroke-width:2px
style H fill:#bbf,stroke:#333,stroke-width:2px
style L fill:#f9f,stroke:#333,stroke-width:2px

View File

@@ -0,0 +1,80 @@
flowchart TD
subgraph "User"
U((User))
end
subgraph "Authentication Use Cases"
UC1(Sign In)
UC2(Sign Out)
UC3(Password Reset)
end
subgraph "Event Management Use Cases"
UC4(Create Event)
UC5(View Event Details)
UC6(List Events)
end
subgraph "Invoice Management Use Cases"
UC7(List Invoices)
UC8(View Invoice Details)
end
subgraph "Staff Management Use Cases"
UC9(View Assigned Staff)
UC10(Rate Staff)
UC11(Manual Clock In/Out)
end
subgraph "Profile Management Use Cases"
UC12(View Profile)
UC13(Edit Profile)
end
subgraph "Notification Use Cases"
UC14(List Notifications)
UC15(View Notification Details)
end
U --> UC1
UC1 -- Success --> UC6
UC1 -- Forgot Password --> UC3
UC6 --> UC5
UC5 --> UC9
UC9 --> UC11
UC5 --> UC10
U --> UC4
UC4 -- Success --> UC5
UC6 -- Triggers --> UC7
UC7 --> UC8
UC8 -- View Event --> UC5
U --> UC12
UC12 --> UC13
UC13 -- Success --> UC12
U --> UC14
UC14 --> UC15
UC12 -- Sign Out --> UC2
UC2 -- Success --> UC1
%% Styling
style UC1 fill:#f9f,stroke:#333,stroke-width:2px
style UC2 fill:#f9f,stroke:#333,stroke-width:2px
style UC3 fill:#f9f,stroke:#333,stroke-width:2px
style UC4 fill:#bbf,stroke:#333,stroke-width:2px
style UC5 fill:#bbf,stroke:#333,stroke-width:2px
style UC6 fill:#bbf,stroke:#333,stroke-width:2px
style UC7 fill:#bbf,stroke:#333,stroke-width:2px
style UC8 fill:#bbf,stroke:#333,stroke-width:2px
style UC9 fill:#bbf,stroke:#333,stroke-width:2px
style UC10 fill:#bbf,stroke:#333,stroke-width:2px
style UC11 fill:#bbf,stroke:#333,stroke-width:2px
style UC12 fill:#bbf,stroke:#333,stroke-width:2px
style UC13 fill:#bbf,stroke:#333,stroke-width:2px
style UC14 fill:#bbf,stroke:#333,stroke-width:2px
style UC15 fill:#bbf,stroke:#333,stroke-width:2px

View File

@@ -0,0 +1,45 @@
flowchart TD
subgraph "Sign-In Flow"
A1[User enters credentials] --> B1{SignInBloc};
B1 --> C1[Firebase Auth: signInWithEmailAndPassword];
C1 -- Success --> D1[Navigate to Home];
C1 -- Failure --> E1[Show error message];
end
subgraph "Password Reset Flow"
A2[User requests password reset] --> B2{SignInBloc};
B2 --> C2[Firebase Auth: sendPasswordResetEmail];
C2 -- Email Sent --> D2[User clicks deep link];
D2 --> E2[UI with new password fields];
E2 --> F2{SignInBloc};
F2 --> G2[Firebase Auth: confirmPasswordReset];
G2 -- Success --> H2[Show success message];
G2 -- Failure --> I2[Show error message];
end
subgraph "Event Listing Flow"
A3[User navigates to Events screen] --> B3{EventsBloc};
B3 --> C3[GraphQL Query: getEvents];
C3 --> D3[Firestore: events collection];
D3 -- Returns event data --> C3;
C3 -- Returns data --> B3;
B3 --> E3[Display list of events];
end
subgraph "Create Event Flow"
A4[User submits new event form] --> B4{CreateEventBloc};
B4 --> C4[GraphQL Mutation: createEvent];
C4 --> D4[Firestore: events collection];
D4 -- Success --> C4;
C4 -- Returns success --> B4;
B4 --> E4[Navigate to event details];
end
subgraph "Profile Viewing Flow"
A5[User navigates to Profile screen] --> B5{ProfileBloc};
B5 --> C5[GraphQL Query: getProfile];
C5 --> D5[Firestore: users collection];
D5 -- Returns profile data --> C5;
C5 -- Returns data --> B5;
B5 --> E5[Display profile information];
end

View File

@@ -0,0 +1,57 @@
graph TD
subgraph GraphQL API
subgraph Queries
Q1[getStaffStatus]
Q2[getMe]
Q3[getStaffPersonalInfo]
Q4[getStaffProfileRoles]
Q5[getShifts]
Q6[staffNoBreakShifts]
Q7[getShiftPosition]
end
subgraph Mutations
M1[updateStaffPersonalInfo]
M2[updateStaffPersonalInfoWithAvatar]
M3[uploadStaffAvatar]
M4[acceptShift]
M5[trackStaffClockin]
M6[trackStaffClockout]
M7[trackStaffBreak]
M8[submitNoBreakStaffShift]
M9[cancelStaffShift]
M10[declineShift]
end
end
subgraph Firebase Services
FS[Firebase Storage]
FF[Firebase Firestore]
FA[Firebase Auth]
end
M2 --> FS;
M3 --> FS;
Q1 --> FF;
Q2 --> FF;
Q3 --> FF;
Q4 --> FF;
Q5 --> FF;
Q6 --> FF;
Q7 --> FF;
M1 --> FF;
M2 --> FF;
M4 --> FF;
M5 --> FF;
M6 --> FF;
M7 --> FF;
M8 --> FF;
M9 --> FF;
M10 --> FF;
Q1 --> FA;
Q2 --> FA;
Q3 --> FA;

View File

@@ -0,0 +1,37 @@
graph TD
subgraph Flutter App
A[Flutter UI]
B[GraphQL Client]
C[Firebase SDK]
end
subgraph Backend
D[GraphQL Server]
E[Firebase]
end
subgraph Firebase
F[Firebase Auth]
G[Firebase Firestore]
H[Firebase Storage]
I[Firebase Cloud Functions]
J[Firebase Cloud Messaging]
K[Firebase Remote Config]
end
A --> B;
A --> C;
B --> D;
C --> F;
C --> J;
C --> K;
D --> G;
D --> H;
D --> I;
D --> F;
I --> G;
I --> H;
I --> J;

View File

@@ -0,0 +1,117 @@
flowchart TD
A[main.dart] --> B{KrowApp};
B --> C{MaterialApp.router};
C --> D[SplashRoute];
D --> E{SplashRedirectGuard};
E -- Authenticated --> F[HomeRoute];
E -- Admin Validation --> G[WaitingValidationRoute];
E -- Prepare Profile --> H[CheckListFlowRoute];
E -- Unauthenticated/Error --> I[AuthFlowRoute];
F --> F1[ShiftsFlowRoute];
F --> F2[EarningsFlowRoute];
F --> F3[ProfileMainFlowRoute];
F1 --> F1a[ShiftsListMainRoute];
F1a --> F1b[ShiftDetailsRoute];
F1a --> F1c[QrScannerRoute];
F2 --> F2a[EarningsRoute];
F2a --> F2b[EarningsHistoryRoute];
F3 --> F3a[ProfileMainRoute];
F3a --> F3b[RoleKitFlowRoute];
F3a --> F3c[CertificatesRoute];
F3a --> F3d[ScheduleRoute];
F3a --> F3e[WorkingAreaRoute];
F3a --> F3f[LivePhotoRoute];
F3a --> F3g[ProfileSettingsFlowRoute];
F3a --> F3h[WagesFormsFlowRoute];
F3a --> F3i[BankAccountFlowRoute];
F3a --> F3j[BenefitsRoute];
F3a --> F3k[SupportRoute];
F3a --> F3l[FaqRoute];
F3g --> F3g1[ProfileSettingsMenuRoute];
F3g1 --> F3g2[RoleRoute];
F3g1 --> F3g3[PersonalInfoRoute];
F3g1 --> F3g4[EmailVerificationRoute];
F3g4 --> L1;
F3g1 --> F3g5[AddressRoute];
F3g1 --> F3g6[EmergencyContactsRoute];
F3g1 --> F3g7[MobilityRoute];
F3g1 --> F3g8[InclusiveRoute];
F3h --> F3h1[FormsListRoute];
F3h1 --> F3h2[OfferLetterFormRoute];
F3h1 --> F3h3[EddFormRoute];
F3h1 --> F3h4[INineFormRoute];
F3h1 --> F3h5[WFourFormRoute];
F3h2 --> F3h6[FormSignRoute];
F3h3 --> F3h6;
F3h4 --> F3h6;
F3h5 --> F3h6;
F3h6 --> F3h7[SignedFormRoute];
F3h6 --> F3h8[FormPreviewRoute];
F3i --> F3i1[BankAccountRoute];
F3i1 --> F3i2[BankAccountEditRoute];
F3b --> F3b1[RolesKitListRoute];
F3b1 --> F3b2[RoleKitRoute];
H --> H1[CheckListRoute];
H1 --> H2[PersonalInfoRoute];
H1 --> H3[EmailVerificationRoute];
H3 --> L1;
H1 --> H4[EmergencyContactsRoute];
H1 --> H5[AddressRoute];
H1 --> H6[WorkingAreaRoute];
H1 --> H7[RoleRoute];
H1 --> H8[CertificatesRoute];
H1 --> H9[ScheduleRoute];
H1 --> F3i;
H1 --> F3h;
H1 --> F3b;
I --> I1[WelcomeRoute];
I1 --> I2[PhoneVerificationRoute];
I2 --> I3[CodeVerificationRoute];
I3 --> J{SingUpRedirectGuard};
J -- Prepare Profile --> K[SignupFlowRoute];
J -- Authenticated --> F;
J -- Admin Validation --> G;
J -- Unauthenticated/Error --> I;
K --> K1[PersonalInfoRoute];
K1 --> K2[EmailVerificationRoute];
K2 --> K3[EmergencyContactsRoute];
K2 --> L1;
K3 --> K4[MobilityRoute];
K4 --> K5[InclusiveRoute];
K5 --> K6[AddressRoute];
K6 --> K7[WorkingAreaRoute];
K7 --> K8[RoleRoute];
subgraph PhoneReLoginFlow
L1[PhoneReLoginFlowRoute]
L1 --> L2[CodeVerificationRoute]
end
subgraph CheckListFlow
H
end
subgraph AuthFlow
I
end
subgraph SignUpFlow
K
end
subgraph HomeFlow
F
end

View File

@@ -0,0 +1,85 @@
flowchart TD
subgraph AppInitialization
A[Start App] --> B{Check Auth Status};
B -- Authenticated --> C[Go to Home];
B -- Unauthenticated --> D[Go to Auth];
B -- Admin Validation --> E[Go to Waiting Validation];
B -- Prepare Profile --> F[Go to Checklist];
end
subgraph UserAuthentication
D --> G[Welcome Screen];
G --> H{Select Sign In/Up};
H -- Sign In --> I[Sign In With Phone];
I --> J[Verify Phone Code];
J -- Success --> C;
H -- Sign Up --> K[Go to User Onboarding];
end
subgraph UserOnboarding
K --> L[Collect Personal Info];
L --> M[Verify Email];
M --> N[Add Emergency Contacts];
N --> O[Specify Mobility];
O --> P[Provide Inclusivity Info];
P --> Q[Enter Address];
Q --> R[Define Working Area];
R --> S[Select Role];
S -- Success --> F;
end
subgraph ProfileCompletion
F --> T[View Checklist];
T --> U[Complete Personal Info];
T --> V[Complete Email Verification];
T --> W[Complete Emergency Contacts];
T --> X[Manage Certificates];
T --> Y[Set Schedule];
T --> Z[Manage Bank Account];
T --> AA[Fill Out Wage Forms];
T --> AB[Manage Role Kit];
AB -- All Complete --> C;
end
subgraph MainApp
C --> AC[Home Screen];
AC --> AD{Navigate};
AD -- Shifts --> AE[Shift Management];
AD -- Earnings --> AF[Earnings Management];
AD -- Profile --> AG[Profile Management];
end
subgraph ShiftManagement
AE --> AH[View Shifts];
AH --> AI[View Shift Details];
AH --> AJ[Clock In/Out via QR];
end
subgraph EarningsManagement
AF --> AK[View Current Earnings];
AK --> AL[View Earnings History];
end
subgraph ProfileManagement
AG --> AM[View Profile];
AM --> AN[Manage Role Kit];
AM --> AO[Manage Certificates];
AM --> AP[Manage Schedule];
AM --> AQ[Manage Working Area];
AM --> AR[Update Live Photo];
AM --> AS[Manage Profile Settings];
AS --> AT[Update Personal Info];
AS --> AU[Update Email];
AU --> AV[Re-login with Phone];
AS --> AW[Update Address];
AM --> AX[Manage Wage Forms];
AM --> AY[Manage Bank Account];
AM --> AZ[View Benefits];
AM --> BA[Access Support];
BA --> BB[View FAQs];
BA --> BC[Contact Support];
end
subgraph QRScanning
AJ --> BD[Scan QR Code];
end

View File

@@ -0,0 +1,39 @@
graph TD
subgraph User Authentication
direction LR
UA1[Flutter App] -->|Phone Number| UA2[Firebase Auth];
UA2 -->|Verification Code| UA1;
UA1 -->|Verification Code| UA2;
UA2 -->|Auth Token| UA1;
UA1 -->|Auth Token| UA3[GraphQL Server];
UA3 -->|User Data| UA1;
end
subgraph User Onboarding
direction LR
UO1[Flutter App] -->|Personal Info| UO2[GraphQL Server];
UO2 -->|update_staff_personal_info| UO3[Firebase Firestore];
UO2 -->|User Data| UO1;
end
subgraph Shift Management
direction LR
SM1[Flutter App] -->|Get Shifts| SM2[GraphQL Server];
SM2 -->|getShifts| SM3[Firebase Firestore];
SM3 -->|Shift Data| SM2;
SM2 -->|Shift Data| SM1;
SM1 -->|Accept Shift| SM2;
SM2 -->|accept_shift| SM3;
SM3 -->|Updated Shift| SM2;
SM2 -->|Updated Shift| SM1;
end
subgraph Profile Update with Avatar
direction LR
PU1[Flutter App] -->|Image| PU2[Firebase Storage];
PU2 -->|Image URL| PU1;
PU1 -->|Image URL & Personal Info| PU3[GraphQL Server];
PU3 -->|update_staff_personal_info & upload_staff_avatar| PU4[Firebase Firestore];
PU3 -->|User Data| PU1;
end

View File

@@ -0,0 +1,17 @@
timeline
title KROW Platform - Accelerated Migration & Enhancement Roadmap (2 Months to Production)
section Phase 1: Foundation & New Workflow Adoption
Week 1-2 : Initialize Firebase projects (Dev, Staging) and configure hosting<br>Set up CI/CD pipelines for automated deployments<br>Adopt new development and deployment workflows
Week 3-4 : Configure internal launchpad for easy access to resources<br>Team training on new tools and workflows<br>Documentation setup
Key Milestones : <b>Dev & Staging environments fully operational</b><br><b>Team ready to work with new infrastructure</b>
section Phase 2: Functional Parity & New Experience
Week 5-6 : Migrate core backend logic (Cloud Functions, Firestore/Cloud SQL)<br>Reconnect Web and Mobile apps to new APIs<br>Database migration and validation
Week 7-8 : Integrate new UI/UX design across all applications<br>Implement new core business workflows<br>Feature parity testing
Key Milestones : <b>All existing features are ISO-functional on the new platform</b><br><b>New design and core workflows fully integrated and tested</b>
section Phase 3: Preparation & Production Launch
Week 9-10 : Complete end-to-end testing and performance optimization<br>Security audits and penetration testing<br>Load testing and optimization
Week 11-12 : Set up robust monitoring and alerting system for production<br>Final production deployment<br>Legacy infrastructure decommissioning plan
Key Milestones : <b>KROW is live in production with new design and workflows</b><br><b>Legacy infrastructure ready for decommissioning</b>

View File

@@ -0,0 +1,10 @@
[
{
"title": "Architecture Document & Migration Plan",
"path": "./assets/documents/legacy/staff-mobile-application/architecture.md"
},
{
"title": "Architecture Document & Migration Plan",
"path": "./assets/documents/legacy/client-mobile-application/architecture.md"
}
]

View File

@@ -0,0 +1,252 @@
# Krow Mobile Client App Architecture Document
## A. Introduction
This document provides a comprehensive overview of the Krow mobile client application's architecture. The Krow app is a Flutter-based mobile application designed to connect staff with work opportunities. It includes features for event management, invoicing, staff rating, and profile management.
The core purpose of the app is to provide a seamless experience for staff to find, manage, and get paid for work, while allowing clients to manage their events and staff effectively.
## B. Full Architecture Overview
The Krow app is built using a layered architecture that separates concerns and promotes modularity. The main layers are the **Presentation Layer**, the **Domain Layer**, and the **Data Layer**, organized into feature-based modules.
### Key Modules and Layers
* **Features:** The `lib/features` directory contains the main features of the app, such as `sign_in`, `events`, `profile`, etc. Each feature directory is further divided into `presentation` and `domain` layers.
* **Presentation Layer:** This layer is responsible for the UI and user interaction. It contains the screens (widgets) and the BLoCs (Business Logic Components) that manage the state of the UI.
* **Domain Layer:** This layer contains the core business logic of the application. It includes the BLoCs, which are responsible for orchestrating the flow of data between the UI and the data layer, and the business objects (entities).
* **Data Layer:** This layer is responsible for all data-related operations. It includes the repositories that fetch data from the backend and the data sources themselves (e.g., GraphQL API, local cache).
* **Core:** The `lib/core` directory contains shared code that is used across multiple features, such as the API client, dependency injection setup, routing, and common widgets.
### Integration Points
* **UI to Domain:** The UI (widgets) dispatches events to the BLoCs in the domain layer based on user interactions.
* **Domain to Data:** The BLoCs in the domain layer call methods on the repositories in the data layer to fetch or update data.
* **Data to Backend:** The repositories in the data layer use the `ApiClient` to make GraphQL calls to the backend.
## C. Backend Architecture
The backend of the Krow app is a hybrid system that leverages both a **GraphQL server** and **Firebase services**.
```mermaid
flowchart TD
subgraph "Client"
A[Flutter App]
end
subgraph "Backend"
B[GraphQL Server (e.g., Node.js)]
C[Firebase]
end
subgraph "Firebase Services"
C1[Firebase Auth]
C2[Firebase Firestore]
C3[Firebase Storage]
end
A -- "GraphQL Queries/Mutations" --> B
A -- "Authentication" --> C1
B -- "Data Operations" --> C2
B -- "File Operations" --> C3
C1 -- "User Tokens" --> A
C2 -- "Data" --> B
C3 -- "Files" --> B
B -- "Data/Files" --> A
```
### GraphQL
The GraphQL server acts as an intermediary between the Flutter app and the Firebase services. It exposes a set of queries and mutations that the app can use to interact with the backend. This provides a single, unified API for the app to consume, simplifying data fetching and manipulation.
### Firebase Integration
* **Firebase Auth:** Firebase Auth is used for user authentication. The Flutter app interacts directly with Firebase Auth to handle user sign-in, sign-up, and password reset flows. Once authenticated, the app retrieves a Firebase ID token, which is then used to authenticate with the GraphQL server.
* **Firebase Firestore:** Firestore is the primary database for the application. The GraphQL server is responsible for all interactions with Firestore, including fetching, creating, updating, and deleting data.
* **Firebase Storage:** Firebase Storage is used for storing user-generated content, such as profile pictures. The GraphQL server handles file uploads and retrieves file URLs that are then sent to the app.
### End-to-End Communication Flow
1. The Flutter app authenticates the user with Firebase Auth.
2. The app receives a Firebase ID token.
3. For all subsequent API requests, the app sends the Firebase ID token in the authorization header of the GraphQL request.
4. The GraphQL server verifies the token and then executes the requested query or mutation.
5. The GraphQL server interacts with Firestore or Firebase Storage to fulfill the request.
6. The GraphQL server returns the requested data to the app.
## D. API Layer
The API layer is responsible for all communication with the backend. It is built around the `graphql_flutter` package and a custom `ApiClient`.
```mermaid
flowchart TD
subgraph "GraphQL API"
direction LR
subgraph "Queries"
Q1[getEvents]
Q2[getEventDetails]
Q3[getInvoices]
Q4[getInvoiceDetails]
Q5[getNotifications]
Q6[getNotificationDetails]
Q7[getProfile]
Q8[getAssignedStaff]
end
subgraph "Mutations"
M1[createEvent]
M2[updateProfile]
M3[rateStaff]
M4[clockIn]
M5[clockOut]
M6[uploadProfilePicture]
end
end
subgraph "Firebase"
direction LR
subgraph "Firestore Collections"
FS1[events]
FS2[invoices]
FS3[notifications]
FS4[users]
end
subgraph "Firebase Storage"
FB1[Profile Pictures]
end
end
Q1 --> FS1
Q2 --> FS1
Q3 --> FS2
Q4 --> FS2
Q5 --> FS3
Q6 --> FS3
Q7 --> FS4
Q8 --> FS1
Q8 --> FS4
M1 --> FS1
M2 --> FS4
M3 --> FS1
M3 --> FS4
M4 --> FS1
M5 --> FS1
M6 --> FB1
```
### API Handling
* **Error Handling:** The `ApiClient` uses the `ErrorPolicy.all` policy to catch all GraphQL errors. The BLoCs are responsible for catching these errors and updating the UI state accordingly.
* **Caching:** The `GraphQLCache` with `HiveStore` is used to cache GraphQL query results. The `fetchPolicy` is set to `cacheAndNetwork` to provide a fast user experience while keeping the data up-to-date.
* **Parsing:** The app uses the `json_serializable` package to parse the JSON responses from the GraphQL server into Dart objects.
## E. State Management
The Krow app uses the **BLoC (Business Logic Component)** pattern for state management, powered by the `flutter_bloc` package.
### Why BLoC?
* **Separation of Concerns:** BLoC separates the business logic from the UI, making the code more organized, testable, and maintainable.
* **Testability:** BLoCs are easy to test in isolation from the UI.
* **Reactivity:** BLoC uses streams to manage state, which makes it easy to update the UI in response to state changes.
### State Flow
1. The UI dispatches an event to the BLoC.
2. The BLoC receives the event and interacts with the data layer (repositories) to fetch or update data.
3. The data layer returns data or a success/failure status to the BLoC.
4. The BLoC updates its state based on the result from the data layer.
5. The UI rebuilds itself in response to the new state.
### Integration with the API Layer
The BLoCs do not interact directly with the `ApiClient`. Instead, they go through a repository layer, which abstracts the data source. This makes it possible to switch out the backend without having to change the BLoCs.
## F. Use-Case Flows
The following diagrams illustrate the flow for some of the major use cases in the app.
```mermaid
flowchart TD
subgraph "Sign-In Flow"
A1[User enters credentials] --> B1{SignInBloc};
B1 --> C1[Firebase Auth: signInWithEmailAndPassword];
C1 -- Success --> D1[Navigate to Home];
C1 -- Failure --> E1[Show error message];
end
subgraph "Password Reset Flow"
A2[User requests password reset] --> B2{SignInBloc};
B2 --> C2[Firebase Auth: sendPasswordResetEmail];
C2 -- Email Sent --> D2[User clicks deep link];
D2 --> E2[UI with new password fields];
E2 --> F2{SignInBloc};
F2 --> G2[Firebase Auth: confirmPasswordReset];
G2 -- Success --> H2[Show success message];
G2 -- Failure --> I2[Show error message];
end
subgraph "Event Listing Flow"
A3[User navigates to Events screen] --> B3{EventsBloc};
B3 --> C3[GraphQL Query: getEvents];
C3 --> D3[Firestore: events collection];
D3 -- Returns event data --> C3;
C3 -- Returns data --> B3;
B3 --> E3[Display list of events];
end
subgraph "Create Event Flow"
A4[User submits new event form] --> B4{CreateEventBloc};
B4 --> C4[GraphQL Mutation: createEvent];
C4 --> D4[Firestore: events collection];
D4 -- Success --> C4;
C4 -- Returns success --> B4;
B4 --> E4[Navigate to event details];
end
subgraph "Profile Viewing Flow"
A5[User navigates to Profile screen] --> B5{ProfileBloc};
B5 --> C5[GraphQL Query: getProfile];
C5 --> D5[Firestore: users collection];
D5 -- Returns profile data --> C5;
C5 -- Returns data --> B5;
B5 --> E5[Display profile information];
end
```
## G. Replacing or Plugging in a New Backend: Considerations & Recommendations
This section provides guidance on how to replace the current GraphQL + Firebase backend with a different backend solution.
### Tightly Coupled Components
* **`ApiClient`:** This class is tightly coupled to `graphql_flutter`.
* **Firebase Auth:** The authentication logic is directly tied to the `firebase_auth` package.
* **BLoCs:** Some BLoCs might have direct dependencies on Firebase or GraphQL-specific models.
### Abstraction Recommendations
To make the architecture more backend-agnostic, the following abstractions should be implemented:
* **Repositories:** Create an abstract `Repository` class for each feature in the `domain` layer. The implementation of this repository will be in the `data` layer. The BLoCs should only depend on the abstract repository.
* **Authentication Service:** Create an abstract `AuthService` class that defines the methods for authentication (e.g., `signIn`, `signOut`, `getToken`). The implementation of this service will be in the `data` layer and will use the specific authentication provider (e.g., Firebase Auth, OAuth).
* **Data Transfer Objects (DTOs):** Use DTOs to transfer data between the data layer and the domain layer. This will prevent the domain layer from having dependencies on backend-specific models.
### Suggested Design Improvements
* **Formalize Clean Architecture:** While the current architecture has elements of Clean Architecture, it could be more formally implemented by creating a clear separation between the `domain`, `data`, and `presentation` layers for all features.
* **Introduce Use Cases:** Introduce `UseCase` classes in the `domain` layer to encapsulate specific business operations. This will make the BLoCs simpler and more focused on state management.
### Migration Strategies
To replace the current backend with a new one (e.g., REST API, Supabase), follow these steps:
1. **Implement New Repositories:** Create new implementations of the repository interfaces for the new backend.
2. **Implement New Auth Service:** Create a new implementation of the `AuthService` interface for the new authentication provider.
3. **Update Dependency Injection:** Use dependency injection (e.g., `get_it` and `injectable`) to provide the new repository and auth service implementations to the BLoCs.
4. **Gradual Migration:** If possible, migrate one feature at a time to the new backend. This will reduce the risk of breaking the entire application at once.

View File

@@ -0,0 +1,120 @@
# Krow Mobile Staff App - Architecture Document
## A. Introduction
This document outlines the architecture of the Krow Mobile Staff App, a Flutter application designed to connect staff with job opportunities. The app provides features for staff to manage their profiles, view and apply for shifts, track earnings, and complete necessary paperwork.
The core purpose of the app is to streamline the process of finding and managing temporary work, providing a seamless experience for staff from onboarding to payment.
## B. Full Architecture Overview
The application follows a **Clean Architecture** pattern, separating concerns into three main layers: **Presentation**, **Domain**, and **Data**. This layered approach promotes a separation of concerns, making the codebase more maintainable, scalable, and testable.
- **Presentation Layer:** This layer is responsible for the UI and user interaction. It consists of widgets, screens, and Blocs that manage the UI state. The Presentation Layer depends on the Domain Layer to execute business logic.
- **Domain Layer:** This layer contains the core business logic of the application. It consists of use cases (interactors), entities (business objects), and repository interfaces. The Domain Layer is independent of the other layers.
- **Data Layer:** This layer is responsible for data retrieval and storage. It consists of repository implementations, data sources (API clients, local database), and data transfer objects (DTOs). The Data Layer depends on the Domain Layer and implements the repository interfaces defined in it.
### Integration Points
- **UI → Domain:** The UI (e.g., a button press) triggers a method in a Bloc. The Bloc then calls a use case in the Domain Layer to execute the business logic.
- **Domain → Data:** The use case calls a method on a repository interface.
- **Data → External:** The repository implementation, located in the Data Layer, communicates with external data sources (GraphQL API, Firebase, local storage) to retrieve or store data.
## C. Backend Architecture
The backend is built on a combination of a **GraphQL server** and **Firebase services**.
- **GraphQL Server:** The primary endpoint for the Flutter app. It handles most of the business logic and data aggregation. The server is responsible for communicating with Firebase services to fulfill requests.
- **Firebase Services:**
- **Firebase Auth:** Used for user authentication, primarily with phone number verification.
- **Firebase Firestore:** The main database for storing application data, such as user profiles, shifts, and earnings.
- **Firebase Storage:** Used for storing user-generated content, such as profile avatars.
- **Firebase Cloud Messaging:** Used for sending push notifications to users.
- **Firebase Remote Config:** Used for remotely configuring app parameters.
### API Flow
1. **Flutter App to GraphQL:** The Flutter app sends GraphQL queries and mutations to the GraphQL server.
2. **GraphQL to Firebase:** The GraphQL server resolves these operations by interacting with Firebase services. For example, a `getShifts` query will fetch data from Firestore, and an `updateStaffPersonalInfoWithAvatar` mutation will update a document in Firestore and upload a file to Firebase Storage.
3. **Response Flow:** The data flows back from Firebase to the GraphQL server, which then sends it back to the Flutter app.
## D. API Layer
The API layer is responsible for all communication with the backend.
- **GraphQL Operations:** The app uses the `graphql_flutter` package to interact with the GraphQL server. Queries, mutations, and subscriptions are defined in `.dart` files within each feature's `data` directory.
- **API Error Handling:** The `ApiClient` class is responsible for handling API errors. It catches exceptions and returns a `Failure` object, which is then handled by the Bloc in the Presentation Layer to show an appropriate error message to the user.
- **Caching:** The `graphql_flutter` client provides caching capabilities. The app uses a `HiveStore` to cache GraphQL responses, reducing the number of network requests and improving performance.
- **Parsing:** JSON responses from the API are parsed into Dart objects using the `json_serializable` package.
## E. State Management
The application uses the **Bloc** library for state management.
- **Why Bloc?** Bloc is a predictable state management library that helps to separate business logic from the UI. It enforces a unidirectional data flow, making the app's state changes predictable and easier to debug.
- **State Flow:**
1. **UI Event:** The UI dispatches an event to the Bloc.
2. **Bloc Logic:** The Bloc receives the event, executes the necessary business logic (often by calling a use case), and emits a new state.
3. **UI Update:** The UI listens to the Bloc's state changes and rebuilds itself to reflect the new state.
- **Integration with API Layer:** Blocs interact with the API layer through use cases. When a Bloc needs to fetch data from the backend, it calls a use case, which in turn calls a repository that communicates with the API.
## F. Use-Case Flows
### User Authentication
1. **UI:** The user enters their phone number.
2. **Logic:** The `AuthBloc` sends the phone number to Firebase Auth for verification.
3. **Backend:** Firebase Auth sends a verification code to the user's phone.
4. **UI:** The user enters the verification code.
5. **Logic:** The `AuthBloc` verifies the code with Firebase Auth.
6. **Backend:** Firebase Auth returns an auth token.
7. **Logic:** The app sends the auth token to the GraphQL server to get the user's profile.
8. **Response:** The GraphQL server returns the user's data, and the app navigates to the home screen.
### Shift Management
1. **UI:** The user navigates to the shifts screen.
2. **Logic:** The `ShiftsBloc` requests a list of shifts.
3. **Backend:** The use case calls the `ShiftsRepository`, which sends a `getShifts` query to the GraphQL server. The server fetches the shifts from Firestore.
4. **Response:** The GraphQL server returns the list of shifts, which is then displayed on the UI.
## G. Replacing or Plugging in a New Backend: Considerations & Recommendations
This section provides guidance on how to replace the current GraphQL + Firebase backend with a different solution (e.g., REST, Supabase, Hasura).
### Tightly Coupled Components
- **Data Layer:** The current `ApiProvider` implementations are tightly coupled to the GraphQL API.
- **Authentication:** The authentication flow is tightly coupled to Firebase Auth.
- **DTOs:** The data transfer objects are generated based on the GraphQL schema.
### Abstraction Recommendations
To make the architecture more backend-agnostic, the following components should be abstracted:
- **Repositories:** The repository interfaces in the Domain Layer should remain unchanged. The implementations in the Data Layer will need to be rewritten for the new backend.
- **Services:** Services like authentication should be abstracted behind an interface. For example, an `AuthService` interface can be defined in the Domain Layer, with a `FirebaseAuthService` implementation in the Data Layer.
- **DTOs:** The DTOs should be mapped to domain entities in the Data Layer. This ensures that the Domain Layer is not affected by changes in the backend's data model.
- **Error Handling:** A generic error handling mechanism should be implemented to handle different types of backend errors.
### Suggested Design Improvements
- **Introduce a Service Locator:** Use a service locator like `get_it` to decouple the layers and make it easier to swap out implementations.
- **Define Abstract Data Sources:** Instead of directly calling the API client in the repository implementations, introduce abstract data source interfaces (e.g., `UserRemoteDataSource`). This adds another layer of abstraction and makes the repositories more testable.
### Migration Strategies
1. **Define Interfaces:** Start by defining abstract interfaces for all backend interactions (repositories, services).
2. **Implement New Data Layer:** Create a new implementation of the Data Layer for the new backend. This will involve writing new repository implementations, API clients, and DTOs.
3. **Swap Implementations:** Use the service locator to swap the old Data Layer implementation with the new one.
4. **Test:** Thoroughly test the application to ensure that everything works as expected with the new backend.
By following these recommendations, the Krow Mobile Staff App can be migrated to a new backend with minimal impact on the overall architecture and business logic.

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-gray-700" fill="currentColor" viewBox="0 0 24 24">
<path
d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09l.01-.01zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 439 B

View File

@@ -0,0 +1 @@
<svg class="w-6 h-6 text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9"></path></svg>

After

Width:  |  Height:  |  Size: 330 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 354 B

View File

@@ -0,0 +1,4 @@
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z"></path>
</svg>

After

Width:  |  Height:  |  Size: 280 B

View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" class="w-6 h-6 text-pink-600">
<path
d="M22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C12.8417 22 14 22.1163 14 21C14 20.391 13.6832 19.9212 13.3686 19.4544C12.9082 18.7715 12.4523 18.0953 13 17C13.6667 15.6667 14.7778 15.6667 16.4815 15.6667C17.3334 15.6667 18.3334 15.6667 19.5 15.5C21.601 15.1999 22 13.9084 22 12Z"
stroke="currentColor" stroke-width="2"></path>
<path d="M7 15.002L7.00868 14.9996" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round"></path>
<circle cx="9.5" cy="8.5" r="1.5" stroke="currentColor" stroke-width="2"></circle>
<circle cx="16.5" cy="9.5" r="1.5" stroke="currentColor" stroke-width="2"></circle>
</svg>

After

Width:  |  Height:  |  Size: 819 B

View File

@@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" viewBox="0 0 200 300" class="w-5 h-5">
<style>
.st0 {
fill: #0acf83
}
.st1 {
fill: #a259ff
}
.st2 {
fill: #f24e1e
}
.st3 {
fill: #ff7262
}
.st4 {
fill: #1abcfe
}
</style>
<title>Figma.logo</title>
<desc>Created using Figma</desc>
<path id="path0_fill" class="st0" d="M50 300c27.6 0 50-22.4 50-50v-50H50c-27.6 0-50 22.4-50 50s22.4 50 50 50z" />
<path id="path1_fill" class="st1" d="M0 150c0-27.6 22.4-50 50-50h50v100H50c-27.6 0-50-22.4-50-50z" />
<path id="path1_fill_1_" class="st2" d="M0 50C0 22.4 22.4 0 50 0h50v100H50C22.4 100 0 77.6 0 50z" />
<path id="path2_fill" class="st3" d="M100 0h50c27.6 0 50 22.4 50 50s-22.4 50-50 50h-50V0z" />
<path id="path3_fill" class="st4" d="M200 150c0 27.6-22.4 50-50 50s-50-22.4-50-50 22.4-50 50-50 50 22.4 50 50z" />
</svg>

After

Width:  |  Height:  |  Size: 995 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-orange-500" fill="currentColor" viewBox="0 0 24 24">
<path
d="M3.89 15.672L6.255.461A.542.542 0 017.27.288l2.543 4.771zm16.794 3.692l-2.25-14.03a.542.542 0 00-.919-.295L3.316 19.365l7.856 4.427a1.621 1.621 0 001.588 0zM14.3 7.147l-1.82-3.482a.542.542 0 00-.96 0L3.53 17.984z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-gray-900" fill="currentColor" viewBox="0 0 24 24">
<path
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 831 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-blue-600" fill="currentColor" viewBox="0 0 24 24">
<path
d="M12.19 2.38a8.85 8.85 0 00-10.4 9.28l5.18-5.18a4.89 4.89 0 012.5-.72 4.89 4.89 0 011.72-.07zm7.6 2.24a8.85 8.85 0 01-7.6 14.91l4.5-4.5a4.89 4.89 0 002.45-2.55 4.89 4.89 0 00.65-7.86z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 300 B

View File

@@ -0,0 +1,5 @@
<svg class="w-5 h-5 text-green-600" fill="currentColor" viewBox="0 0 24 24">
<path
d="M3,20.5V3.5C3,2.91 3.34,2.39 3.84,2.15L13.69,12L3.84,21.85C3.34,21.6 3,21.09 3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08 20.75,11.5 20.75,12C20.75,12.5 20.53,12.9 20.18,13.18L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 412 B

View File

@@ -0,0 +1,4 @@
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 18h.01M8 21h8a2 2 0 002-2V5a2 2 0 00-2-2H8a2 2 0 00-2 2v14a2 2 0 002 2z"></path>
</svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@@ -0,0 +1,6 @@
<svg class="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
</path>
</svg>

After

Width:  |  Height:  |  Size: 436 B

View File

@@ -0,0 +1,5 @@
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253">
</path>
</svg>

After

Width:  |  Height:  |  Size: 440 B

View File

@@ -0,0 +1,88 @@
async function loadLinks() {
const container = document.getElementById('links-container');
if (!container) return;
try {
const response = await fetch('./assets/data/links.json');
if (!response.ok) {
throw new Error(`Failed to load links: ${response.status}`);
}
const groups = await response.json();
// Helper function to fetch SVG content
const fetchSvg = async (path) => {
if (!path) return '';
try {
const res = await fetch(path);
if (!res.ok) return '';
return await res.text();
} catch (e) {
console.error(`Failed to load SVG: ${path}`, e);
return '';
}
};
// Process groups and fetch SVGs in parallel
const groupsWithSvgs = await Promise.all(groups.map(async (group) => {
const groupIconSvg = await fetchSvg(group.iconPath);
const linksWithSvgs = await Promise.all(group.links.map(async (link) => {
const linkIconSvg = link.iconPath ? await fetchSvg(link.iconPath) : '';
return { ...link, iconSvg: linkIconSvg };
}));
return { ...group, iconSvg: groupIconSvg, links: linksWithSvgs };
}));
container.innerHTML = groupsWithSvgs.map(group => `
<!-- ${group.title} Card -->
<div class="card-hover bg-white rounded-2xl shadow-lg p-6 border border-gray-100">
<div class="flex items-center space-x-3 mb-6">
<div class="w-10 h-10 ${group.iconColorClass} rounded-lg flex items-center justify-center">
${group.iconSvg}
</div>
<h3 class="text-xl font-bold text-gray-900">${group.title}</h3>
</div>
<div class="space-y-3">
${group.links.map(link => `
<a href="${link.url}" target="_blank"
class="flex items-center justify-between p-4 ${link.containerClass} rounded-xl transition-all group">
<div class="flex items-center space-x-3">
${link.iconClass ? `<div class="${link.iconClass}"></div>` : link.iconSvg}
${link.subtitle ? `
<div>
<div class="font-medium text-gray-900 ${link.textHoverClass}">${link.title}</div>
<div class="text-xs text-gray-500">${link.subtitle}</div>
</div>
` : `
<span class="font-medium text-gray-900 ${link.textHoverClass}">${link.title}</span>
`}
</div>
${link.badge ? `
<span class="px-3 py-1 ${link.badgeColorClass} text-white text-xs font-semibold rounded-full">${link.badge}</span>
` : ''}
${link.arrowIcon ? `
<svg class="w-5 h-5 text-gray-400 group-hover:translate-x-1 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
` : ''}
</a>
`).join('')}
</div>
</div>
`).join('');
} catch (error) {
console.error('Error loading links:', error);
container.innerHTML = `
<div class="col-span-full p-4 bg-red-50 text-red-600 rounded-xl border border-red-200">
Failed to load application links. Please try refreshing the page.
</div>
`;
}
}
// Load links when the DOM is loaded
document.addEventListener('DOMContentLoaded', loadLinks);

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="200 180 280 140" style="enable-background:new 0 0 500 500;" xml:space="preserve">
<style type="text/css">
.st0{fill:#24303B;}
.st1{fill:#002FE3;}
</style>
<g>
<path class="st1" d="M459.81,202.55c-5.03,0.59-9.08,4.49-10.36,9.38l-15.99,59.71l-16.24-56.3
c-1.68-5.92-6.22-10.86-12.19-12.34c-1.58-0.39-3.11-0.54-4.64-0.49h-0.15c-1.53-0.05-3.11,0.1-4.64,0.49
c-5.97,1.48-10.51,6.42-12.24,12.34l-3.6,12.53l-11.35,39.38l-7.9-27.54c-10.76-37.5-48.56-62.23-88.38-55.32
c-33.26,5.82-57.05,35.68-56.99,69.48v0.79c0,4.34,0.39,8.73,1.13,13.18c0.18,1.02,0.37,2.03,0.6,3.03
c1.84,8.31,10.93,12.73,18.49,8.8v0c5.36-2.79,7.84-8.89,6.42-14.77c-0.85-3.54-1.28-7.23-1.23-11.03
c0-25.02,20.48-45.5,45.55-45.2c7.6,0.1,15.59,2.07,23.59,6.37c13.52,7.3,23.15,20.18,27.34,34.94l13.32,46.34
c1.73,5.97,6.22,11,12.24,12.58c9.62,2.62,19-3.06,21.51-12.04l16.09-56.7l0.2-0.1l16.09,56.85c1.63,5.68,5.87,10.41,11.55,11.99
c9.13,2.57,18.11-2.66,20.67-11.2l24.13-79.6C475.35,209.85,468.64,201.56,459.81,202.55z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,14 @@
# List of authorized users for the Krow DevOps Launchpad
# Format: one email per line, lines starting with # are comments
#
# Users must be listed here to access the Launchpad via Firebase Auth.
# Both internal (@krowwithus.com) and external emails are supported.
user:admin@krowwithus.com
# External users - Oloodi employees
user:boris@oloodi.com
user:achintha.isuru@oloodi.com
# External users - Legendary employees

View File

@@ -0,0 +1,832 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Krow DevOps Launchpad</title>
<link rel="icon" type="image/x-icon" href="favicon.svg">
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Mermaid -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.9.1/mermaid.min.js"></script>
<!-- Marked.js for Markdown parsing -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- Custom Tailwind Config -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
}
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap');
* {
font-family: 'Inter', sans-serif;
}
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.card-hover {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.card-hover:hover {
transform: translateY(-4px);
box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
}
.nav-item {
transition: all 0.2s ease;
}
.nav-item:hover {
transform: translateX(4px);
}
.badge-pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: .7; }
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
#diagram-container:active {
cursor: grabbing;
}
/* Accordion styles */
.accordion-button {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 0.75rem 1rem;
font-size: 0.875rem;
color: #4b5563;
text-align: left;
background-color: #f9fafb;
border-radius: 0.5rem;
transition: background-color 0.2s ease;
}
.accordion-button:hover {
background-color: #f3f4f6;
}
.accordion-button .chevron {
transition: transform 0.2s ease;
}
.accordion-button[aria-expanded="true"] .chevron {
transform: rotate(90deg);
}
.accordion-panel {
overflow: hidden;
transition: max-height 0.3s ease-out;
max-height: 0;
}
/* Markdown styling */
.markdown-content { line-height: 1.7; color: #374151; }
.markdown-content h1 { font-size: 2em; font-weight: 700; margin-top: 1.5em; margin-bottom: 0.5em; padding-bottom: 0.3em; border-bottom: 2px solid #e5e7eb; color: #111827; }
.markdown-content h1:first-child { margin-top: 0; }
.markdown-content h2 { font-size: 1.5em; font-weight: 600; margin-top: 1.5em; margin-bottom: 0.5em; padding-bottom: 0.2em; border-bottom: 1px solid #e5e7eb; color: #111827; }
.markdown-content h3 { font-size: 1.25em; font-weight: 600; margin-top: 1.2em; margin-bottom: 0.5em; color: #111827; }
.markdown-content h4 { font-size: 1.1em; font-weight: 600; margin-top: 1em; margin-bottom: 0.5em; color: #111827; }
.markdown-content p { margin-bottom: 1em; }
.markdown-content ul, .markdown-content ol { margin-bottom: 1em; padding-left: 2em; }
.markdown-content ul { list-style-type: disc; }
.markdown-content ol { list-style-type: decimal; }
.markdown-content li { margin-bottom: 0.5em; }
.markdown-content code { background-color: #f3f4f6; padding: 0.2em 0.4em; border-radius: 0.25em; font-size: 0.9em; font-family: 'Courier New', monospace; color: #dc2626; }
.markdown-content pre { background-color: #1f2937; color: #f9fafb; padding: 1em; border-radius: 0.5em; overflow-x: auto; margin-bottom: 1em; }
.markdown-content pre code { background-color: transparent; padding: 0; color: inherit; }
.markdown-content blockquote { border-left: 4px solid #3b82f6; padding-left: 1em; margin: 1em 0; color: #6b7280; font-style: italic; }
.markdown-content a { color: #3b82f6; text-decoration: underline; }
.markdown-content a:hover { color: #2563eb; }
.markdown-content table { width: 100%; border-collapse: collapse; margin-bottom: 1em; }
.markdown-content th, .markdown-content td { border: 1px solid #e5e7eb; padding: 0.5em; text-align: left; }
.markdown-content th { background-color: #f9fafb; font-weight: 600; }
.markdown-content img { max-width: 100%; height: auto; border-radius: 0.5em; margin: 1em 0; }
.markdown-content hr { border: none; border-top: 2px solid #e5e7eb; margin: 2em 0; }
/* Loading Overlay */
#auth-loading {
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
background: white; z-index: 50;
display: flex; flex-direction: column; align-items: center; justify-content: center;
}
#login-screen {
display: none;
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
z-index: 40;
align-items: center; justify-content: center;
}
</style>
</head>
<body class="bg-gradient-to-br from-gray-50 to-gray-100 min-h-screen">
<!-- Auth Loading State -->
<div id="auth-loading">
<div class="w-16 h-16 border-4 border-primary-200 border-t-primary-600 rounded-full animate-spin mb-4"></div>
<p class="text-gray-500 font-medium">Verifying access...</p>
</div>
<!-- Login Screen -->
<div id="login-screen" class="flex">
<div class="bg-white p-8 rounded-2xl shadow-xl max-w-md w-full mx-4 text-center">
<div class="flex justify-center mb-6">
<img src="logo.svg" alt="KROW Logo" class="h-16 w-16" onerror="this.src='https://via.placeholder.com/64?text=KROW'">
</div>
<h1 class="text-2xl font-bold text-gray-900 mb-2">Internal DevOps Launchpad</h1>
<p class="text-gray-500 mb-8">Please sign in to access internal development resources.</p>
<button id="google-signin-btn" class="w-full flex items-center justify-center space-x-3 bg-white border border-gray-300 hover:bg-gray-50 text-gray-700 font-medium py-3 px-4 rounded-xl transition-all shadow-sm">
<svg class="w-5 h-5" viewBox="0 0 24 24">
<path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" />
<path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" />
<path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" />
<path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" />
</svg>
<span>Sign in with Google</span>
</button>
<p id="login-error" class="mt-4 text-red-500 text-sm hidden"></p>
</div>
</div>
<!-- Main Content (Protected) -->
<div id="app-content" class="hidden flex h-screen overflow-hidden">
<!-- Sidebar -->
<aside class="w-72 bg-white shadow-xl flex flex-col border-r border-gray-200">
<!-- Logo Section -->
<div class="p-6 border-b border-gray-200">
<div class="flex items-center justify-center space-x-3">
<div class="w-12 h-12 rounded-xl flex items-center justify-center">
<img src="logo.svg" alt="Krow Logo" style="height: 60px;" onerror="this.style.display='none'">
</div>
<div>
<h1 class="text-xl font-bold text-gray-900">KROW DevOps</h1>
<p class="text-xs text-gray-500">Launchpad Hub</p>
</div>
</div>
</div>
<!-- Navigation -->
<nav class="flex-1 overflow-y-auto scrollbar-hide p-4" id="sidebar-nav">
<a href="#" id="nav-home" onclick="showView('home', this)"
class="nav-item flex items-center space-x-3 px-4 py-3 rounded-xl text-gray-700 bg-primary-50 border border-primary-200 font-medium mb-2">
<svg class="w-5 h-5 text-primary-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6">
</path>
</svg>
<span>Home</span>
</a>
<!-- Dynamic diagrams section - ALL diagrams loaded here -->
<div id="dynamic-diagrams-section"></div>
<!-- Documentation section -->
<div id="documentation-section"></div>
</nav>
<!-- Footer -->
<div class="p-4 border-t border-gray-200 bg-gray-50">
<div class="flex flex-col space-y-2">
<div class="flex items-center space-x-2 text-xs text-gray-500">
<div class="w-2 h-2 bg-green-500 rounded-full badge-pulse"></div>
<span>System Online</span>
</div>
<div class="flex items-center justify-between pt-2 border-t border-gray-100">
<span id="user-email" class="text-xs text-gray-400 truncate max-w-[150px]"></span>
<button id="logout-btn" class="text-xs text-red-500 hover:text-red-700 font-medium">Sign Out</button>
</div>
</div>
</div>
</aside>
<!-- Main Content Area -->
<main class="flex-1 overflow-y-auto">
<!-- Home View -->
<div id="home-view" class="p-8">
<!-- Header -->
<div class="mb-8">
<h2 class="text-3xl font-bold text-gray-900 mb-2">Krow DevOps Launchpad</h2>
<p class="text-gray-600">Central hub for KROW development and operations infrastructure</p>
</div>
<div id="links-container" class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- Links will be loaded dynamically -->
<div class="col-span-full flex justify-center p-12">
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-primary-600"></div>
</div>
</div>
</div>
<!-- Diagram Viewer -->
<div id="diagram-viewer" class="hidden h-full flex flex-col p-8">
<div class="flex items-center justify-between mb-6">
<h3 id="diagram-title" class="text-2xl font-bold text-gray-900"></h3>
<div class="flex items-center space-x-2 bg-white rounded-xl shadow-lg p-2 border border-gray-200">
<button id="zoomInBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors"
title="Zoom In">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM10 7v6m3-3H7"></path>
</svg>
</button>
<button id="zoomOutBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors"
title="Zoom Out">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0zM13 10H7"></path>
</svg>
</button>
<button id="resetBtn" class="p-2 hover:bg-gray-100 rounded-lg transition-colors"
title="Reset View">
<svg class="w-5 h-5 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15">
</path>
</svg>
</button>
</div>
</div>
<div id="diagram-container" tabindex="-1"
class="flex-1 bg-white rounded-2xl shadow-xl border border-gray-200 overflow-hidden cursor-grab flex items-center justify-center p-8">
<!-- SVG will be loaded here -->
</div>
</div>
<!-- Document Viewer -->
<div id="document-viewer" class="hidden h-full flex flex-col p-8">
<div class="mb-6">
<h3 id="document-title" class="text-2xl font-bold text-gray-900"></h3>
</div>
<div id="document-container"
class="flex-1 bg-white rounded-2xl shadow-xl border border-gray-200 overflow-y-auto p-8 markdown-content">
<!-- Document content will be loaded here -->
</div>
</div>
</main>
</div>
<!-- Links Loader -->
<script src="assets/js/links-loader.js"></script>
<!-- Panzoom -->
<script src="https://cdn.jsdelivr.net/npm/@panzoom/panzoom@4.5.1/dist/panzoom.min.js"></script>
<!-- Firebase Auth Logic -->
<script type="module">
import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js';
import { getAuth, GoogleAuthProvider, signInWithPopup, onAuthStateChanged, signOut } from 'https://www.gstatic.com/firebasejs/10.8.0/firebase-auth.js';
// Elements
const authLoading = document.getElementById('auth-loading');
const loginScreen = document.getElementById('login-screen');
const appContent = document.getElementById('app-content');
const googleBtn = document.getElementById('google-signin-btn');
const logoutBtn = document.getElementById('logout-btn');
const loginError = document.getElementById('login-error');
const userEmailSpan = document.getElementById('user-email');
let pendingError = null;
// Initialize Firebase
// Note: fetch('/__/firebase/init.json') works only on deployed Firebase Hosting or firebase serve
async function initAuth() {
try {
let config;
// Fetch config from hosting environment
const res = await fetch('/__/firebase/init.json');
if (!res.ok) throw new Error('Failed to load Firebase config. Ensure you are running via "make launchpad-dev" or deployed on Hosting.');
config = await res.json();
console.log("Firebase Config Loaded:", config.projectId);
const app = initializeApp(config);
const auth = getAuth(app);
// Auth State Observer
onAuthStateChanged(auth, async (user) => {
if (user) {
// User is signed in, check if allowed
const allowed = await checkAccess(user.email);
if (allowed) {
showApp(user);
} else {
pendingError = `Access Denied: <b>${user.email}</b> is not authorized.<br>Please contact the Krow Internal Developers or an Administrator to request access.`;
signOut(auth);
}
} else {
// User is signed out
if (pendingError) {
showLogin(pendingError);
pendingError = null;
} else {
showLogin();
}
}
});
// Login Handler
googleBtn.addEventListener('click', () => {
// Clear previous errors
loginError.classList.add('hidden');
const provider = new GoogleAuthProvider();
signInWithPopup(auth, provider).catch((error) => {
console.error("Login failed:", error);
showLogin("Login failed: " + error.message);
});
});
// Logout Handler
logoutBtn.addEventListener('click', () => {
signOut(auth);
});
} catch (e) {
console.error("Auth init error:", e);
// Fallback for local dev without firebase serving
if (window.location.hostname === 'localhost') {
alert("Firebase Auth failed to load. Ensure you are using 'firebase serve' or have configured local auth.");
}
}
}
async function checkAccess(email) {
try {
// 1. Fetch the secure list of hashes
const res = await fetch('allowed-hashes.json');
if (!res.ok) return false;
const allowedHashes = await res.json();
// 2. Hash the user's email (SHA-256)
const normalizedEmail = email.trim().toLowerCase();
const msgBuffer = new TextEncoder().encode(normalizedEmail);
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
// 3. Compare
return allowedHashes.includes(hashHex);
} catch (e) {
console.error("Failed to check access list:", e);
return false;
}
}
function showApp(user) {
authLoading.style.display = 'none';
loginScreen.style.display = 'none';
appContent.classList.remove('hidden');
userEmailSpan.textContent = user.email;
// Trigger link loading if not already done
if (typeof loadLinks === 'function') loadLinks();
}
function showLogin(errorMsg) {
authLoading.style.display = 'none';
appContent.classList.add('hidden');
loginScreen.style.display = 'flex';
if (errorMsg) {
loginError.innerHTML = errorMsg;
loginError.classList.remove('hidden');
} else {
loginError.classList.add('hidden');
}
}
// Start
initAuth();
</script>
<script>
let allDiagrams = [];
let allDocuments = [];
const homeView = document.getElementById('home-view');
const diagramViewer = document.getElementById('diagram-viewer');
const diagramContainer = document.getElementById('diagram-container');
const diagramTitle = document.getElementById('diagram-title');
const documentViewer = document.getElementById('document-viewer');
const documentContainer = document.getElementById('document-container');
const documentTitle = document.getElementById('document-title');
const zoomInBtn = document.getElementById('zoomInBtn');
const zoomOutBtn = document.getElementById('zoomOutBtn');
const resetBtn = document.getElementById('resetBtn');
let panzoomInstance = null;
let currentScale = 1;
// Initialize Mermaid
mermaid.initialize({
startOnLoad: false,
theme: 'default',
flowchart: {
useMaxWidth: false,
htmlLabels: true,
curve: 'basis'
}
});
// Build hierarchical structure from paths
function buildHierarchy(items, pathPrefix) {
const hierarchy = { _root: { _items: [], _children: {} } };
items.forEach(item => {
let relativePath = item.path;
if (relativePath.startsWith('./')) {
relativePath = relativePath.substring(2);
}
if (relativePath.startsWith(pathPrefix)) {
relativePath = relativePath.substring(pathPrefix.length);
}
const parts = relativePath.split('/');
const relevantParts = parts.slice(0, -1); // remove filename
let current = hierarchy._root;
relevantParts.forEach(part => {
if (!current._children[part]) {
current._children[part] = { _items: [], _children: {} };
}
current = current._children[part];
});
current._items.push(item);
});
return hierarchy;
}
// Generic function to create accordion navigation
function createAccordionNavigation(hierarchy, parentElement, createLinkFunction, sectionTitle) {
const createAccordion = (title, items, children) => {
const container = document.createElement('div');
container.className = 'mb-1';
const button = document.createElement('button');
button.className = 'accordion-button';
button.setAttribute('aria-expanded', 'false');
button.innerHTML = `
<span class="font-medium">${title.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}</span>
<svg class="chevron w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
`;
const panel = document.createElement('div');
panel.className = 'accordion-panel pl-4 pt-1';
if (items) {
items.forEach(item => createLinkFunction(item, panel, 1));
}
if (children) {
Object.keys(children).forEach(childKey => {
const childSection = children[childKey];
const childHeading = document.createElement('div');
childHeading.className = 'px-4 pt-2 pb-1 text-xs font-semibold text-gray-400 uppercase tracking-wider';
childHeading.textContent = childKey.replace(/-/g, ' ');
panel.appendChild(childHeading);
childSection._items.forEach(item => createLinkFunction(item, panel, 2));
});
}
button.addEventListener('click', () => {
const isExpanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', !isExpanded);
if (!isExpanded) {
panel.style.maxHeight = panel.scrollHeight + 'px';
} else {
panel.style.maxHeight = '0px';
}
});
container.appendChild(button);
container.appendChild(panel);
return container;
};
const heading = document.createElement('div');
heading.className = 'px-4 text-xs font-semibold text-gray-500 uppercase tracking-wider mt-6 mb-3';
heading.textContent = sectionTitle;
parentElement.appendChild(heading);
// Process root items first
if (hierarchy._root && hierarchy._root._items.length > 0) {
hierarchy._root._items.forEach(item => createLinkFunction(item, parentElement, 0));
}
// Process categories as accordions
Object.keys(hierarchy._root._children).forEach(key => {
if (key.startsWith('_')) return;
const section = hierarchy._root._children[key];
const accordion = createAccordion(key, section._items, section._children);
parentElement.appendChild(accordion);
});
}
// Helper function to create a document link
function createDocumentLink(doc, parentElement, level) {
const link = document.createElement('a');
link.href = '#';
link.className = 'nav-item flex items-center space-x-3 px-4 py-2.5 rounded-lg text-gray-600 hover:bg-gray-100 text-sm mb-1' +
(level > 0 ? ' ' : '');
link.onclick = (e) => {
e.preventDefault();
showView('document', link, doc.path, doc.title);
};
const iconSvg = `<svg class="w-5 h-5 text-gray-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>`;
link.innerHTML = `${iconSvg}<span class="truncate">${doc.title}</span>`;
parentElement.appendChild(link);
}
// Helper function to create a diagram link
function createDiagramLink(diagram, parentElement, level) {
const link = document.createElement('a');
link.href = '#';
link.className = 'nav-item flex items-center space-x-3 px-4 py-2.5 rounded-lg text-gray-600 hover:bg-gray-100 text-sm mb-1' +
(level > 0 ? ' ' : '');
link.onclick = (e) => {
e.preventDefault();
showView('diagram', link, diagram.path, diagram.title, diagram.type);
};
const iconSvg = `<svg class="w-5 h-5 text-gray-400 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4l2 2h4a2 2 0 012 2v12a2 2 0 01-2 2h-4l-2-2H7z"></path>
</svg>`;
link.innerHTML = `${iconSvg}<span class="truncate">${diagram.title}</span>`;
parentElement.appendChild(link);
}
// Load all diagrams from config
async function loadAllDiagrams() {
const dynamicSection = document.getElementById('dynamic-diagrams-section');
try {
const response = await fetch('./assets/diagrams/diagrams-config.json');
if (!response.ok) {
throw new Error(`Failed to load diagrams config: ${response.status}`);
}
const text = await response.text();
allDiagrams = JSON.parse(text);
if (allDiagrams && allDiagrams.length > 0) {
const hierarchy = buildHierarchy(allDiagrams, 'assets/diagrams/');
createAccordionNavigation(hierarchy, dynamicSection, createDiagramLink, 'Diagrams');
}
} catch (error) {
console.error('Error loading diagrams configuration:', error);
const errorDiv = document.createElement('div');
errorDiv.className = 'px-4 py-3 mx-2 mt-4 text-xs text-amber-600 bg-amber-50 rounded-lg border border-amber-200';
errorDiv.innerHTML = `
<div class="font-semibold mb-1">⚠️ Diagrams</div>
<div>Unable to load diagrams-config.json</div>
<div class="mt-1 text-amber-500">${error.message}</div>
`;
dynamicSection.appendChild(errorDiv);
}
}
// Load all documentation from config
async function loadAllDocuments() {
const documentationSection = document.getElementById('documentation-section');
try {
const response = await fetch('./assets/documents/documents-config.json');
if (!response.ok) {
throw new Error(`Failed to load documents config: ${response.status}`);
}
const text = await response.text();
allDocuments = JSON.parse(text);
if (allDocuments && allDocuments.length > 0) {
const hierarchy = buildHierarchy(allDocuments, 'assets/documents/');
createAccordionNavigation(hierarchy, documentationSection, createDocumentLink, 'Documentation');
}
} catch (error) {
console.error('Error loading documents configuration:', error);
const errorDiv = document.createElement('div');
errorDiv.className = 'px-4 py-3 mx-2 mt-4 text-xs text-amber-600 bg-amber-50 rounded-lg border border-amber-200';
errorDiv.innerHTML = `
<div class="font-semibold mb-1">⚠️ Documentation</div>
<div>Unable to load documents-config.json</div>
<div class="mt-1 text-amber-500">${error.message}</div>
`;
documentationSection.appendChild(errorDiv);
}
}
function setActiveNav(activeLink) {
document.querySelectorAll('#sidebar-nav a').forEach(link => {
link.classList.remove('bg-primary-50', 'border', 'border-primary-200', 'text-primary-700');
link.classList.add('text-gray-700');
});
activeLink.classList.remove('text-gray-700');
activeLink.classList.add('bg-primary-50', 'border', 'border-primary-200', 'text-primary-700');
}
async function showView(viewName, navLink, filePath, title, type = 'svg') {
setActiveNav(navLink);
if (panzoomInstance) {
panzoomInstance.destroy();
panzoomInstance = null;
}
diagramContainer.innerHTML = '';
documentContainer.innerHTML = '';
currentScale = 1;
if (viewName === 'home') {
homeView.classList.remove('hidden');
diagramViewer.classList.add('hidden');
documentViewer.classList.add('hidden');
} else if (viewName === 'diagram') {
homeView.classList.add('hidden');
diagramViewer.classList.remove('hidden');
documentViewer.classList.add('hidden');
diagramTitle.textContent = title;
diagramContainer.innerHTML = `
<div class="flex flex-col items-center space-y-3">
<div class="w-12 h-12 border-4 border-primary-200 border-t-primary-600 rounded-full animate-spin"></div>
<p class="text-gray-600 font-medium">Loading diagram...</p>
</div>
`;
try {
if (type === 'svg') {
const response = await fetch(filePath);
if (!response.ok) throw new Error(`Network error: ${response.status}`);
const svgContent = await response.text();
const parser = new DOMParser();
const svgDoc = parser.parseFromString(svgContent, "image/svg+xml");
const svgElement = svgDoc.querySelector('svg');
if (svgElement) {
diagramContainer.innerHTML = '';
diagramContainer.appendChild(svgElement);
panzoomInstance = Panzoom(svgElement, {
canvas: true,
maxScale: 10,
minScale: 0.3,
startScale: 1
});
diagramContainer.addEventListener('wheel', panzoomInstance.zoomWithWheel);
diagramContainer.focus();
} else {
throw new Error('No SVG element found.');
}
} else if (type === 'mermaid') {
const response = await fetch(filePath);
if (!response.ok) throw new Error(`Network error: ${response.status}`);
const mermaidCode = await response.text();
const { svg } = await mermaid.render('mermaidDiagram_' + Date.now(), mermaidCode);
diagramContainer.innerHTML = svg;
const svgElement = diagramContainer.querySelector('svg');
if (svgElement) {
svgElement.style.maxWidth = 'none';
svgElement.style.height = 'auto';
panzoomInstance = Panzoom(svgElement, {
canvas: true,
maxScale: 10,
minScale: 0.3,
startScale: 1
});
diagramContainer.addEventListener('wheel', panzoomInstance.zoomWithWheel);
diagramContainer.focus();
} else {
throw new Error('Failed to render Mermaid diagram.');
}
}
} catch (error) {
diagramContainer.innerHTML = `
<div class="bg-red-50 border border-red-200 rounded-xl p-6 max-w-md">
<div class="flex items-center space-x-3 mb-2">
<svg class="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<h4 class="font-bold text-red-900">Failed to load diagram</h4>
</div>
<p class="text-red-700 text-sm">${error.message}</p>
</div>
`;
}
} else if (viewName === 'document') {
homeView.classList.add('hidden');
diagramViewer.classList.add('hidden');
documentViewer.classList.remove('hidden');
documentTitle.textContent = title;
documentContainer.innerHTML = `
<div class="flex flex-col items-center justify-center space-y-3 py-12">
<div class="w-12 h-12 border-4 border-primary-200 border-t-primary-600 rounded-full animate-spin"></div>
<p class="text-gray-600 font-medium">Loading document...</p>
</div>
`;
try {
const response = await fetch(filePath);
if (!response.ok) {
throw new Error(`Failed to load document: ${response.status}`);
}
const markdownText = await response.text();
const htmlContent = marked.parse(markdownText);
documentContainer.innerHTML = htmlContent;
} catch (error) {
console.error('Error loading document:', error);
documentContainer.innerHTML = `
<div class="bg-red-50 border border-red-200 rounded-xl p-6">
<div class="flex items-center space-x-3 mb-2">
<svg class="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<h4 class="font-bold text-red-900">Failed to load document</h4>
</div>
<p class="text-red-700 text-sm">${error.message}</p>
</div>
`;
}
}
}
zoomInBtn.addEventListener('click', () => {
if (panzoomInstance) {
panzoomInstance.zoomIn();
diagramContainer.focus();
}
});
zoomOutBtn.addEventListener('click', () => {
if (panzoomInstance) {
panzoomInstance.zoomOut();
diagramContainer.focus();
}
});
resetBtn.addEventListener('click', () => {
if (panzoomInstance) {
panzoomInstance.reset();
diagramContainer.focus();
}
});
document.addEventListener('DOMContentLoaded', () => {
loadAllDiagrams();
loadAllDocuments();
showView('home', document.getElementById('nav-home'));
});
</script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More