@oneuptime/common 10.2.17 → 10.2.20

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.
Files changed (109) hide show
  1. package/Models/DatabaseModels/Index.ts +4 -0
  2. package/Models/DatabaseModels/ScheduledMaintenanceFeed.ts +2 -0
  3. package/Models/DatabaseModels/ScheduledMaintenanceLabelRule.ts +742 -0
  4. package/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.ts +828 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1778703414082-AddScheduledMaintenanceRules.ts +375 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +463 -0
  8. package/Server/Services/ScheduledMaintenanceLabelRuleService.ts +14 -0
  9. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +545 -0
  10. package/Server/Services/ScheduledMaintenanceOwnerRuleService.ts +14 -0
  11. package/Server/Services/ScheduledMaintenanceService.ts +34 -0
  12. package/Types/Call/CallRequest.ts +29 -5
  13. package/Types/Docs/DocsLanguage.ts +36 -0
  14. package/Types/Permission.ts +96 -0
  15. package/UI/Components/AlertBanner/AlertBanner.tsx +4 -1
  16. package/UI/Components/Alerts/Alert.tsx +15 -4
  17. package/UI/Components/Button/DropdownButton.tsx +4 -2
  18. package/UI/Components/Detail/Detail.tsx +5 -1
  19. package/UI/Components/Detail/FieldLabel.tsx +14 -6
  20. package/UI/Components/Detail/PlaceholderText.tsx +4 -1
  21. package/UI/Components/Dropdown/Dropdown.tsx +13 -4
  22. package/UI/Components/ErrorMessage/ErrorMessage.tsx +9 -2
  23. package/UI/Components/Filters/FilterViewer.tsx +42 -31
  24. package/UI/Components/Filters/FiltersForm.tsx +13 -6
  25. package/UI/Components/Forms/BasicForm.tsx +23 -6
  26. package/UI/Components/Forms/Fields/FieldLabel.tsx +18 -6
  27. package/UI/Components/ModelTable/BaseModelTable.tsx +16 -13
  28. package/UI/Components/MoreMenu/MoreMenuSection.tsx +4 -1
  29. package/UI/Components/Navbar/NavBarItem.tsx +4 -1
  30. package/UI/Components/Navbar/NavBarMenuItem.tsx +7 -2
  31. package/UI/Components/Navbar/NavBarMenuSubItem.tsx +4 -1
  32. package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +4 -1
  33. package/UI/Components/Table/Table.tsx +13 -7
  34. package/UI/Components/Table/TableHeader.tsx +3 -1
  35. package/UI/Components/Tabs/Tab.tsx +5 -1
  36. package/UI/Components/TopAlert/TopAlert.tsx +8 -2
  37. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  38. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  39. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js +2 -0
  40. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceFeed.js.map +1 -1
  41. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js +749 -0
  42. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceLabelRule.js.map +1 -0
  43. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js +834 -0
  44. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceOwnerRule.js.map +1 -0
  45. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778703414082-AddScheduledMaintenanceRules.js +132 -0
  46. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1778703414082-AddScheduledMaintenanceRules.js.map +1 -0
  47. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  48. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  49. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +375 -0
  50. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -0
  51. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleService.js +13 -0
  52. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleService.js.map +1 -0
  53. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +431 -0
  54. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -0
  55. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleService.js +13 -0
  56. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleService.js.map +1 -0
  57. package/build/dist/Server/Services/ScheduledMaintenanceService.js +28 -0
  58. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  59. package/build/dist/Types/Call/CallRequest.js +28 -5
  60. package/build/dist/Types/Call/CallRequest.js.map +1 -1
  61. package/build/dist/Types/Docs/DocsLanguage.js +25 -0
  62. package/build/dist/Types/Docs/DocsLanguage.js.map +1 -0
  63. package/build/dist/Types/Permission.js +84 -0
  64. package/build/dist/Types/Permission.js.map +1 -1
  65. package/build/dist/UI/Components/AlertBanner/AlertBanner.js +5 -1
  66. package/build/dist/UI/Components/AlertBanner/AlertBanner.js.map +1 -1
  67. package/build/dist/UI/Components/Alerts/Alert.js +9 -4
  68. package/build/dist/UI/Components/Alerts/Alert.js.map +1 -1
  69. package/build/dist/UI/Components/Button/DropdownButton.js +6 -2
  70. package/build/dist/UI/Components/Button/DropdownButton.js.map +1 -1
  71. package/build/dist/UI/Components/Detail/Detail.js +4 -1
  72. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  73. package/build/dist/UI/Components/Detail/FieldLabel.js +11 -6
  74. package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
  75. package/build/dist/UI/Components/Detail/PlaceholderText.js +5 -1
  76. package/build/dist/UI/Components/Detail/PlaceholderText.js.map +1 -1
  77. package/build/dist/UI/Components/Dropdown/Dropdown.js +11 -4
  78. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  79. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +8 -2
  80. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  81. package/build/dist/UI/Components/Filters/FilterViewer.js +49 -32
  82. package/build/dist/UI/Components/Filters/FilterViewer.js.map +1 -1
  83. package/build/dist/UI/Components/Filters/FiltersForm.js +9 -3
  84. package/build/dist/UI/Components/Filters/FiltersForm.js.map +1 -1
  85. package/build/dist/UI/Components/Forms/BasicForm.js +16 -6
  86. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  87. package/build/dist/UI/Components/Forms/Fields/FieldLabel.js +13 -6
  88. package/build/dist/UI/Components/Forms/Fields/FieldLabel.js.map +1 -1
  89. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +15 -10
  90. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  91. package/build/dist/UI/Components/MoreMenu/MoreMenuSection.js +5 -1
  92. package/build/dist/UI/Components/MoreMenu/MoreMenuSection.js.map +1 -1
  93. package/build/dist/UI/Components/Navbar/NavBarItem.js +5 -1
  94. package/build/dist/UI/Components/Navbar/NavBarItem.js.map +1 -1
  95. package/build/dist/UI/Components/Navbar/NavBarMenuItem.js +7 -2
  96. package/build/dist/UI/Components/Navbar/NavBarMenuItem.js.map +1 -1
  97. package/build/dist/UI/Components/Navbar/NavBarMenuSubItem.js +5 -1
  98. package/build/dist/UI/Components/Navbar/NavBarMenuSubItem.js.map +1 -1
  99. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +5 -1
  100. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
  101. package/build/dist/UI/Components/Table/Table.js +12 -7
  102. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  103. package/build/dist/UI/Components/Table/TableHeader.js +4 -2
  104. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  105. package/build/dist/UI/Components/Tabs/Tab.js +5 -1
  106. package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
  107. package/build/dist/UI/Components/TopAlert/TopAlert.js +7 -2
  108. package/build/dist/UI/Components/TopAlert/TopAlert.js.map +1 -1
  109. package/package.json +1 -1
