Skip to content

Commit

Permalink
fix(ExternalTasks): don`t destroy service on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
LamaEats committed Sep 9, 2024
1 parent 47f0397 commit 73162b5
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 50 deletions.
19 changes: 14 additions & 5 deletions src/components/CriteriaForm/CriteriaForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ interface CriteriaFormProps {
withModeSwitch?: boolean;
values?: CriteriaFormValues;
validityData: ValidityData;
externalAllowed?: boolean;

setMode: (mode: CriteriaFormMode) => void;
onSubmit: (values: CriteriaFormValues) => void;
Expand Down Expand Up @@ -318,6 +319,7 @@ export const CriteriaForm = ({
onReset,
items,
withModeSwitch,
externalAllowed,
validityData,
validateBindingsFor,
values,
Expand All @@ -343,11 +345,18 @@ export const CriteriaForm = ({

const isEditMode = values != null && !!values.title?.length;

const radios: Array<{ value: CriteriaFormMode; title: string }> = [
{ title: tr('Simple'), value: 'simple' },
{ title: tr('Goal'), value: 'goal' },
{ title: tr('Task'), value: 'task' },
];
const radios = useMemo<Array<{ value: CriteriaFormMode; title: string }>>(() => {
const base: Array<{ value: CriteriaFormMode; title: string }> = [
{ title: tr('Simple'), value: 'simple' },
{ title: tr('Goal'), value: 'goal' },
];

if (externalAllowed) {
base.push({ title: tr('Task'), value: 'task' });
}

return base;
}, [externalAllowed]);

const title = watch('title');
const selected = watch('selected');
Expand Down
3 changes: 2 additions & 1 deletion src/components/GoalActivityFeed/GoalActivityFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type AddCriteriaMode = NonNullable<React.ComponentProps<typeof GoalCriteriaSugge

export const GoalActivityFeed = forwardRef<HTMLDivElement, GoalActivityFeedProps>(
({ goal, shortId, onGoalDeleteConfirm, onInvalidate }, ref) => {
const { user } = usePageContext();
const { user, allowedServices } = usePageContext();
const {
onGoalCommentUpdate,
onGoalDelete,
Expand Down Expand Up @@ -217,6 +217,7 @@ export const GoalActivityFeed = forwardRef<HTMLDivElement, GoalActivityFeedProps
validateGoalCriteriaBindings={validateGoalCriteriaBindings}
validityData={criteriaValidityData}
filter={[goal.id, ...parentGoalIds.map((id) => id.id)]}
externalAllowed={allowedServices?.jira || false}
/>
</GoalFormPopupTrigger>
))}
Expand Down
3 changes: 3 additions & 0 deletions src/components/GoalCriteriaSuggest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface GoalCriteriaSuggestProps {
versa?: boolean;
/** Value allows restrict search results by current user */
restrictedSearch?: boolean;
externalAllowed?: boolean;
withModeSwitch?: React.ComponentProps<typeof CriteriaForm>['withModeSwitch'];
defaultMode?: React.ComponentProps<typeof CriteriaForm>['mode'];
values?: React.ComponentProps<typeof CriteriaForm>['values'];
Expand All @@ -55,6 +56,7 @@ export const GoalCriteriaSuggest: React.FC<GoalCriteriaSuggestProps> = ({
validityData,
onGoalSelect,
restrictedSearch = false,
externalAllowed = false,
}) => {
const [mode, setMode] = useState(defaultMode);
const [query, setQuery] = useState<string | void>('');
Expand Down Expand Up @@ -176,6 +178,7 @@ export const GoalCriteriaSuggest: React.FC<GoalCriteriaSuggestProps> = ({
items={itemsToRender}
validityData={validityData}
validateBindingsFor={validateBindings}
externalAllowed={externalAllowed}
/>
);
};
Expand Down
5 changes: 4 additions & 1 deletion src/components/Page/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const Page: React.FC<PageProps> = ({ user, ssrTime, title = 'Untitled', c
const { setPreview } = useGoalPreview();
const { data: userSettings = user?.settings } = trpc.user.settings.useQuery();
const { data: config } = trpc.appConfig.get.useQuery();
const { data: jiraIsEnable = false } = trpc.external.isEnable.useQuery();

const router = useRouter();

Expand All @@ -80,7 +81,9 @@ export const Page: React.FC<PageProps> = ({ user, ssrTime, title = 'Untitled', c
}, [router, userSettings]);

return (
<pageContext.Provider value={{ user, theme, themeId: mapThemeOnId[theme], ssrTime }}>
<pageContext.Provider
value={{ user, theme, themeId: mapThemeOnId[theme], ssrTime, allowedServices: { jira: jiraIsEnable } }}
>
<Head>
<link rel="icon" href={config?.favicon || '/favicon.png'} />
<title>{title}</title>
Expand Down
14 changes: 11 additions & 3 deletions src/utils/declareSsrProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ import type { TrpcRouter } from '../../trpc/router';
import { transformer } from './transformer';
import { setSSRLocale, TLocale } from './getLang';

type IntegrationServices = 'jira';

export interface SSRProps<P = { [key: string]: string }> {
user: Session['user'];
req: GetServerSidePropsContext['req'];
params: P;
query: Record<string, string | string[] | undefined>;
ssrTime: number;
ssrHelpers: DecoratedProcedureSSGRecord<TrpcRouter>;
allowedServices?: {
[key in IntegrationServices]: boolean;
};
}

export interface ExternalPageProps<P = { [key: string]: string }> extends SSRProps<P> {
Expand Down Expand Up @@ -52,9 +57,12 @@ export function declareSsrProps<T = ExternalPageProps>(
transformer,
});

await ssrHelpers.appConfig.get.fetch();
await ssrHelpers.v2.project.userProjects.fetch({});
await ssrHelpers.filter.getUserFilters.fetch();
await Promise.all([
ssrHelpers.appConfig.get.fetch(),
ssrHelpers.v2.project.userProjects.fetch({}),
ssrHelpers.filter.getUserFilters.fetch(),
ssrHelpers.external.isEnable.fetch(),
]);

const ssrTime = Date.now();

Expand Down
89 changes: 50 additions & 39 deletions src/utils/integration/jira.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,31 +83,46 @@ const isDebugEnabled = process.env.NODE_ENV === 'development' && process.env.DEB

// @ts-ignore
class JiraService extends JiraApi {
private positiveFinishedStatuses: string;

private finishedStatusCategory: JiraIssueStatus['statusCategory'];

constructor(options: JiraApi.JiraApiOptions) {
super(options);

assert(
process.env.JIRA_POSITIVE_STATUS_NAMES,
`Env variable \`JIRA_POSITIVE_STATUS_NAMES\` must be string, but get ${typeof process.env
.JIRA_POSITIVE_STATUS_NAMES}`,
);
assert(
process.env.JIRA_FINISHED_CATEGORY,
`Env variable \`JIRA_FINISHED_CATEGORY\` must be string, but get ${typeof process.env
.JIRA_FINISHED_CATEGORY}`,
);

