Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: preparation to NPM publish #1511

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/build-ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ jobs:
run: yarn run lint
- name: Unit test
run: yarn run test
- name: Build UCC library
run: yarn run build:lib
- name: Build UCC UI
run: yarn run build
- name: List deps into dependencies.txt
Expand Down
27 changes: 22 additions & 5 deletions ui/package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
{
"name": "@splunk/ucc_ui_lib",
"version": "0.0.1",
"name": "@splunk/add-on-ucc-framework",
"description": "Splunk Add-on SDK formerly UCC is a build and code generation framework",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formerly?

"repository": {
"type": "git",
"url": "git+https://github.com/splunk/addonfactory-ucc-generator.git",
"directory": "ui"
},
"version": "5.55.0",
"license": "Apache-2.0",
"private": true,
"author": "Splunk Inc.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add this one?

"homepage": "https://splunk.github.io/addonfactory-ucc-generator",
"scripts": {
"build": "cross-env NODE_ENV=production webpack --bail",
"build:lib": "cross-env NODE_ENV=production tsc --project tsconfig.lib.json",
"build:watch": "webpack --watch",
"format": "prettier \"src/**/*.(js|jsx|ts|tsx|css)\" --write",
"format:verify": "prettier \"src/**/*.(js|jsx|ts|tsx|css)\" --list-different",
Expand All @@ -18,7 +26,8 @@
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"test-storybook": "test-storybook",
"test-storybook:update-snapshots": "yarn run test-storybook -u"
"test-storybook:update-snapshots": "yarn run test-storybook -u",
"prepublishOnly": "yarn run build:lib"
},
"dependencies": {
"@splunk/dashboard-action-buttons": "^27.5.1",
Expand Down Expand Up @@ -118,6 +127,10 @@
"webpack-dev-server": "^5.2.0",
"webpack-merge": "^6.0.1"
},
"peerDependencies": {
"react": "^16.14.0",
"typescript": "^5.6.3"
},
"resolutions": {
"@npmcli/git": "^2.1.0",
"@types/react": "^16.14.62",
Expand All @@ -138,5 +151,9 @@
"workerDirectory": [
"src/public"
]
}
},
"types": "./dist/lib/publicApi.d.ts",
"files": [
"dist/lib"
]
}
12 changes: 6 additions & 6 deletions ui/src/components/BaseFormView/BaseFormView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,10 @@ import {
UtilControlWrapper,
ServiceGroup,
OauthConfiguration,
CustomHook,
AnyEntity,
OAuthEntity,
BasicEntity,
ChangeRecord,
CustomHookClass,
EntitiesAllowingModifications,
} from '../../types/components/BaseFormTypes';
import {
Expand All @@ -52,6 +50,7 @@ import {
import { GlobalConfig } from '../../types/globalConfig/globalConfig';
import { PageContextProviderType } from '../../context/PageContext';
import { shouldHideForPlatform } from '../../util/pageContext';
import { CustomHookConstructor, CustomHookInstance } from '../../types/components/CustomHookClass';

function onCustomHookError(params: { methodName: string; error?: CustomHookError }) {
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -110,7 +109,7 @@ class BaseFormView extends PureComponent<BaseFormProps, BaseFormState> {

datadict: Record<string, AcceptableFormValueOrNullish>;

hook?: CustomHook;
hook?: CustomHookInstance;

// eslint-disable-next-line camelcase
state_enabled?: boolean;
Expand Down Expand Up @@ -1083,7 +1082,7 @@ class BaseFormView extends PureComponent<BaseFormProps, BaseFormState> {
if (type === 'external') {
import(/* webpackIgnore: true */ `${getBuildDirPath()}/custom/${module}.js`).then(
(external) => {
const Hook = external.default;
const Hook = external.default as CustomHookConstructor;
this.hook = new Hook(
globalConfig,
this.props.serviceName,
Expand All @@ -1099,13 +1098,14 @@ class BaseFormView extends PureComponent<BaseFormProps, BaseFormState> {
// @ts-expect-error should be exported to other js module and imported here
__non_webpack_require__(
[`app/${this.appName}/js/build/custom/${module}`],
(Hook: CustomHookClass) => {
(Hook: CustomHookConstructor) => {
this.hook = new Hook(
globalConfig,
this.props.serviceName,
this.state,
this.props.mode,
this.util
this.util,
this.props.groupName
);
resolve(Hook);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import Switch from '@splunk/react-ui/Switch';
import { isFalse } from '../../util/considerFalseAndTruthy';

interface CheckBoxComponentProps {
export interface CheckBoxComponentProps {
value: 0 | 1 | boolean;
handleChange: (field: string, value: 0 | 1) => void;
field: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const Base: Story = {
utilCustomFunctions: {
setState: () => {},
setErrorFieldMsg: () => {},
clearAllErrorMsg: () => {},
clearAllErrorMsg: (state) => state,
setErrorMsg: () => {},
},
handleChange: () => {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const renderControlWrapper = (props: Partial<ControlWrapperProps>) => {
utilCustomFunctions: {
setState: () => {},
setErrorFieldMsg: () => {},
clearAllErrorMsg: () => {},
clearAllErrorMsg: (state) => state,
setErrorMsg: () => {},
},
handleChange: () => {},
Expand Down
54 changes: 20 additions & 34 deletions ui/src/components/CustomControl/CustomControl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,12 @@ import { getUnifiedConfigs } from '../../util/util';
import { getBuildDirPath } from '../../util/script';
import { AcceptableFormValueOrNullish } from '../../types/components/shareableTypes';
import { UtilBaseForm } from '../../types/components/BaseFormTypes';
import { GlobalConfig } from '../../types/globalConfig/globalConfig';
import { Mode } from '../../constants/modes';
import { invariant } from '../../util/invariant';
import { CustomControlConstructor } from './CustomControlBase';
import { ControlData } from './CustomControl.types';

interface IData {
value: AcceptableFormValueOrNullish;
mode: Mode;
serviceName: string;
}

interface ICustomCompClass {
new (
config: GlobalConfig,
el: HTMLElement | undefined,
data: IData,
setValue: (field: string, newValue: AcceptableFormValueOrNullish) => void,
util: UtilBaseForm
): {
render: () => void;
validation?: (submittedField: string, submittedValue: string) => void;
};
}

interface ICustomCompProps {
data: IData;
interface Props {
data: ControlData;
field: string;
handleChange: (field: string, newValue: AcceptableFormValueOrNullish) => void;
controlOptions: { src: string; type: string };
Expand All @@ -38,37 +20,40 @@ interface ICustomCompProps {
utilCustomFunctions: UtilBaseForm;
}

interface ICustomCompState {
interface State {
loading: boolean;
}

class CustomControl extends React.Component<ICustomCompProps, ICustomCompState> {
class CustomControl extends React.Component<Props, State> {
static loadCustomControl = (
module: string,
type: string,
appName: string
): Promise<ICustomCompClass> =>
): Promise<CustomControlConstructor> =>
new Promise((resolve) => {
if (type === 'external') {
import(/* webpackIgnore: true */ `${getBuildDirPath()}/custom/${module}.js`).then(
(external) => {
const Control = external.default;
async (external) => {
const Control = external.default as CustomControlConstructor;
resolve(Control);
}
);
} else {
// @ts-expect-error typeof __non_webpack_require__ is not known during bundle
__non_webpack_require__([`app/${appName}/js/build/custom/${module}`], (Control) => {
resolve(Control);
});
__non_webpack_require__(
[`app/${appName}/js/build/custom/${module}`],
(Control: CustomControlConstructor) => {
resolve(Control);
}
);
}
});

shouldRender: boolean;

el?: HTMLElement;

constructor(props: ICustomCompProps) {
constructor(props: Props) {
super(props);
this.state = {
loading: true,
Expand All @@ -85,14 +70,15 @@ class CustomControl extends React.Component<ICustomCompProps, ICustomCompState>
this.props.controlOptions.type,
appName
).then((Control) => {
invariant(this.el !== undefined, 'Element should be defined');
const customControl = new Control(
globalConfig,
this.el,
this.props.data,
this.setValue,
this.props.utilCustomFunctions
);
customControl?.render();
customControl.render();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to not change behaviour, should we validate if that one exists?


if (typeof customControl.validation === 'function') {
this.props.addCustomValidator(this.props.field, customControl.validation);
Expand All @@ -101,7 +87,7 @@ class CustomControl extends React.Component<ICustomCompProps, ICustomCompState>
});
}

shouldComponentUpdate(_nextProps: ICustomCompProps, nextState: ICustomCompState) {
shouldComponentUpdate(_nextProps: Props, nextState: State) {
if (!nextState.loading && this.shouldRender) {
this.shouldRender = false;
return true;
Expand Down
8 changes: 8 additions & 0 deletions ui/src/components/CustomControl/CustomControl.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { AcceptableFormValueOrNullish } from '../../types/components/shareableTypes';
import { Mode } from '../../constants/modes';

export interface ControlData {
value: AcceptableFormValueOrNullish;
mode: Mode;
serviceName: string;
}
43 changes: 43 additions & 0 deletions ui/src/components/CustomControl/CustomControlBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { GlobalConfig } from '../../types/globalConfig/globalConfig';
import { UtilBaseForm } from '../../types/components/BaseFormTypes';
import { AcceptableFormValueOrNullish } from '../../types/components/shareableTypes';
import { ControlData } from './CustomControl.types';

type ValueSetter = (newValue: AcceptableFormValueOrNullish) => void;

export type CustomControlInstance<T extends typeof CustomControlBase = typeof CustomControlBase> =
InstanceType<T>;

export type CustomControlConstructor<
T extends typeof CustomControlBase = typeof CustomControlBase
> = new (...args: ConstructorParameters<T>) => CustomControlInstance<T>;

export abstract class CustomControlBase {
protected globalConfig: GlobalConfig;

protected el: HTMLElement;

protected data: ControlData;

protected setValue: ValueSetter;

protected util: UtilBaseForm;

constructor(
globalConfig: GlobalConfig,
el: HTMLElement,
data: ControlData,
setValue: ValueSetter,
util: UtilBaseForm
) {
this.globalConfig = globalConfig;
this.el = el;
this.data = data;
this.setValue = setValue;
this.util = util;
}

abstract render(): void;

validation?(field: string, value: ControlData['value']): string | undefined;
}
11 changes: 3 additions & 8 deletions ui/src/components/CustomTab/CustomTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,22 @@ import { z } from 'zod';
import { getUnifiedConfigs } from '../../util/util';
import { getBuildDirPath } from '../../util/script';
import { TabSchema } from '../../types/globalConfig/pages';
import { CustomTabConstructor } from './CustomTabBase';

type Tab = z.infer<typeof TabSchema>;

interface CustomTabProps {
tab: Tab;
}

interface ICustomTabClass {
new (tab: Tab, ref: HTMLDivElement): {
render: () => void;
};
}

const CustomTab: React.FC<CustomTabProps> = ({ tab }) => {
const [loading, setLoading] = useState(true);
const divRef = useRef<HTMLDivElement>(null);

const globalConfig = getUnifiedConfigs();
const appName = globalConfig.meta.name;

const loadCustomTab = (): Promise<ICustomTabClass> =>
const loadCustomTab = (): Promise<CustomTabConstructor> =>
new Promise((resolve) => {
if (tab.customTab?.type === 'external') {
import(
Expand All @@ -37,7 +32,7 @@ const CustomTab: React.FC<CustomTabProps> = ({ tab }) => {
// @ts-expect-error should be exported to other js module and imported here
__non_webpack_require__(
[`app/${appName}/js/build/custom/${tab.customTab?.src}`],
(Control: ICustomTabClass) => resolve(Control)
(Control: CustomTabConstructor) => resolve(Control)
);
}
});
Expand Down
19 changes: 19 additions & 0 deletions ui/src/components/CustomTab/CustomTabBase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export type CustomTabInstance<T extends typeof CustomTabBase = typeof CustomTabBase> =
InstanceType<T>;

export type CustomTabConstructor<T extends typeof CustomTabBase = typeof CustomTabBase> = new (
...args: ConstructorParameters<T>
) => CustomTabInstance<T>;

export abstract class CustomTabBase {
protected tab: object;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe lets add a type for this one?


protected el: HTMLElement;

constructor(tab: object, el: HTMLElement) {
this.tab = tab;
this.el = el;
}

abstract render(): void;
}
2 changes: 1 addition & 1 deletion ui/src/components/DeleteModal/DeleteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ModalWrapper = styled(Modal)`
width: 800px;
`;

interface DeleteModalProps {
export interface DeleteModalProps {
page: StandardPages;
handleRequestClose: () => void;
serviceName: string;
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/EntityPage/EntityPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { StandardPages } from '../../types/components/shareableTypes';
import PageContext from '../../context/PageContext';
import { UCCButton } from '../UCCButton/UCCButton';

interface EntityPageProps {
export interface EntityPageProps {
handleRequestClose: () => void;
serviceName: string;
mode: Mode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const TextWrapper = styled(TextArea)`
width: 320px !important;
`;

interface TextAreaComponentProps {
export interface TextAreaComponentProps {
id?: string;
value: string | number;
handleChange: (field: string, value: string) => void;
Expand Down
Loading
Loading