@@ -367,6 +367,18 @@ enum Permission {
367
367
  EditScheduledMaintenanceTemplateOwnerTeam = "EditScheduledMaintenanceTemplateOwnerTeam",
368
368
  ReadScheduledMaintenanceTemplateOwnerTeam = "ReadScheduledMaintenanceTemplateOwnerTeam",
369
369
 
370
+ // Scheduled Maintenance Owner Rule Permissions
371
+ CreateScheduledMaintenanceOwnerRule = "CreateScheduledMaintenanceOwnerRule",
372
+ DeleteScheduledMaintenanceOwnerRule = "DeleteScheduledMaintenanceOwnerRule",
373
+ EditScheduledMaintenanceOwnerRule = "EditScheduledMaintenanceOwnerRule",
374
+ ReadScheduledMaintenanceOwnerRule = "ReadScheduledMaintenanceOwnerRule",
375
+
376
+ // Scheduled Maintenance Label Rule Permissions
377
+ CreateScheduledMaintenanceLabelRule = "CreateScheduledMaintenanceLabelRule",
378
+ DeleteScheduledMaintenanceLabelRule = "DeleteScheduledMaintenanceLabelRule",
379
+ EditScheduledMaintenanceLabelRule = "EditScheduledMaintenanceLabelRule",
380
+ ReadScheduledMaintenanceLabelRule = "ReadScheduledMaintenanceLabelRule",
381
+
370
382
  CreateStatusPageOwnerTeam = "CreateStatusPageOwnerTeam",
371
383
  DeleteStatusPageOwnerTeam = "DeleteStatusPageOwnerTeam",
372
384
  EditStatusPageOwnerTeam = "EditStatusPageOwnerTeam",
@@ -7844,6 +7856,90 @@ export class PermissionHelper {
7844
7856
  group: PermissionGroup.ScheduledMaintenance,
7845
7857
  },
7846
7858
 
7859
+ // Scheduled Maintenance Owner Rule Permissions
7860
+ {
7861
+ permission: Permission.CreateScheduledMaintenanceOwnerRule,
7862
+ title: "Create Scheduled Maintenance Owner Rule",
7863
+ description:
7864
+ "This permission can create Scheduled Maintenance Owner Rules in this project.",
7865
+ isAssignableToTenant: true,
7866
+ isAccessControlPermission: false,
7867
+ isRolePermission: false,
7868
+ group: PermissionGroup.ScheduledMaintenance,
7869
+ },
7870
+ {
7871
+ permission: Permission.DeleteScheduledMaintenanceOwnerRule,
7872
+ title: "Delete Scheduled Maintenance Owner Rule",
7873
+ description:
7874
+ "This permission can delete Scheduled Maintenance Owner Rules of this project.",
7875
+ isAssignableToTenant: true,
7876
+ isAccessControlPermission: false,
7877
+ isRolePermission: false,
7878
+ group: PermissionGroup.ScheduledMaintenance,
7879
+ },
7880
+ {
7881
+ permission: Permission.EditScheduledMaintenanceOwnerRule,
7882
+ title: "Edit Scheduled Maintenance Owner Rule",
7883
+ description:
7884
+ "This permission can edit Scheduled Maintenance Owner Rules of this project.",
7885
+ isAssignableToTenant: true,
7886
+ isAccessControlPermission: false,
7887
+ isRolePermission: false,
7888
+ group: PermissionGroup.ScheduledMaintenance,
7889
+ },
7890
+ {
7891
+ permission: Permission.ReadScheduledMaintenanceOwnerRule,
7892
+ title: "Read Scheduled Maintenance Owner Rule",
7893
+ description:
7894
+ "This permission can read Scheduled Maintenance Owner Rules of this project.",
7895
+ isAssignableToTenant: true,
7896
+ isAccessControlPermission: false,
7897
+ isRolePermission: false,
7898
+ group: PermissionGroup.ScheduledMaintenance,
7899
+ },
7900
+
7901
+ // Scheduled Maintenance Label Rule Permissions
7902
+ {
7903
+ permission: Permission.CreateScheduledMaintenanceLabelRule,
7904
+ title: "Create Scheduled Maintenance Label Rule",
7905
+ description:
7906
+ "This permission can create Scheduled Maintenance Label Rules in this project.",
7907
+ isAssignableToTenant: true,
7908
+ isAccessControlPermission: false,
7909
+ isRolePermission: false,
7910
+ group: PermissionGroup.ScheduledMaintenance,
7911
+ },
7912
+ {
7913
+ permission: Permission.DeleteScheduledMaintenanceLabelRule,
7914
+ title: "Delete Scheduled Maintenance Label Rule",
7915
+ description:
7916
+ "This permission can delete Scheduled Maintenance Label Rules of this project.",
7917
+ isAssignableToTenant: true,
7918
+ isAccessControlPermission: false,
7919
+ isRolePermission: false,
7920
+ group: PermissionGroup.ScheduledMaintenance,
7921
+ },
7922
+ {
7923
+ permission: Permission.EditScheduledMaintenanceLabelRule,
7924
+ title: "Edit Scheduled Maintenance Label Rule",
7925
+ description:
7926
+ "This permission can edit Scheduled Maintenance Label Rules of this project.",
7927
+ isAssignableToTenant: true,
7928
+ isAccessControlPermission: false,
7929
+ isRolePermission: false,
7930
+ group: PermissionGroup.ScheduledMaintenance,
7931
+ },
7932
+ {
7933
+ permission: Permission.ReadScheduledMaintenanceLabelRule,
7934
+ title: "Read Scheduled Maintenance Label Rule",
7935
+ description:
7936
+ "This permission can read Scheduled Maintenance Label Rules of this project.",
7937
+ isAssignableToTenant: true,
7938
+ isAccessControlPermission: false,
7939
+ isRolePermission: false,
7940
+ group: PermissionGroup.ScheduledMaintenance,
7941
+ },
7942
+
7847
7943
  // Alert Episode Permissions
7848
7944
  {
7849
7945
  permission: Permission.CreateAlertEpisode,
@@ -1,3 +1,4 @@
1
+ import useTranslateValue from "../../Utils/Translation";
1
2
  import React, { FunctionComponent, ReactElement } from "react";
2
3
 
3
4
  export enum AlertBannerType {
@@ -44,6 +45,8 @@ const bannerStyles: Record<
44
45
  const AlertBanner: FunctionComponent<ComponentProps> = (
45
46
  props: ComponentProps,
46
47
  ): ReactElement => {
48
+ const { translateString } = useTranslateValue();
49
+ const translatedTitle: string = translateString(props.title) ?? props.title;
47
50
  const styles: { container: string; dot: string; title: string } =
48
51
  bannerStyles[props.type];
49
52
 
@@ -56,7 +59,7 @@ const AlertBanner: FunctionComponent<ComponentProps> = (
56
59
  <div className="flex items-center gap-3">
57
60
  <span className={`inline-flex h-3 w-3 rounded-full ${styles.dot}`} />
58
61
  <span className={`text-lg font-semibold ${styles.title}`}>
59
- {props.title}
62
+ {translatedTitle}
60
63
  </span>
61
64
  </div>
62
65
  {props.rightElement && <div>{props.rightElement}</div>}
@@ -1,6 +1,7 @@
1
1
  import Icon from "../Icon/Icon";
2
2
  import Color from "../../../Types/Color";
3
3
  import IconProp from "../../../Types/Icon/IconProp";
4
+ import useTranslateValue from "../../Utils/Translation";
4
5
  import React, { FunctionComponent, ReactElement } from "react";
5
6
 
6
7
  export enum AlertType {
@@ -35,6 +36,16 @@ export interface ComponentProps {
35
36
  const Alert: FunctionComponent<ComponentProps> = (
36
37
  props: ComponentProps,
37
38
  ): ReactElement => {
39
+ const { translateString, translateValue } = useTranslateValue();
40
+ const translatedStrongTitle: string | undefined = translateString(
41
+ props.strongTitle,
42
+ );
43
+ const translatedTitle: string | ReactElement | undefined = translateValue(
44
+ props.title,
45
+ );
46
+ const translatedTextOnRight: string | undefined = translateString(
47
+ props.textOnRight,
48
+ );
38
49
  const type: AlertType = props.type || AlertType.INFO;
39
50
 
40
51
  const typeClassNames: {
@@ -122,12 +133,12 @@ const Alert: FunctionComponent<ComponentProps> = (
122
133
  >
123
134
  <div>
124
135
  <span className="font-medium">
125
- {props.strongTitle}{" "}
126
- {props.title && props.strongTitle ? "- " : ""}
136
+ {translatedStrongTitle}{" "}
137
+ {translatedTitle && translatedStrongTitle ? "- " : ""}
127
138
  </span>
128
- {props.title}
139
+ {translatedTitle}
129
140
  </div>
130
- {props.textOnRight && <div>{props.textOnRight}</div>}
141
+ {translatedTextOnRight && <div>{translatedTextOnRight}</div>}
131
142
  </div>
132
143
  {props.onClose && (
133
144
  <p className="alert-close mt-3 text-sm md:mt-0 md:ml-6">
@@ -1,3 +1,4 @@
1
+ import useTranslateValue from "../../Utils/Translation";
1
2
  import React, { ReactElement, useState } from "react";
2
3
 
3
4
  interface DropdownOption {
@@ -22,6 +23,7 @@ const DropdownButton: React.FC<DropdownButtonProps> = ({
22
23
  dropdownOptions,
23
24
  onButtonClick,
24
25
  }: ComponentProps): ReactElement => {
26
+ const { translateString } = useTranslateValue();
25
27
  const [isOpen, setIsOpen] = useState(false);
26
28
 
27
29
  const toggleDropdown: VoidFunction = () => {
@@ -35,7 +37,7 @@ const DropdownButton: React.FC<DropdownButtonProps> = ({
35
37
  className="relative inline-flex items-center rounded-l-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
36
38
  onClick={onButtonClick}
37
39
  >
38
- {title}
40
+ {translateString(title) ?? title}
39
41
  </button>
40
42
  <div className="relative -ml-px block">
41
43
  <button
@@ -78,7 +80,7 @@ const DropdownButton: React.FC<DropdownButtonProps> = ({
78
80
  role="menuitem"
79
81
  onClick={option.onClick}
80
82
  >
81
- {option.label}
83
+ {translateString(option.label) ?? option.label}
82
84
  </a>
83
85
  );
84
86
  })}
@@ -1,5 +1,6 @@
1
1
  import AlignItem from "../../Types/AlignItem";
2
2
  import { Logger } from "../../Utils/Logger";
3
+ import useTranslateValue from "../../Utils/Translation";
3
4
  import CodeBlock from "../CodeBlock/CodeBlock";
4
5
  import ColorViewer from "../ColorViewer/ColorViewer";
5
6
  import CopyableButton from "../CopyableButton/CopyableButton";
@@ -42,6 +43,7 @@ type DetailFunction = <T extends GenericObject>(
42
43
  const Detail: DetailFunction = <T extends GenericObject>(
43
44
  props: ComponentProps<T>,
44
45
  ): ReactElement => {
46
+ const { translateString } = useTranslateValue();
45
47
  // Track mobile view for responsive behavior
46
48
  const [isMobile, setIsMobile] = useState<boolean>(false);
47
49
 
@@ -83,7 +85,9 @@ const Detail: DetailFunction = <T extends GenericObject>(
83
85
  ): ReactElement => {
84
86
  if (!options) {
85
87
  return (
86
- <span className="text-gray-400 italic text-sm">No options found</span>
88
+ <span className="text-gray-400 italic text-sm">
89
+ {translateString("No options found") ?? "No options found"}
90
+ </span>
87
91
  );
88
92
  }
89
93
 
@@ -1,5 +1,6 @@
1
1
  import Link from "../Link/Link";
2
2
  import { DetailSideLink } from "./Field";
3
+ import useTranslateValue from "../../Utils/Translation";
3
4
  import React, { FunctionComponent, ReactElement } from "react";
4
5
 
5
6
  export enum Size {
@@ -20,26 +21,33 @@ export interface ComponentProps {
20
21
  const FieldLabelElement: FunctionComponent<ComponentProps> = (
21
22
  props: ComponentProps,
22
23
  ): ReactElement => {
24
+ const { translateString, translateValue } = useTranslateValue();
25
+ const translatedTitle: string | undefined = translateString(props.title);
26
+ const translatedDescription: string | ReactElement | undefined =
27
+ translateValue(props.description);
28
+ const translatedSideLinkText: string | undefined = translateString(
29
+ props.sideLink?.text,
30
+ );
23
31
  const isCardStyle: boolean = props.isCardStyle || false;
24
32
 
25
33
  return (
26
34
  <div className="space-y-1">
27
- {props.title && (
35
+ {translatedTitle && (
28
36
  <label
29
37
  className={`${props.size || "text-xs"} font-semibold uppercase tracking-widest ${
30
38
  isCardStyle ? "text-gray-500" : "text-gray-500"
31
39
  } flex items-center gap-2`}
32
40
  >
33
41
  <span className={`${props.alignClassName} flex items-center gap-1.5`}>
34
- {props.title}
42
+ {translatedTitle}
35
43
  <span className="w-1 h-1 rounded-full bg-gray-300"></span>
36
44
  </span>
37
- {props.sideLink && props.sideLink?.text && props.sideLink?.url && (
45
+ {props.sideLink && translatedSideLinkText && props.sideLink?.url && (
38
46
  <Link
39
47
  to={props.sideLink?.url}
40
48
  className="inline-flex items-center gap-1 text-indigo-500 hover:text-indigo-600 transition-all duration-200 font-medium normal-case tracking-normal text-xs hover:underline underline-offset-2"
41
49
  >
42
- {props.sideLink?.text}
50
+ {translatedSideLinkText}
43
51
  <svg
44
52
  className="w-3 h-3"
45
53
  fill="none"
@@ -57,11 +65,11 @@ const FieldLabelElement: FunctionComponent<ComponentProps> = (
57
65
  )}
58
66
  </label>
59
67
  )}
60
- {props.description && (
68
+ {translatedDescription && (
61
69
  <p
62
70
  className={`${props.alignClassName} text-xs text-gray-400 leading-relaxed mt-0.5`}
63
71
  >
64
- {props.description}
72
+ {translatedDescription}
65
73
  </p>
66
74
  )}
67
75
  </div>
@@ -1,3 +1,4 @@
1
+ import useTranslateValue from "../../Utils/Translation";
1
2
  import React, { FunctionComponent, ReactElement } from "react";
2
3
 
3
4
  export interface ComponentProps {
@@ -7,6 +8,8 @@ export interface ComponentProps {
7
8
  const PlaceholderText: FunctionComponent<ComponentProps> = (
8
9
  props: ComponentProps,
9
10
  ): ReactElement => {
11
+ const { translateString } = useTranslateValue();
12
+ const translatedText: string = translateString(props.text) ?? props.text;
10
13
  return (
11
14
  <span className="inline-flex items-center gap-1.5 text-gray-400 italic text-sm select-none px-2 py-0.5 rounded-md bg-gray-50 border border-dashed border-gray-200">
12
15
  <svg
@@ -22,7 +25,7 @@ const PlaceholderText: FunctionComponent<ComponentProps> = (
22
25
  d="M20 12H4"
23
26
  />
24
27
  </svg>
25
- {props.text}
28
+ {translatedText}
26
29
  </span>
27
30
  );
28
31
  };
@@ -1,4 +1,5 @@
1
1
  import ObjectID from "../../../Types/ObjectID";
2
+ import useTranslateValue from "../../Utils/Translation";
2
3
  import React, {
3
4
  FunctionComponent,
4
5
  ReactElement,
@@ -63,6 +64,12 @@ export interface ComponentProps {
63
64
  const Dropdown: FunctionComponent<ComponentProps> = (
64
65
  props: ComponentProps,
65
66
  ): ReactElement => {
67
+ const { translateString } = useTranslateValue();
68
+ const tx: (value: string | undefined) => string | undefined = (
69
+ value: string | undefined,
70
+ ): string | undefined => {
71
+ return translateString(value);
72
+ };
66
73
  const uniqueId: string = useId();
67
74
  const errorId: string = `dropdown-error-${uniqueId}`;
68
75
 
@@ -459,7 +466,7 @@ const Dropdown: FunctionComponent<ComponentProps> = (
459
466
  <div className="flex items-center gap-2">
460
467
  {renderOptionColorIndicator(option.color)}
461
468
  <span className="text-sm font-medium text-gray-900">
462
- {option.label}
469
+ {tx(option.label) ?? option.label}
463
470
  </span>
464
471
  </div>
465
472
  {renderAssociatedLabels(
@@ -476,11 +483,13 @@ const Dropdown: FunctionComponent<ComponentProps> = (
476
483
  <div className="flex items-center gap-2">
477
484
  {renderOptionColorIndicator(option.color)}
478
485
  <span className="text-sm font-medium text-gray-900">
479
- {option.label}
486
+ {tx(option.label) ?? option.label}
480
487
  </span>
481
488
  </div>
482
489
  {option.description ? (
483
- <span className="text-xs text-gray-500">{option.description}</span>
490
+ <span className="text-xs text-gray-500">
491
+ {tx(option.description) ?? option.description}
492
+ </span>
484
493
  ) : null}
485
494
  {renderAssociatedLabels(visibleLabels, meta.context, hiddenLabelCount)}
486
495
  </div>
@@ -707,7 +716,7 @@ const Dropdown: FunctionComponent<ComponentProps> = (
707
716
  menuPosition="fixed"
708
717
  isClearable={true}
709
718
  isSearchable={true}
710
- placeholder={props.placeholder}
719
+ placeholder={tx(props.placeholder) ?? props.placeholder}
711
720
  options={props.options as any}
712
721
  onChange={(option: any | null) => {
713
722
  if (option) {
@@ -1,3 +1,4 @@
1
+ import useTranslateValue from "../../Utils/Translation";
1
2
  import React, { FunctionComponent, ReactElement } from "react";
2
3
 
3
4
  export interface ComponentProps {
@@ -8,9 +9,15 @@ export interface ComponentProps {
8
9
  const ErrorMessage: FunctionComponent<ComponentProps> = (
9
10
  props: ComponentProps,
10
11
  ): ReactElement => {
12
+ const { translateValue, translateString } = useTranslateValue();
13
+ const translatedMessage: string | ReactElement | undefined =
14
+ typeof props.message === "string"
15
+ ? (translateValue(props.message) as string | ReactElement | undefined) ??
16
+ props.message
17
+ : props.message;
11
18
  return (
12
19
  <div className="text-center my-10 text-gray-500 text-sm">
13
- {props.message}
20
+ {translatedMessage}
14
21
  {props.onRefreshClick ? (
15
22
  <div
16
23
  role={"refresh-button"}
@@ -21,7 +28,7 @@ const ErrorMessage: FunctionComponent<ComponentProps> = (
21
28
  }}
22
29
  className="underline cursor-pointer hover:text-gray-700 mt-3"
23
30
  >
24
- Refresh?
31
+ {translateString("Refresh?") ?? "Refresh?"}
25
32
  </div>
26
33
  ) : (
27
34
  <></>
@@ -34,6 +34,7 @@ import OneUptimeDate from "../../../Types/Date";
34
34
  import Dictionary from "../../../Types/Dictionary";
35
35
  import GenericObject from "../../../Types/GenericObject";
36
36
  import IconProp from "../../../Types/Icon/IconProp";
37
+ import useTranslateValue from "../../Utils/Translation";
37
38
  import React, { ReactElement, useEffect, useState } from "react";
38
39
 
39
40
  export interface ComponentProps<T extends GenericObject> {
@@ -61,6 +62,12 @@ type FilterComponentFunction = <T extends GenericObject>(
61
62
  const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
62
63
  props: ComponentProps<T>,
63
64
  ): ReactElement => {
65
+ const { translateString } = useTranslateValue();
66
+ const tx: (value: string | undefined) => string = (
67
+ value: string | undefined,
68
+ ): string => {
69
+ return translateString(value) ?? value ?? "";
70
+ };
64
71
  const [tempFilterDataForModal, setTempFilterDataForModal] = useState<
65
72
  FilterData<T>
66
73
  >({});
@@ -207,9 +214,10 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
207
214
  if (data.filter.type === FieldType.Boolean) {
208
215
  filterText = (
209
216
  <span>
210
- <span className="font-medium">{data.filter.title}</span> is{" "}
217
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
218
+ {tx("is")}{" "}
211
219
  <span className="font-medium">
212
- {data.filterData[data.filter.key] ? "Yes" : "No"}
220
+ {data.filterData[data.filter.key] ? tx("Yes") : tx("No")}
213
221
  </span>
214
222
  </span>
215
223
  );
@@ -238,8 +246,8 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
238
246
  ): ReactElement => {
239
247
  return (
240
248
  <span>
241
- <span className="font-medium">{data.filter.title}</span> {verb}{" "}
242
- <span className="font-medium">{display}</span>
249
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
250
+ {tx(verb)} <span className="font-medium">{display}</span>
243
251
  </span>
244
252
  );
245
253
  };
@@ -247,15 +255,16 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
247
255
  if (value instanceof IsNull) {
248
256
  return (
249
257
  <span>
250
- <span className="font-medium">{data.filter.title}</span> is empty
258
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
259
+ {tx("is empty")}
251
260
  </span>
252
261
  );
253
262
  }
254
263
  if (value instanceof NotNull) {
255
264
  return (
256
265
  <span>
257
- <span className="font-medium">{data.filter.title}</span> is not
258
- empty
266
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
267
+ {tx("is not empty")}
259
268
  </span>
260
269
  );
261
270
  }
@@ -328,8 +337,8 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
328
337
  ): ReactElement => {
329
338
  return (
330
339
  <span>
331
- <span className="font-medium">{data.filter.title}</span> {verb}{" "}
332
- <span className="font-medium">{display}</span>
340
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
341
+ {tx(verb)} <span className="font-medium">{display}</span>
333
342
  </span>
334
343
  );
335
344
  };
@@ -337,15 +346,16 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
337
346
  if (value instanceof IsNull) {
338
347
  return (
339
348
  <span>
340
- <span className="font-medium">{data.filter.title}</span> is empty
349
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
350
+ {tx("is empty")}
341
351
  </span>
342
352
  );
343
353
  }
344
354
  if (value instanceof NotNull) {
345
355
  return (
346
356
  <span>
347
- <span className="font-medium">{data.filter.title}</span> is not
348
- empty
357
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
358
+ {tx("is not empty")}
349
359
  </span>
350
360
  );
351
361
  }
@@ -409,8 +419,8 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
409
419
 
410
420
  return (
411
421
  <span className="inline-flex items-center space-x-1">
412
- <span className="font-medium">{data.filter.title}</span>
413
- <span>{isPlural ? "are" : "is"}</span>
422
+ <span className="font-medium">{tx(data.filter.title)}</span>
423
+ <span>{isPlural ? tx("are") : tx("is")}</span>
414
424
  <span className="font-medium">{formatJson(json)}</span>
415
425
  </span>
416
426
  );
@@ -428,15 +438,16 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
428
438
  if (rawValue instanceof IsNull) {
429
439
  return (
430
440
  <span>
431
- <span className="font-medium">{data.filter.title}</span> is empty
441
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
442
+ {tx("is empty")}
432
443
  </span>
433
444
  );
434
445
  }
435
446
  if (rawValue instanceof NotNull) {
436
447
  return (
437
448
  <span>
438
- <span className="font-medium">{data.filter.title}</span> is not
439
- empty
449
+ <span className="font-medium">{tx(data.filter.title)}</span>{" "}
450
+ {tx("is not empty")}
440
451
  </span>
441
452
  );
442
453
  }
@@ -484,19 +495,18 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
484
495
  const isMoreItems: boolean = items.length > 1;
485
496
  let joiner: string;
486
497
  if (matchMode === "all") {
487
- joiner = " has all of: ";
498
+ joiner = tx("has all of:");
488
499
  } else if (matchMode === "none") {
489
- joiner = " has none of: ";
500
+ joiner = tx("has none of:");
490
501
  } else if (isMoreItems) {
491
- joiner = " is any of: ";
502
+ joiner = tx("is any of:");
492
503
  } else {
493
- joiner = " is ";
504
+ joiner = tx("is");
494
505
  }
495
506
 
496
507
  return (
497
508
  <span>
498
- <span className="font-medium">{data.filter.title}</span>
499
- {joiner}
509
+ <span className="font-medium">{tx(data.filter.title)}</span> {joiner}{" "}
500
510
  <span className="font-medium">{entityNames}</span>
501
511
  </span>
502
512
  );
@@ -525,7 +535,8 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
525
535
  <div className="flex items-center gap-2 text-sm text-gray-700">
526
536
  <Icon icon={IconProp.Filter} size={SizeProp.Smaller} />
527
537
  <span className="font-semibold">
528
- Showing {props.pluralLabel || "results"} that match
538
+ {tx("Showing")} {props.pluralLabel || tx("results")}{" "}
539
+ {tx("that match")}
529
540
  </span>
530
541
  </div>
531
542
  </div>
@@ -549,7 +560,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
549
560
  className="font-medium text-gray-900"
550
561
  icon={IconProp.Filter}
551
562
  onClick={props.onFilterModalOpen}
552
- title="Edit Filters"
563
+ title={tx("Edit Filters")}
553
564
  iconSize={SizeProp.Smaller}
554
565
  buttonStyle={ButtonStyleType.SECONDARY_LINK}
555
566
  />
@@ -562,7 +573,7 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
562
573
  }}
563
574
  className="font-medium text-gray-900"
564
575
  icon={IconProp.Close}
565
- title="Clear Filters"
576
+ title={tx("Clear Filters")}
566
577
  buttonStyle={ButtonStyleType.SECONDARY_LINK}
567
578
  />
568
579
  </div>
@@ -574,11 +585,11 @@ const FilterComponent: FilterComponentFunction = <T extends GenericObject>(
574
585
  <Modal
575
586
  modalWidth={ModalWidth.Large}
576
587
  isLoading={props.isModalLoading}
577
- title={`Filter ${props.pluralLabel || props.singularLabel || "results"}`}
578
- description={`Narrow down ${
579
- props.pluralLabel || "results"
580
- } by one or more criteria below.`}
581
- submitButtonText={`Apply Filters`}
588
+ title={`${tx("Filter")} ${props.pluralLabel || props.singularLabel || tx("results")}`}
589
+ description={`${tx("Narrow down")} ${
590
+ props.pluralLabel || tx("results")
591
+ } ${tx("by one or more criteria below.")}`}
592
+ submitButtonText={tx("Apply Filters")}
582
593
  onClose={() => {
583
594
  props.onFilterModalClose?.();
584
595
  }}
@@ -3,6 +3,7 @@ import ComponentLoader from "../ComponentLoader/ComponentLoader";
3
3
  import ErrorMessage from "../ErrorMessage/ErrorMessage";
4
4
  import FieldType from "../Types/FieldType";
5
5
  import IconProp from "../../../Types/Icon/IconProp";
6
+ import useTranslateValue from "../../Utils/Translation";
6
7
  import BooleanFilter from "./BooleanFilter";
7
8
  import DateFilter from "./DateFilter";
8
9
  import DropdownFilter from "./DropdownFilter";
@@ -53,6 +54,12 @@ type FiltersFormFunction = <T extends GenericObject>(
53
54
  const FiltersForm: FiltersFormFunction = <T extends GenericObject>(
54
55
  props: ComponentProps<T>,
55
56
  ): ReactElement => {
57
+ const { translateString } = useTranslateValue();
58
+ const tx: (value: string | undefined) => string = (
59
+ value: string | undefined,
60
+ ): string => {
61
+ return translateString(value) ?? value ?? "";
62
+ };
56
63
  if (!props.showFilter) {
57
64
  return <></>;
58
65
  }
@@ -127,7 +134,7 @@ const FiltersForm: FiltersFormFunction = <T extends GenericObject>(
127
134
  }`}
128
135
  >
129
136
  <label className="text-sm font-medium text-gray-700 truncate">
130
- {filter.title}
137
+ {tx(filter.title)}
131
138
  </label>
132
139
  </div>
133
140
 
@@ -196,8 +203,8 @@ const FiltersForm: FiltersFormFunction = <T extends GenericObject>(
196
203
  return clearFilter(filter.key as keyof T);
197
204
  }}
198
205
  className="p-1.5 rounded-md text-gray-400 hover:text-gray-700 hover:bg-gray-100 transition-colors"
199
- aria-label={`Clear ${filter.title} filter`}
200
- title={`Clear ${filter.title}`}
206
+ aria-label={`${tx("Clear")} ${tx(filter.title)} ${tx("filter")}`}
207
+ title={`${tx("Clear")} ${tx(filter.title)}`}
201
208
  >
202
209
  <svg
203
210
  xmlns="http://www.w3.org/2000/svg"
@@ -240,9 +247,9 @@ const FiltersForm: FiltersFormFunction = <T extends GenericObject>(
240
247
  buttonSize={ButtonSize.Small}
241
248
  buttonStyle={ButtonStyleType.SECONDARY_LINK}
242
249
  icon={showMoreFilters ? IconProp.ChevronUp : IconProp.ChevronDown}
243
- title={
244
- showMoreFilters ? "Hide Advanced Filters" : "Show Advanced Filters"
245
- }
250
+ title={tx(
251
+ showMoreFilters ? "Hide Advanced Filters" : "Show Advanced Filters",
252
+ )}
246
253
  onClick={() => {
247
254
  setShowMoreFilters((currentValue: boolean) => {
248
255
  const newValue: boolean = !currentValue;