this.positiveFinishedStatuses = process.env.JIRA_POSITIVE_STATUS_NAMES;
this.finishedStatusCategory = JSON.parse(process.env.JIRA_FINISHED_CATEGORY);

assert(
typeof this.finishedStatusCategory === 'object' && this.finishedStatusCategory != null,
"Env variable 'JIRA_FINISHED_CATEGORY' must be JSON string value",
);
private positiveFinishedStatuses = '';

private finishedStatusCategory?: JiraIssueStatus['statusCategory'];

public isEnable = false;

constructor() {
super({
protocol: 'https',
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
host: process.env.JIRA_URL!,
username: process.env.JIRA_USER,
password: process.env.JIRA_PASSWORD,
apiVersion: process.env.JIRA_API_VERSION,
strictSSL: process.env.NODE_ENV === 'production',
});

try {
// check env variables which contains `JIRA` prefix
Object.keys(process.env)
.filter((k) => k.includes('JIRA'))
.forEach((jiraEnvKey) => {
const val = process.env[jiraEnvKey];

assert(val, `Env variable \`${jiraEnvKey}\` must be string, but get ${typeof val}`);
});

// here suppoed that env variable is available
this.positiveFinishedStatuses = process.env.JIRA_POSITIVE_STATUS_NAMES as string;
this.finishedStatusCategory = JSON.parse(process.env.JIRA_FINISHED_CATEGORY as string);

assert(
typeof this.finishedStatusCategory === 'object' && this.finishedStatusCategory != null,
"Env variable 'JIRA_FINISHED_CATEGORY' must be JSON string value",
);
this.isEnable = true;
} catch (error) {
console.error(error);
this.isEnable = false;
}
}

/** start overriding private instamce methods */
Expand Down Expand Up @@ -144,23 +159,19 @@ class JiraService extends JiraApi {
}

public checkStatusIsFinished(status: JiraIssueStatus) {
return (
(status.statusCategory.key === this.finishedStatusCategory.key ||
status.statusCategory.id === this.finishedStatusCategory.id) &&
this.positiveFinishedStatuses.includes(status.name)
);
if (this.isEnable && this.finishedStatusCategory) {
return (
(status.statusCategory.key === this.finishedStatusCategory.key ||
status.statusCategory.id === this.finishedStatusCategory.id) &&
this.positiveFinishedStatuses.includes(status.name)
);
}

return false;
}
}

export const jiraService = new JiraService({
protocol: 'https',
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
host: process.env.JIRA_URL!,
username: process.env.JIRA_USER,
password: process.env.JIRA_PASSWORD,
apiVersion: process.env.JIRA_API_VERSION,
strictSSL: process.env.NODE_ENV === 'production',
});
export const jiraService = new JiraService();

const re = '(\\w+)-(\\d+)';

Expand Down
3 changes: 3 additions & 0 deletions src/utils/pageContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export interface PageContext {
themeId: number;
ssrTime: number;
user?: Session['user'];
allowedServices?: {
jira: boolean;
};
}

export const pageContext = React.createContext<PageContext>({ theme: 'dark', themeId: 0, ssrTime: 0 });
5 changes: 4 additions & 1 deletion trpc/router/external.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { z } from 'zod';

import { protectedProcedure, router } from '../trpcBackend';
import { JiraIssue, searchIssue } from '../../src/utils/integration/jira';
import { JiraIssue, searchIssue, jiraService } from '../../src/utils/integration/jira';
import { ExternalTask } from '../../generated/kysely/types';
import { ExtractTypeFromGenerated } from '../utils';

Expand Down Expand Up @@ -30,6 +30,9 @@ const jiraIssueToExternalTask = (
};

export const external = router({
isEnable: protectedProcedure.query(async () => {
return Promise.resolve(jiraService.isEnable);
}),
search: protectedProcedure
.input(
z.object({
Expand Down

0 comments on commit 73162b5

Please sign in to comment.