@solidxai/core-ui 0.1.7-beta.6 → 0.1.7-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/auth/helper.d.ts +9 -0
- package/dist/adapters/auth/helper.d.ts.map +1 -0
- package/dist/adapters/auth/helper.js +37 -0
- package/dist/adapters/auth/helper.js.map +1 -0
- package/dist/adapters/auth/helper.ts +45 -0
- package/dist/adapters/auth/signInWithOtp.d.ts.map +1 -1
- package/dist/adapters/auth/signInWithOtp.js +3 -27
- package/dist/adapters/auth/signInWithOtp.js.map +1 -1
- package/dist/adapters/auth/signInWithOtp.ts +3 -23
- package/dist/components/auth/SolidOTPVerify.d.ts +3 -0
- package/dist/components/auth/SolidOTPVerify.d.ts.map +1 -0
- package/dist/components/auth/SolidOTPVerify.js +67 -0
- package/dist/components/auth/SolidOTPVerify.js.map +1 -0
- package/dist/components/auth/SolidOTPVerify.tsx +133 -0
- package/dist/components/common/AuthBanner.js.map +1 -1
- package/dist/components/core/common/LoadDynamicJsxComponent.d.ts +2 -0
- package/dist/components/core/common/LoadDynamicJsxComponent.d.ts.map +1 -0
- package/dist/components/core/common/LoadDynamicJsxComponent.js +50 -0
- package/dist/components/core/common/LoadDynamicJsxComponent.js.map +1 -0
- package/dist/components/core/common/LoadDynamicJsxComponent.tsx +70 -0
- package/dist/components/core/kanban/SolidManyToOneFilterElement.d.ts.map +1 -1
- package/dist/components/core/kanban/SolidManyToOneFilterElement.js.map +1 -1
- package/dist/components/core/kanban/SolidManyToOneFilterElement.tsx +2 -1
- package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.d.ts.map +1 -1
- package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.js +2 -2
- package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.js.map +1 -1
- package/dist/components/core/kanban/kanban-fields/SolidMediaMultipleKanbanField.tsx +10 -21
- package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.d.ts.map +1 -1
- package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.js +2 -2
- package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.js.map +1 -1
- package/dist/components/core/kanban/kanban-fields/SolidMediaSingleKanbanField.tsx +10 -18
- package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.d.ts.map +1 -1
- package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.js +6 -3
- package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.js.map +1 -1
- package/dist/components/core/kanban/kanban-fields/SolidShortTextKanbanField.tsx +24 -30
- package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.js.map +1 -1
- package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx +2 -2
- package/dist/components/core/list/SolidListViewRowButtonContextMenu.d.ts +1 -1
- package/dist/components/core/list/SolidListViewRowButtonContextMenu.d.ts.map +1 -1
- package/dist/components/core/list/SolidListViewRowButtonContextMenu.js +7 -6
- package/dist/components/core/list/SolidListViewRowButtonContextMenu.js.map +1 -1
- package/dist/components/core/list/SolidListViewRowButtonContextMenu.tsx +10 -9
- package/dist/components/core/users/ApiKeysTab/ApiKeysTab.d.ts +7 -0
- package/dist/components/core/users/ApiKeysTab/ApiKeysTab.d.ts.map +1 -0
- package/dist/components/core/users/ApiKeysTab/ApiKeysTab.js +138 -0
- package/dist/components/core/users/ApiKeysTab/ApiKeysTab.js.map +1 -0
- package/dist/components/core/users/ApiKeysTab/ApiKeysTab.tsx +246 -0
- package/dist/components/core/users/ApiKeysTab/GenerateApiKeyModal.d.ts +8 -0
- package/dist/components/core/users/ApiKeysTab/GenerateApiKeyModal.d.ts.map +1 -0
- package/dist/components/core/users/ApiKeysTab/GenerateApiKeyModal.js +156 -0
- package/dist/components/core/users/ApiKeysTab/GenerateApiKeyModal.js.map +1 -0
- package/dist/components/core/users/ApiKeysTab/GenerateApiKeyModal.tsx +184 -0
- package/dist/components/core/users/ApiKeysTab/RevealApiKeyModal.d.ts +9 -0
- package/dist/components/core/users/ApiKeysTab/RevealApiKeyModal.d.ts.map +1 -0
- package/dist/components/core/users/ApiKeysTab/RevealApiKeyModal.js +37 -0
- package/dist/components/core/users/ApiKeysTab/RevealApiKeyModal.js.map +1 -0
- package/dist/components/core/users/ApiKeysTab/RevealApiKeyModal.tsx +111 -0
- package/dist/components/core/users/ApiKeysTab/index.d.ts +4 -0
- package/dist/components/core/users/ApiKeysTab/index.d.ts.map +1 -0
- package/dist/components/core/users/ApiKeysTab/index.js +4 -0
- package/dist/components/core/users/ApiKeysTab/index.js.map +1 -0
- package/dist/components/core/users/ApiKeysTab/index.ts +3 -0
- package/dist/helpers/# no such endpoints exist, need to calle +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.ts +1 -0
- package/dist/nextAuth/authProviders.d.ts +4 -0
- package/dist/nextAuth/authProviders.d.ts.map +1 -0
- package/dist/nextAuth/authProviders.js +198 -0
- package/dist/nextAuth/authProviders.js.map +1 -0
- package/dist/nextAuth/authProviders.tsx +232 -0
- package/dist/nextAuth/handleLogout.d.ts +2 -0
- package/dist/nextAuth/handleLogout.d.ts.map +1 -0
- package/dist/nextAuth/handleLogout.js +36 -0
- package/dist/nextAuth/handleLogout.js.map +1 -0
- package/dist/nextAuth/handleLogout.tsx +39 -0
- package/dist/nextAuth/refreshAccessToken.d.ts +2 -0
- package/dist/nextAuth/refreshAccessToken.d.ts.map +1 -0
- package/dist/nextAuth/refreshAccessToken.js +24 -0
- package/dist/nextAuth/refreshAccessToken.js.map +1 -0
- package/dist/nextAuth/refreshAccessToken.tsx +28 -0
- package/dist/redux/api/apiKeyApi.d.ts +40 -0
- package/dist/redux/api/apiKeyApi.d.ts.map +1 -0
- package/dist/redux/api/apiKeyApi.js +36 -0
- package/dist/redux/api/apiKeyApi.js.map +1 -0
- package/dist/redux/api/apiKeyApi.ts +60 -0
- package/dist/redux/features/settingsSlice.d.ts +20 -0
- package/dist/redux/features/settingsSlice.d.ts.map +1 -0
- package/dist/redux/features/settingsSlice.js +39 -0
- package/dist/redux/features/settingsSlice.js.map +1 -0
- package/dist/redux/features/settingsSlice.ts +60 -0
- package/dist/routes/guards/AuthGuard.d.ts +5 -1
- package/dist/routes/guards/AuthGuard.d.ts.map +1 -1
- package/dist/routes/guards/AuthGuard.js +13 -2
- package/dist/routes/guards/AuthGuard.js.map +1 -1
- package/dist/routes/guards/AuthGuard.tsx +27 -3
- package/package.json +1 -1
- package/dist/components/core/list/SolidDataTablePagination.d.ts +0 -15
- package/dist/components/core/list/SolidDataTablePagination.d.ts.map +0 -1
- package/dist/components/core/list/SolidDataTablePagination.js +0 -22
- package/dist/components/core/list/SolidDataTablePagination.js.map +0 -1
- package/dist/components/core/list/SolidDataTablePagination.tsx +0 -71
- package/dist/components/solid-ui/SolidButton.d.ts +0 -14
- package/dist/components/solid-ui/SolidButton.d.ts.map +0 -1
- package/dist/components/solid-ui/SolidButton.js +0 -36
- package/dist/components/solid-ui/SolidButton.js.map +0 -1
- package/dist/components/solid-ui/SolidButton.tsx +0 -54
- package/dist/components/solid-ui/SolidTabs.d.ts +0 -18
- package/dist/components/solid-ui/SolidTabs.d.ts.map +0 -1
- package/dist/components/solid-ui/SolidTabs.js +0 -22
- package/dist/components/solid-ui/SolidTabs.js.map +0 -1
- package/dist/components/solid-ui/SolidTabs.tsx +0 -73
- package/dist/components/solid-ui/index.d.ts +0 -3
- package/dist/components/solid-ui/index.d.ts.map +0 -1
- package/dist/components/solid-ui/index.js +0 -3
- package/dist/components/solid-ui/index.js.map +0 -1
- package/dist/components/solid-ui/index.ts +0 -2
package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolidRelationManyToOneKanbanField.js","sourceRoot":"","sources":["../../../../../../src/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx"],"names":[],"mappings":";AAOA,IAAM,iCAAiC,GAAG,UAAC,EAAyF;QAAvF,uBAAuB,6BAAA,EAAE,aAAa,mBAAA,EAAE,WAAW,iBAAA,EAAC,IAAI,UAAA;IAEjG,OAAO,CACJ,mBAAK,CACP,CAAC;AAEN,CAAC,CAAC;AAEF,eAAe,iCAAiC,CAAC","sourcesContent":["\nimport { FilterMatchMode } from 'primereact/api';\nimport { Column, ColumnFilterElementTemplateOptions } from \"primereact/column\";\nimport { FormEvent } from \"primereact/ts-helpers\";\nimport { InputTypes, SolidVarInputsFilterElement } from '../../../../../components/core/
|
|
1
|
+
{"version":3,"file":"SolidRelationManyToOneKanbanField.js","sourceRoot":"","sources":["../../../../../../src/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx"],"names":[],"mappings":";AAOA,IAAM,iCAAiC,GAAG,UAAC,EAAyF;QAAvF,uBAAuB,6BAAA,EAAE,aAAa,mBAAA,EAAE,WAAW,iBAAA,EAAC,IAAI,UAAA;IAEjG,OAAO,CACJ,mBAAK,CACP,CAAC;AAEN,CAAC,CAAC;AAEF,eAAe,iCAAiC,CAAC","sourcesContent":["\nimport { FilterMatchMode } from 'primereact/api';\nimport { Column, ColumnFilterElementTemplateOptions } from \"primereact/column\";\nimport { FormEvent } from \"primereact/ts-helpers\";\nimport { InputTypes, SolidVarInputsFilterElement } from '../../../../../components/core/kanban/SolidVarInputsFilterElement';\nimport { SolidKanbanViewFieldsParams } from '../../../../../components/core/kanban/SolidKanbanViewFields';\n\nconst SolidRelationManyToOneKanbanField = ({ solidKanbanViewMetaData, fieldMetadata, fieldLayout,data }: SolidKanbanViewFieldsParams) => {\n \n return (\n <></>\n );\n\n};\n\nexport default SolidRelationManyToOneKanbanField;"]}
|
package/dist/components/core/kanban/kanban-fields/relations/SolidRelationManyToOneKanbanField.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { FilterMatchMode } from 'primereact/api';
|
|
3
3
|
import { Column, ColumnFilterElementTemplateOptions } from "primereact/column";
|
|
4
4
|
import { FormEvent } from "primereact/ts-helpers";
|
|
5
|
-
import { InputTypes, SolidVarInputsFilterElement } from '../../../../../components/core/
|
|
5
|
+
import { InputTypes, SolidVarInputsFilterElement } from '../../../../../components/core/kanban/SolidVarInputsFilterElement';
|
|
6
6
|
import { SolidKanbanViewFieldsParams } from '../../../../../components/core/kanban/SolidKanbanViewFields';
|
|
7
7
|
|
|
8
8
|
const SolidRelationManyToOneKanbanField = ({ solidKanbanViewMetaData, fieldMetadata, fieldLayout,data }: SolidKanbanViewFieldsParams) => {
|
|
@@ -13,4 +13,4 @@ const SolidRelationManyToOneKanbanField = ({ solidKanbanViewMetaData, fieldMetad
|
|
|
13
13
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export default SolidRelationManyToOneKanbanField;
|
|
16
|
+
export default SolidRelationManyToOneKanbanField;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SolidListViewRowButtonContextMenu: ({ button, params,
|
|
1
|
+
export declare const SolidListViewRowButtonContextMenu: ({ button, params, getSelectedSolidViewData, solidListViewMetaData, handleCustomButtonClick }: any) => import("react/jsx-runtime").JSX.Element | null;
|
|
2
2
|
//# sourceMappingURL=SolidListViewRowButtonContextMenu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolidListViewRowButtonContextMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/core/list/SolidListViewRowButtonContextMenu.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SolidListViewRowButtonContextMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/core/list/SolidListViewRowButtonContextMenu.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,iCAAiC,iGAAkG,GAAG,mDAmClJ,CAAC"}
|
|
@@ -9,21 +9,23 @@ var __assign = (this && this.__assign) || function () {
|
|
|
9
9
|
};
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
|
-
import { jsx as _jsx
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
13
|
import { useSession } from "../../../hooks/useSession";
|
|
14
14
|
import { hasAnyRole } from "../../../helpers/rolesHelper";
|
|
15
|
+
import { Button } from "primereact/button";
|
|
15
16
|
export var SolidListViewRowButtonContextMenu = function (_a) {
|
|
16
17
|
var _b, _c, _d, _e, _f, _g, _h;
|
|
17
|
-
var button = _a.button, params = _a.params,
|
|
18
|
+
var button = _a.button, params = _a.params, getSelectedSolidViewData = _a.getSelectedSolidViewData, solidListViewMetaData = _a.solidListViewMetaData, handleCustomButtonClick = _a.handleCustomButtonClick;
|
|
19
|
+
var selectedSolidViewData = getSelectedSolidViewData === null || getSelectedSolidViewData === void 0 ? void 0 : getSelectedSolidViewData();
|
|
18
20
|
var _j = useSession(), session = _j.data, status = _j.status;
|
|
19
21
|
var user = session === null || session === void 0 ? void 0 : session.user;
|
|
20
22
|
var hasRole = !((_b = button === null || button === void 0 ? void 0 : button.attrs) === null || _b === void 0 ? void 0 : _b.roles) || ((_c = button === null || button === void 0 ? void 0 : button.attrs) === null || _c === void 0 ? void 0 : _c.roles.length) === 0 ? true : hasAnyRole(user === null || user === void 0 ? void 0 : user.roles, (_d = button === null || button === void 0 ? void 0 : button.attrs) === null || _d === void 0 ? void 0 : _d.roles);
|
|
21
23
|
if (!hasRole)
|
|
22
24
|
return null;
|
|
23
|
-
return (
|
|
25
|
+
return (_jsx(Button, { type: "button", icon: ((_e = button === null || button === void 0 ? void 0 : button.attrs) === null || _e === void 0 ? void 0 : _e.icon) ? (_f = button === null || button === void 0 ? void 0 : button.attrs) === null || _f === void 0 ? void 0 : _f.icon : "pi pi-pencil", className: "w-full text-left gap-2 ".concat(((_g = button === null || button === void 0 ? void 0 : button.attrs) === null || _g === void 0 ? void 0 : _g.className) ? (_h = button === null || button === void 0 ? void 0 : button.attrs) === null || _h === void 0 ? void 0 : _h.className : ''), label: button.attrs.label, size: "small", onClick: function () {
|
|
24
26
|
var event = {
|
|
25
27
|
params: params,
|
|
26
|
-
rowData:
|
|
28
|
+
rowData: selectedSolidViewData,
|
|
27
29
|
solidListViewMetaData: solidListViewMetaData.data,
|
|
28
30
|
};
|
|
29
31
|
var modifiedButtonAttrs = __assign({}, button.attrs); // Create a copy
|
|
@@ -32,7 +34,6 @@ export var SolidListViewRowButtonContextMenu = function (_a) {
|
|
|
32
34
|
modifiedButtonAttrs.popupWidth = '30vw';
|
|
33
35
|
}
|
|
34
36
|
handleCustomButtonClick(modifiedButtonAttrs, event);
|
|
35
|
-
|
|
36
|
-
}, children: [_jsx("i", { className: "".concat(((_g = button === null || button === void 0 ? void 0 : button.attrs) === null || _g === void 0 ? void 0 : _g.icon) ? (_h = button === null || button === void 0 ? void 0 : button.attrs) === null || _h === void 0 ? void 0 : _h.icon : "pi pi-pencil", " solid-row-action-button-icon") }), _jsx("span", { className: "solid-row-action-button-label", children: button.attrs.label })] }));
|
|
37
|
+
} }));
|
|
37
38
|
};
|
|
38
39
|
//# sourceMappingURL=SolidListViewRowButtonContextMenu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolidListViewRowButtonContextMenu.js","sourceRoot":"","sources":["../../../../src/components/core/list/SolidListViewRowButtonContextMenu.tsx"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"SolidListViewRowButtonContextMenu.js","sourceRoot":"","sources":["../../../../src/components/core/list/SolidListViewRowButtonContextMenu.tsx"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,CAAC,IAAM,iCAAiC,GAAG,UAAC,EAAiG;;QAA/F,MAAM,YAAA,EAAE,MAAM,YAAA,EAAE,wBAAwB,8BAAA,EAAE,qBAAqB,2BAAA,EAAE,uBAAuB,6BAAA;IACxI,IAAM,qBAAqB,GAAG,wBAAwB,aAAxB,wBAAwB,uBAAxB,wBAAwB,EAAI,CAAC;IAErD,IAAA,KAA4B,UAAU,EAAE,EAAhC,OAAO,UAAA,EAAE,MAAM,YAAiB,CAAC;IAC/C,IAAM,IAAI,GAAG,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,CAAC;IAE3B,IAAM,OAAO,GAAG,CAAC,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,KAAK,CAAA,IAAI,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,KAAK,CAAC,MAAM,MAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,KAAK,EAAE,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,KAAK,CAAC,CAAC;IAElI,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,OAAO,CACH,KAAC,MAAM,IACH,IAAI,EAAC,QAAQ,EACb,IAAI,EAAE,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,IAAI,EAAC,CAAC,CAAC,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,IAAI,CAAC,CAAC,CAAC,cAAc,EAChE,SAAS,EAAE,iCAA0B,CAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,SAAS,EAAC,CAAC,CAAC,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,0CAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAE,EAC/F,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,EACzB,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE;YACL,IAAM,KAAK,GAAG;gBACV,MAAM,QAAA;gBACN,OAAO,EAAE,qBAAqB;gBAC9B,qBAAqB,EAAE,qBAAqB,CAAC,IAAI;aACpD,CAAC;YAEF,IAAM,mBAAmB,gBAAQ,MAAM,CAAC,KAAK,CAAE,CAAC,CAAC,gBAAgB;YAEjE,oDAAoD;YACpD,IAAI,mBAAmB,CAAC,MAAM,KAAK,4BAA4B,IAAI,mBAAmB,CAAC,MAAM,KAAK,6BAA6B,EAAE;gBAC7H,mBAAmB,CAAC,UAAU,GAAG,MAAM,CAAC;aAC3C;YAED,uBAAuB,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;QACxD,CAAC,GACH,CACL,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { useSession } from \"../../../hooks/useSession\";\nimport { hasAnyRole } from \"../../../helpers/rolesHelper\";\nimport { Button } from \"primereact/button\";\n\nexport const SolidListViewRowButtonContextMenu = ({ button, params, getSelectedSolidViewData, solidListViewMetaData, handleCustomButtonClick }: any) => {\n const selectedSolidViewData = getSelectedSolidViewData?.();\n\n const { data: session, status } = useSession();\n const user = session?.user;\n\n const hasRole = !button?.attrs?.roles || button?.attrs?.roles.length === 0 ? true : hasAnyRole(user?.roles, button?.attrs?.roles);\n\n if (!hasRole) return null;\n\n return (\n <Button\n type=\"button\"\n icon={button?.attrs?.icon ? button?.attrs?.icon : \"pi pi-pencil\"}\n className={`w-full text-left gap-2 ${button?.attrs?.className ? button?.attrs?.className : ''}`}\n label={button.attrs.label}\n size=\"small\"\n onClick={() => {\n const event = {\n params,\n rowData: selectedSolidViewData,\n solidListViewMetaData: solidListViewMetaData.data,\n };\n\n const modifiedButtonAttrs = { ...button.attrs }; // Create a copy\n\n // Conditionally add popupWidth for specific actions\n if (modifiedButtonAttrs.action === 'GenerateModelCodeRowAction' || modifiedButtonAttrs.action === 'GenerateModuleCodeRowAction') {\n modifiedButtonAttrs.popupWidth = '30vw';\n }\n\n handleCustomButtonClick(modifiedButtonAttrs, event);\n }}\n />\n );\n};\n"]}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useSession } from "../../../hooks/useSession";
|
|
2
2
|
import { hasAnyRole } from "../../../helpers/rolesHelper";
|
|
3
|
+
import { Button } from "primereact/button";
|
|
3
4
|
|
|
4
|
-
export const SolidListViewRowButtonContextMenu = ({ button, params,
|
|
5
|
+
export const SolidListViewRowButtonContextMenu = ({ button, params, getSelectedSolidViewData, solidListViewMetaData, handleCustomButtonClick }: any) => {
|
|
6
|
+
const selectedSolidViewData = getSelectedSolidViewData?.();
|
|
5
7
|
|
|
6
8
|
const { data: session, status } = useSession();
|
|
7
9
|
const user = session?.user;
|
|
@@ -11,13 +13,16 @@ export const SolidListViewRowButtonContextMenu = ({ button, params, rowData, sol
|
|
|
11
13
|
if (!hasRole) return null;
|
|
12
14
|
|
|
13
15
|
return (
|
|
14
|
-
<
|
|
16
|
+
<Button
|
|
15
17
|
type="button"
|
|
16
|
-
|
|
18
|
+
icon={button?.attrs?.icon ? button?.attrs?.icon : "pi pi-pencil"}
|
|
19
|
+
className={`w-full text-left gap-2 ${button?.attrs?.className ? button?.attrs?.className : ''}`}
|
|
20
|
+
label={button.attrs.label}
|
|
21
|
+
size="small"
|
|
17
22
|
onClick={() => {
|
|
18
23
|
const event = {
|
|
19
24
|
params,
|
|
20
|
-
rowData:
|
|
25
|
+
rowData: selectedSolidViewData,
|
|
21
26
|
solidListViewMetaData: solidListViewMetaData.data,
|
|
22
27
|
};
|
|
23
28
|
|
|
@@ -29,11 +34,7 @@ export const SolidListViewRowButtonContextMenu = ({ button, params, rowData, sol
|
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
handleCustomButtonClick(modifiedButtonAttrs, event);
|
|
32
|
-
onActionComplete?.();
|
|
33
37
|
}}
|
|
34
|
-
|
|
35
|
-
<i className={`${button?.attrs?.icon ? button?.attrs?.icon : "pi pi-pencil"} solid-row-action-button-icon`} />
|
|
36
|
-
<span className="solid-row-action-button-label">{button.attrs.label}</span>
|
|
37
|
-
</button>
|
|
38
|
+
/>
|
|
38
39
|
);
|
|
39
40
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiKeysTab.d.ts","sourceRoot":"","sources":["../../../../../src/components/core/users/ApiKeysTab/ApiKeysTab.tsx"],"names":[],"mappings":"AAsJA,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,SAAiB,EAAE,EAAE,eAAe,2CA0FxE"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
12
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
38
|
+
import { useState } from "react";
|
|
39
|
+
import { useDispatch } from "react-redux";
|
|
40
|
+
import { KeyRound, Plus } from "lucide-react";
|
|
41
|
+
import { SolidButton, SolidSpinner, SolidSwitch, SolidTag } from "../../../shad-cn-ui";
|
|
42
|
+
import { showToast } from "../../../../redux/features/toastSlice";
|
|
43
|
+
import { useGetUserApiKeysQuery, useUpdateApiKeyMutation, } from "../../../../redux/api/apiKeyApi";
|
|
44
|
+
import { GenerateApiKeyModal } from "./GenerateApiKeyModal";
|
|
45
|
+
import { RevealApiKeyModal } from "./RevealApiKeyModal";
|
|
46
|
+
function formatDate(iso) {
|
|
47
|
+
if (!iso)
|
|
48
|
+
return "—";
|
|
49
|
+
return new Date(iso).toLocaleDateString(undefined, {
|
|
50
|
+
year: "numeric",
|
|
51
|
+
month: "short",
|
|
52
|
+
day: "numeric",
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function getExpiryStatus(expiresAt) {
|
|
56
|
+
if (!expiresAt)
|
|
57
|
+
return "never";
|
|
58
|
+
var diff = new Date(expiresAt).getTime() - Date.now();
|
|
59
|
+
if (diff < 0)
|
|
60
|
+
return "expired";
|
|
61
|
+
if (diff < 7 * 24 * 60 * 60 * 1000)
|
|
62
|
+
return "expiring-soon";
|
|
63
|
+
return "ok";
|
|
64
|
+
}
|
|
65
|
+
function ApiKeysTable(_a) {
|
|
66
|
+
var keys = _a.keys, onToggleActive = _a.onToggleActive, isTogglingId = _a.isTogglingId;
|
|
67
|
+
if (keys.length === 0) {
|
|
68
|
+
return (_jsxs("div", { className: "flex flex-column align-items-center justify-content-center gap-3 py-6", style: { color: "var(--solid-text-secondary, #888)" }, children: [_jsx(KeyRound, { size: 32, strokeWidth: 1.5 }), _jsxs("div", { className: "text-center", children: [_jsx("p", { className: "m-0", style: { fontSize: 14, fontWeight: 500 }, children: "No API keys" }), _jsx("p", { className: "m-0 mt-1", style: { fontSize: 12 }, children: "Generate a key to enable programmatic access." })] })] }));
|
|
69
|
+
}
|
|
70
|
+
return (_jsx("div", { style: { overflowX: "auto" }, children: _jsxs("table", { style: { width: "100%", borderCollapse: "collapse" }, children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { className: "solid-api-keys-th", children: "Name" }), _jsx("th", { className: "solid-api-keys-th", children: "Key" }), _jsx("th", { className: "solid-api-keys-th", children: "Status" }), _jsx("th", { className: "solid-api-keys-th", children: "Expires" }), _jsx("th", { className: "solid-api-keys-th", children: "Last Used" }), _jsx("th", { className: "solid-api-keys-th", children: "Active" })] }) }), _jsx("tbody", { children: keys.map(function (key) {
|
|
71
|
+
var expiryStatus = getExpiryStatus(key.expiresAt);
|
|
72
|
+
var isExpired = expiryStatus === "expired";
|
|
73
|
+
return (_jsxs("tr", { className: isExpired ? "solid-api-keys-row--expired" : undefined, children: [_jsx("td", { className: "solid-api-keys-td", children: _jsx("span", { style: { fontWeight: 500 }, children: key.name }) }), _jsx("td", { className: "solid-api-keys-td", children: _jsx("code", { style: {
|
|
74
|
+
fontFamily: "monospace",
|
|
75
|
+
fontSize: 13,
|
|
76
|
+
background: "var(--solid-surface-secondary, #f5f5f5)",
|
|
77
|
+
padding: "2px 6px",
|
|
78
|
+
borderRadius: 4,
|
|
79
|
+
}, children: key.maskedKey }) }), _jsx("td", { className: "solid-api-keys-td", children: isExpired ? (_jsx(SolidTag, { tone: "danger", children: "Expired" })) : !key.isActive ? (_jsx(SolidTag, { tone: "warn", children: "Inactive" })) : expiryStatus === "expiring-soon" ? (_jsx(SolidTag, { tone: "warn", children: "Expiring soon" })) : (_jsx(SolidTag, { tone: "success", children: "Active" })) }), _jsx("td", { className: "solid-api-keys-td", style: {
|
|
80
|
+
color: expiryStatus === "expired"
|
|
81
|
+
? "var(--solid-danger-color, #ef4444)"
|
|
82
|
+
: expiryStatus === "expiring-soon"
|
|
83
|
+
? "var(--solid-warn-color, #f59e0b)"
|
|
84
|
+
: undefined,
|
|
85
|
+
}, children: expiryStatus === "never" ? (_jsx("span", { style: { color: "var(--solid-text-secondary, #888)" }, children: "Never" })) : (formatDate(key.expiresAt)) }), _jsx("td", { className: "solid-api-keys-td", style: { color: "var(--solid-text-secondary, #888)" }, children: formatDate(key.lastUsedAt) }), _jsx("td", { className: "solid-api-keys-td", children: isTogglingId === key.id ? (_jsx(SolidSpinner, {})) : (_jsx(SolidSwitch, { checked: key.isActive, disabled: isExpired, onChange: function () { return onToggleActive(key); } })) })] }, key.id));
|
|
86
|
+
}) })] }) }));
|
|
87
|
+
}
|
|
88
|
+
export function ApiKeysTab(_a) {
|
|
89
|
+
var _this = this;
|
|
90
|
+
var _b, _c;
|
|
91
|
+
var userId = _a.userId, _d = _a.canCreate, canCreate = _d === void 0 ? false : _d;
|
|
92
|
+
var dispatch = useDispatch();
|
|
93
|
+
var _e = useGetUserApiKeysQuery(userId), data = _e.data, isLoading = _e.isLoading, isError = _e.isError;
|
|
94
|
+
var updateApiKey = useUpdateApiKeyMutation()[0];
|
|
95
|
+
var _f = useState(null), togglingId = _f[0], setTogglingId = _f[1];
|
|
96
|
+
var _g = useState(false), showGenerate = _g[0], setShowGenerate = _g[1];
|
|
97
|
+
var _h = useState(null), revealKey = _h[0], setRevealKey = _h[1];
|
|
98
|
+
var keys = (_c = (_b = data === null || data === void 0 ? void 0 : data.data) === null || _b === void 0 ? void 0 : _b.apiKeys) !== null && _c !== void 0 ? _c : [];
|
|
99
|
+
var handleToggle = function (key) { return __awaiter(_this, void 0, void 0, function () {
|
|
100
|
+
var err_1;
|
|
101
|
+
var _a;
|
|
102
|
+
return __generator(this, function (_b) {
|
|
103
|
+
switch (_b.label) {
|
|
104
|
+
case 0:
|
|
105
|
+
setTogglingId(key.id);
|
|
106
|
+
_b.label = 1;
|
|
107
|
+
case 1:
|
|
108
|
+
_b.trys.push([1, 3, 4, 5]);
|
|
109
|
+
return [4 /*yield*/, updateApiKey({ id: key.id, isActive: !key.isActive }).unwrap()];
|
|
110
|
+
case 2:
|
|
111
|
+
_b.sent();
|
|
112
|
+
dispatch(showToast({
|
|
113
|
+
severity: "success",
|
|
114
|
+
summary: "Updated",
|
|
115
|
+
detail: "API key \"".concat(key.name, "\" ").concat(!key.isActive ? "activated" : "deactivated", "."),
|
|
116
|
+
}));
|
|
117
|
+
return [3 /*break*/, 5];
|
|
118
|
+
case 3:
|
|
119
|
+
err_1 = _b.sent();
|
|
120
|
+
dispatch(showToast({
|
|
121
|
+
severity: "error",
|
|
122
|
+
summary: "Error",
|
|
123
|
+
detail: ((_a = err_1 === null || err_1 === void 0 ? void 0 : err_1.data) === null || _a === void 0 ? void 0 : _a.message) || "Failed to update API key.",
|
|
124
|
+
}));
|
|
125
|
+
return [3 /*break*/, 5];
|
|
126
|
+
case 4:
|
|
127
|
+
setTogglingId(null);
|
|
128
|
+
return [7 /*endfinally*/];
|
|
129
|
+
case 5: return [2 /*return*/];
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}); };
|
|
133
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "solid-api-keys-tab", children: [_jsxs("div", { className: "flex align-items-center justify-content-between mb-4", children: [_jsxs("div", { children: [_jsx("p", { className: "m-0", style: { fontWeight: 600, fontSize: 14 }, children: "API Keys" }), _jsx("p", { className: "m-0 mt-1", style: { fontSize: 12, color: "var(--solid-text-secondary, #888)" }, children: "Keys grant programmatic access. Store them securely \u2014 they are shown only once." })] }), canCreate && (_jsxs(SolidButton, { size: "small", type: "button", onClick: function () { return setShowGenerate(true); }, children: [_jsx(Plus, { size: 14 }), "Generate Key"] }))] }), isLoading ? (_jsx("div", { className: "flex justify-content-center py-5", children: _jsx(SolidSpinner, {}) })) : isError && keys.length === 0 ? (_jsxs("div", { className: "flex flex-column align-items-center justify-content-center gap-2 py-5", style: { color: "var(--solid-text-secondary, #888)", fontSize: 13 }, children: [_jsx("p", { className: "m-0", children: "Something went wrong while loading API keys." }), _jsx("p", { className: "m-0", children: "Please refresh the page and try again." })] })) : (_jsx(ApiKeysTable, { keys: keys, onToggleActive: handleToggle, isTogglingId: togglingId }))] }), _jsx(GenerateApiKeyModal, { open: showGenerate, onClose: function () { return setShowGenerate(false); }, onCreated: function (apiKey, keyName) {
|
|
134
|
+
setShowGenerate(false);
|
|
135
|
+
setRevealKey({ apiKey: apiKey, keyName: keyName });
|
|
136
|
+
} }), revealKey && (_jsx(RevealApiKeyModal, { open: true, apiKey: revealKey.apiKey, keyName: revealKey.keyName, onClose: function () { return setRevealKey(null); } }))] }));
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=ApiKeysTab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiKeysTab.js","sourceRoot":"","sources":["../../../../../src/components/core/users/ApiKeysTab/ApiKeysTab.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\nimport { useDispatch } from \"react-redux\";\nimport { KeyRound, Plus } from \"lucide-react\";\nimport { SolidButton, SolidSpinner, SolidSwitch, SolidTag } from \"../../../shad-cn-ui\";\nimport { showToast } from \"../../../../redux/features/toastSlice\";\nimport {\n useGetUserApiKeysQuery,\n useUpdateApiKeyMutation,\n type ApiKeyRecord,\n} from \"../../../../redux/api/apiKeyApi\";\nimport { GenerateApiKeyModal } from \"./GenerateApiKeyModal\";\nimport { RevealApiKeyModal } from \"./RevealApiKeyModal\";\n\nfunction formatDate(iso: string | null): string {\n if (!iso) return \"—\";\n return new Date(iso).toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n });\n}\n\nfunction getExpiryStatus(expiresAt: string | null): \"expired\" | \"expiring-soon\" | \"ok\" | \"never\" {\n if (!expiresAt) return \"never\";\n const diff = new Date(expiresAt).getTime() - Date.now();\n if (diff < 0) return \"expired\";\n if (diff < 7 * 24 * 60 * 60 * 1000) return \"expiring-soon\";\n return \"ok\";\n}\n\nfunction ApiKeysTable({\n keys,\n onToggleActive,\n isTogglingId,\n}: {\n keys: ApiKeyRecord[];\n onToggleActive: (key: ApiKeyRecord) => void;\n isTogglingId: string | null;\n}) {\n if (keys.length === 0) {\n return (\n <div\n className=\"flex flex-column align-items-center justify-content-center gap-3 py-6\"\n style={{ color: \"var(--solid-text-secondary, #888)\" }}\n >\n <KeyRound size={32} strokeWidth={1.5} />\n <div className=\"text-center\">\n <p className=\"m-0\" style={{ fontSize: 14, fontWeight: 500 }}>\n No API keys\n </p>\n <p className=\"m-0 mt-1\" style={{ fontSize: 12 }}>\n Generate a key to enable programmatic access.\n </p>\n </div>\n </div>\n );\n }\n\n return (\n <div style={{ overflowX: \"auto\" }}>\n <table style={{ width: \"100%\", borderCollapse: \"collapse\" }}>\n <thead>\n <tr>\n <th className=\"solid-api-keys-th\">Name</th>\n <th className=\"solid-api-keys-th\">Key</th>\n <th className=\"solid-api-keys-th\">Status</th>\n <th className=\"solid-api-keys-th\">Expires</th>\n <th className=\"solid-api-keys-th\">Last Used</th>\n <th className=\"solid-api-keys-th\">Active</th>\n </tr>\n </thead>\n <tbody>\n {keys.map((key) => {\n const expiryStatus = getExpiryStatus(key.expiresAt);\n const isExpired = expiryStatus === \"expired\";\n\n return (\n <tr key={key.id} className={isExpired ? \"solid-api-keys-row--expired\" : undefined}>\n <td className=\"solid-api-keys-td\">\n <span style={{ fontWeight: 500 }}>{key.name}</span>\n </td>\n\n <td className=\"solid-api-keys-td\">\n <code\n style={{\n fontFamily: \"monospace\",\n fontSize: 13,\n background: \"var(--solid-surface-secondary, #f5f5f5)\",\n padding: \"2px 6px\",\n borderRadius: 4,\n }}\n >\n {key.maskedKey}\n </code>\n </td>\n\n <td className=\"solid-api-keys-td\">\n {isExpired ? (\n <SolidTag tone=\"danger\">Expired</SolidTag>\n ) : !key.isActive ? (\n <SolidTag tone=\"warn\">Inactive</SolidTag>\n ) : expiryStatus === \"expiring-soon\" ? (\n <SolidTag tone=\"warn\">Expiring soon</SolidTag>\n ) : (\n <SolidTag tone=\"success\">Active</SolidTag>\n )}\n </td>\n\n <td\n className=\"solid-api-keys-td\"\n style={{\n color:\n expiryStatus === \"expired\"\n ? \"var(--solid-danger-color, #ef4444)\"\n : expiryStatus === \"expiring-soon\"\n ? \"var(--solid-warn-color, #f59e0b)\"\n : undefined,\n }}\n >\n {expiryStatus === \"never\" ? (\n <span style={{ color: \"var(--solid-text-secondary, #888)\" }}>Never</span>\n ) : (\n formatDate(key.expiresAt)\n )}\n </td>\n\n <td className=\"solid-api-keys-td\" style={{ color: \"var(--solid-text-secondary, #888)\" }}>\n {formatDate(key.lastUsedAt)}\n </td>\n\n <td className=\"solid-api-keys-td\">\n {isTogglingId === key.id ? (\n <SolidSpinner />\n ) : (\n <SolidSwitch\n checked={key.isActive}\n disabled={isExpired}\n onChange={() => onToggleActive(key)}\n />\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n\ninterface ApiKeysTabProps {\n userId: string;\n canCreate?: boolean;\n}\n\nexport function ApiKeysTab({ userId, canCreate = false }: ApiKeysTabProps) {\n const dispatch = useDispatch();\n const { data, isLoading, isError } = useGetUserApiKeysQuery(userId);\n const [updateApiKey] = useUpdateApiKeyMutation();\n const [togglingId, setTogglingId] = useState<string | null>(null);\n const [showGenerate, setShowGenerate] = useState(false);\n const [revealKey, setRevealKey] = useState<{ apiKey: string; keyName: string } | null>(null);\n\n const keys: ApiKeyRecord[] = data?.data?.apiKeys ?? [];\n\n const handleToggle = async (key: ApiKeyRecord) => {\n setTogglingId(key.id);\n try {\n await updateApiKey({ id: key.id, isActive: !key.isActive }).unwrap();\n dispatch(\n showToast({\n severity: \"success\",\n summary: \"Updated\",\n detail: `API key \"${key.name}\" ${!key.isActive ? \"activated\" : \"deactivated\"}.`,\n })\n );\n } catch (err: any) {\n dispatch(\n showToast({\n severity: \"error\",\n summary: \"Error\",\n detail: err?.data?.message || \"Failed to update API key.\",\n })\n );\n } finally {\n setTogglingId(null);\n }\n };\n\n return (\n <>\n <div className=\"solid-api-keys-tab\">\n <div className=\"flex align-items-center justify-content-between mb-4\">\n <div>\n <p className=\"m-0\" style={{ fontWeight: 600, fontSize: 14 }}>\n API Keys\n </p>\n <p className=\"m-0 mt-1\" style={{ fontSize: 12, color: \"var(--solid-text-secondary, #888)\" }}>\n Keys grant programmatic access. Store them securely — they are shown only once.\n </p>\n </div>\n {canCreate && (\n <SolidButton size=\"small\" type=\"button\" onClick={() => setShowGenerate(true)}>\n <Plus size={14} />\n Generate Key\n </SolidButton>\n )}\n </div>\n\n {isLoading ? (\n <div className=\"flex justify-content-center py-5\">\n <SolidSpinner />\n </div>\n ) : isError && keys.length === 0 ? (\n <div\n className=\"flex flex-column align-items-center justify-content-center gap-2 py-5\"\n style={{ color: \"var(--solid-text-secondary, #888)\", fontSize: 13 }}\n >\n <p className=\"m-0\">Something went wrong while loading API keys.</p>\n <p className=\"m-0\">Please refresh the page and try again.</p>\n </div>\n ) : (\n <ApiKeysTable keys={keys} onToggleActive={handleToggle} isTogglingId={togglingId} />\n )}\n </div>\n\n <GenerateApiKeyModal\n open={showGenerate}\n onClose={() => setShowGenerate(false)}\n onCreated={(apiKey, keyName) => {\n setShowGenerate(false);\n setRevealKey({ apiKey, keyName });\n }}\n />\n\n {revealKey && (\n <RevealApiKeyModal\n open={true}\n apiKey={revealKey.apiKey}\n keyName={revealKey.keyName}\n onClose={() => setRevealKey(null)}\n />\n )}\n </>\n );\n}\n"]}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { useDispatch } from "react-redux";
|
|
3
|
+
import { KeyRound, Plus } from "lucide-react";
|
|
4
|
+
import { SolidButton, SolidSpinner, SolidSwitch, SolidTag } from "../../../shad-cn-ui";
|
|
5
|
+
import { showToast } from "../../../../redux/features/toastSlice";
|
|
6
|
+
import {
|
|
7
|
+
useGetUserApiKeysQuery,
|
|
8
|
+
useUpdateApiKeyMutation,
|
|
9
|
+
type ApiKeyRecord,
|
|
10
|
+
} from "../../../../redux/api/apiKeyApi";
|
|
11
|
+
import { GenerateApiKeyModal } from "./GenerateApiKeyModal";
|
|
12
|
+
import { RevealApiKeyModal } from "./RevealApiKeyModal";
|
|
13
|
+
|
|
14
|
+
function formatDate(iso: string | null): string {
|
|
15
|
+
if (!iso) return "—";
|
|
16
|
+
return new Date(iso).toLocaleDateString(undefined, {
|
|
17
|
+
year: "numeric",
|
|
18
|
+
month: "short",
|
|
19
|
+
day: "numeric",
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getExpiryStatus(expiresAt: string | null): "expired" | "expiring-soon" | "ok" | "never" {
|
|
24
|
+
if (!expiresAt) return "never";
|
|
25
|
+
const diff = new Date(expiresAt).getTime() - Date.now();
|
|
26
|
+
if (diff < 0) return "expired";
|
|
27
|
+
if (diff < 7 * 24 * 60 * 60 * 1000) return "expiring-soon";
|
|
28
|
+
return "ok";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ApiKeysTable({
|
|
32
|
+
keys,
|
|
33
|
+
onToggleActive,
|
|
34
|
+
isTogglingId,
|
|
35
|
+
}: {
|
|
36
|
+
keys: ApiKeyRecord[];
|
|
37
|
+
onToggleActive: (key: ApiKeyRecord) => void;
|
|
38
|
+
isTogglingId: string | null;
|
|
39
|
+
}) {
|
|
40
|
+
if (keys.length === 0) {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
className="flex flex-column align-items-center justify-content-center gap-3 py-6"
|
|
44
|
+
style={{ color: "var(--solid-text-secondary, #888)" }}
|
|
45
|
+
>
|
|
46
|
+
<KeyRound size={32} strokeWidth={1.5} />
|
|
47
|
+
<div className="text-center">
|
|
48
|
+
<p className="m-0" style={{ fontSize: 14, fontWeight: 500 }}>
|
|
49
|
+
No API keys
|
|
50
|
+
</p>
|
|
51
|
+
<p className="m-0 mt-1" style={{ fontSize: 12 }}>
|
|
52
|
+
Generate a key to enable programmatic access.
|
|
53
|
+
</p>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<div style={{ overflowX: "auto" }}>
|
|
61
|
+
<table style={{ width: "100%", borderCollapse: "collapse" }}>
|
|
62
|
+
<thead>
|
|
63
|
+
<tr>
|
|
64
|
+
<th className="solid-api-keys-th">Name</th>
|
|
65
|
+
<th className="solid-api-keys-th">Key</th>
|
|
66
|
+
<th className="solid-api-keys-th">Status</th>
|
|
67
|
+
<th className="solid-api-keys-th">Expires</th>
|
|
68
|
+
<th className="solid-api-keys-th">Last Used</th>
|
|
69
|
+
<th className="solid-api-keys-th">Active</th>
|
|
70
|
+
</tr>
|
|
71
|
+
</thead>
|
|
72
|
+
<tbody>
|
|
73
|
+
{keys.map((key) => {
|
|
74
|
+
const expiryStatus = getExpiryStatus(key.expiresAt);
|
|
75
|
+
const isExpired = expiryStatus === "expired";
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<tr key={key.id} className={isExpired ? "solid-api-keys-row--expired" : undefined}>
|
|
79
|
+
<td className="solid-api-keys-td">
|
|
80
|
+
<span style={{ fontWeight: 500 }}>{key.name}</span>
|
|
81
|
+
</td>
|
|
82
|
+
|
|
83
|
+
<td className="solid-api-keys-td">
|
|
84
|
+
<code
|
|
85
|
+
style={{
|
|
86
|
+
fontFamily: "monospace",
|
|
87
|
+
fontSize: 13,
|
|
88
|
+
background: "var(--solid-surface-secondary, #f5f5f5)",
|
|
89
|
+
padding: "2px 6px",
|
|
90
|
+
borderRadius: 4,
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
{key.maskedKey}
|
|
94
|
+
</code>
|
|
95
|
+
</td>
|
|
96
|
+
|
|
97
|
+
<td className="solid-api-keys-td">
|
|
98
|
+
{isExpired ? (
|
|
99
|
+
<SolidTag tone="danger">Expired</SolidTag>
|
|
100
|
+
) : !key.isActive ? (
|
|
101
|
+
<SolidTag tone="warn">Inactive</SolidTag>
|
|
102
|
+
) : expiryStatus === "expiring-soon" ? (
|
|
103
|
+
<SolidTag tone="warn">Expiring soon</SolidTag>
|
|
104
|
+
) : (
|
|
105
|
+
<SolidTag tone="success">Active</SolidTag>
|
|
106
|
+
)}
|
|
107
|
+
</td>
|
|
108
|
+
|
|
109
|
+
<td
|
|
110
|
+
className="solid-api-keys-td"
|
|
111
|
+
style={{
|
|
112
|
+
color:
|
|
113
|
+
expiryStatus === "expired"
|
|
114
|
+
? "var(--solid-danger-color, #ef4444)"
|
|
115
|
+
: expiryStatus === "expiring-soon"
|
|
116
|
+
? "var(--solid-warn-color, #f59e0b)"
|
|
117
|
+
: undefined,
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{expiryStatus === "never" ? (
|
|
121
|
+
<span style={{ color: "var(--solid-text-secondary, #888)" }}>Never</span>
|
|
122
|
+
) : (
|
|
123
|
+
formatDate(key.expiresAt)
|
|
124
|
+
)}
|
|
125
|
+
</td>
|
|
126
|
+
|
|
127
|
+
<td className="solid-api-keys-td" style={{ color: "var(--solid-text-secondary, #888)" }}>
|
|
128
|
+
{formatDate(key.lastUsedAt)}
|
|
129
|
+
</td>
|
|
130
|
+
|
|
131
|
+
<td className="solid-api-keys-td">
|
|
132
|
+
{isTogglingId === key.id ? (
|
|
133
|
+
<SolidSpinner />
|
|
134
|
+
) : (
|
|
135
|
+
<SolidSwitch
|
|
136
|
+
checked={key.isActive}
|
|
137
|
+
disabled={isExpired}
|
|
138
|
+
onChange={() => onToggleActive(key)}
|
|
139
|
+
/>
|
|
140
|
+
)}
|
|
141
|
+
</td>
|
|
142
|
+
</tr>
|
|
143
|
+
);
|
|
144
|
+
})}
|
|
145
|
+
</tbody>
|
|
146
|
+
</table>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface ApiKeysTabProps {
|
|
152
|
+
userId: string;
|
|
153
|
+
canCreate?: boolean;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function ApiKeysTab({ userId, canCreate = false }: ApiKeysTabProps) {
|
|
157
|
+
const dispatch = useDispatch();
|
|
158
|
+
const { data, isLoading, isError } = useGetUserApiKeysQuery(userId);
|
|
159
|
+
const [updateApiKey] = useUpdateApiKeyMutation();
|
|
160
|
+
const [togglingId, setTogglingId] = useState<string | null>(null);
|
|
161
|
+
const [showGenerate, setShowGenerate] = useState(false);
|
|
162
|
+
const [revealKey, setRevealKey] = useState<{ apiKey: string; keyName: string } | null>(null);
|
|
163
|
+
|
|
164
|
+
const keys: ApiKeyRecord[] = data?.data?.apiKeys ?? [];
|
|
165
|
+
|
|
166
|
+
const handleToggle = async (key: ApiKeyRecord) => {
|
|
167
|
+
setTogglingId(key.id);
|
|
168
|
+
try {
|
|
169
|
+
await updateApiKey({ id: key.id, isActive: !key.isActive }).unwrap();
|
|
170
|
+
dispatch(
|
|
171
|
+
showToast({
|
|
172
|
+
severity: "success",
|
|
173
|
+
summary: "Updated",
|
|
174
|
+
detail: `API key "${key.name}" ${!key.isActive ? "activated" : "deactivated"}.`,
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
} catch (err: any) {
|
|
178
|
+
dispatch(
|
|
179
|
+
showToast({
|
|
180
|
+
severity: "error",
|
|
181
|
+
summary: "Error",
|
|
182
|
+
detail: err?.data?.message || "Failed to update API key.",
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
} finally {
|
|
186
|
+
setTogglingId(null);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<>
|
|
192
|
+
<div className="solid-api-keys-tab">
|
|
193
|
+
<div className="flex align-items-center justify-content-between mb-4">
|
|
194
|
+
<div>
|
|
195
|
+
<p className="m-0" style={{ fontWeight: 600, fontSize: 14 }}>
|
|
196
|
+
API Keys
|
|
197
|
+
</p>
|
|
198
|
+
<p className="m-0 mt-1" style={{ fontSize: 12, color: "var(--solid-text-secondary, #888)" }}>
|
|
199
|
+
Keys grant programmatic access. Store them securely — they are shown only once.
|
|
200
|
+
</p>
|
|
201
|
+
</div>
|
|
202
|
+
{canCreate && (
|
|
203
|
+
<SolidButton size="small" type="button" onClick={() => setShowGenerate(true)}>
|
|
204
|
+
<Plus size={14} />
|
|
205
|
+
Generate Key
|
|
206
|
+
</SolidButton>
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
{isLoading ? (
|
|
211
|
+
<div className="flex justify-content-center py-5">
|
|
212
|
+
<SolidSpinner />
|
|
213
|
+
</div>
|
|
214
|
+
) : isError && keys.length === 0 ? (
|
|
215
|
+
<div
|
|
216
|
+
className="flex flex-column align-items-center justify-content-center gap-2 py-5"
|
|
217
|
+
style={{ color: "var(--solid-text-secondary, #888)", fontSize: 13 }}
|
|
218
|
+
>
|
|
219
|
+
<p className="m-0">Something went wrong while loading API keys.</p>
|
|
220
|
+
<p className="m-0">Please refresh the page and try again.</p>
|
|
221
|
+
</div>
|
|
222
|
+
) : (
|
|
223
|
+
<ApiKeysTable keys={keys} onToggleActive={handleToggle} isTogglingId={togglingId} />
|
|
224
|
+
)}
|
|
225
|
+
</div>
|
|
226
|
+
|
|
227
|
+
<GenerateApiKeyModal
|
|
228
|
+
open={showGenerate}
|
|
229
|
+
onClose={() => setShowGenerate(false)}
|
|
230
|
+
onCreated={(apiKey, keyName) => {
|
|
231
|
+
setShowGenerate(false);
|
|
232
|
+
setRevealKey({ apiKey, keyName });
|
|
233
|
+
}}
|
|
234
|
+
/>
|
|
235
|
+
|
|
236
|
+
{revealKey && (
|
|
237
|
+
<RevealApiKeyModal
|
|
238
|
+
open={true}
|
|
239
|
+
apiKey={revealKey.apiKey}
|
|
240
|
+
keyName={revealKey.keyName}
|
|
241
|
+
onClose={() => setRevealKey(null)}
|
|
242
|
+
/>
|
|
243
|
+
)}
|
|
244
|
+
</>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface GenerateApiKeyModalProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
onCreated: (rawApiKey: string, keyName: string) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function GenerateApiKeyModal({ open, onClose, onCreated }: GenerateApiKeyModalProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=GenerateApiKeyModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GenerateApiKeyModal.d.ts","sourceRoot":"","sources":["../../../../../src/components/core/users/ApiKeysTab/GenerateApiKeyModal.tsx"],"names":[],"mappings":"AAmDA,UAAU,wBAAwB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACzD;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,wBAAwB,2CA8HzF"}
|