@backstage-community/plugin-announcements 2.3.0 → 2.5.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @backstage-community/plugin-announcements
2
2
 
3
+ ## 2.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a598f92: Migrate Announcements Banner to the Backstage UI using the Alert component.
8
+
9
+ This change also removes the `variant` React prop. If you were using the prop with the `block` or `floating` values, it can be safely removed, as the banner now uses the Backstage UI Alert default style.
10
+
11
+ ### Patch Changes
12
+
13
+ - 693fc2f: Replace Announcements plugin icon from Material UI's RecordVoiceOverIcon to Remix Icon's RiMegaphoneLine. This change is made in the SearchPage component, the search result list item component, the search result type blueprint and use by default for nav blueprint.
14
+
15
+ ## 2.4.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 8b42b6b: Backstage version bump to v1.48.2
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies [8b42b6b]
24
+ - @backstage-community/plugin-announcements-common@0.18.0
25
+ - @backstage-community/plugin-announcements-react@0.22.0
26
+
3
27
  ## 2.3.0
4
28
 
5
29
  ### Minor Changes
package/README.md CHANGED
@@ -96,7 +96,6 @@ app:
96
96
  extensions:
97
97
  - announcements/banner:
98
98
  config:
99
- variant: floating
100
99
  max: 2
101
100
  category: updates
102
101
  active: true
@@ -7,8 +7,7 @@ const announcementsBanner = AppRootElementBlueprint.makeWithOverrides({
7
7
  name: "banner",
8
8
  config: {
9
9
  schema: {
10
- variant: (z) => z.enum(["block", "floating"]).default("floating"),
11
- max: (z) => z.number().optional(),
10
+ max: (z) => z.number().optional().default(1),
12
11
  category: (z) => z.string().optional(),
13
12
  active: (z) => z.boolean().optional(),
14
13
  current: (z) => z.boolean().optional(),
@@ -1 +1 @@
1
- {"version":3,"file":"banner.esm.js","sources":["../../src/alpha/banner.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { compatWrapper } from '@backstage/core-compat-api';\nimport { AppRootElementBlueprint } from '@backstage/frontend-plugin-api';\nimport { NewAnnouncementBanner } from '../components/NewAnnouncementBanner';\n\n/**\n * @alpha\n */\nexport const announcementsBanner = AppRootElementBlueprint.makeWithOverrides({\n name: 'banner',\n config: {\n schema: {\n variant: z => z.enum(['block', 'floating']).default('floating'),\n max: z => z.number().optional(),\n category: z => z.string().optional(),\n active: z => z.boolean().optional(),\n current: z => z.boolean().optional(),\n tags: z => z.array(z.string()).optional(),\n },\n },\n factory: (originalFactory, { config }) => {\n return originalFactory({\n element: compatWrapper(<NewAnnouncementBanner {...config} />),\n });\n },\n});\n"],"names":[],"mappings":";;;;;AAuBa,MAAA,mBAAA,GAAsB,wBAAwB,iBAAkB,CAAA;AAAA,EAC3E,IAAM,EAAA,QAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,OAAA,EAAS,CAAK,CAAA,KAAA,CAAA,CAAE,IAAK,CAAA,CAAC,SAAS,UAAU,CAAC,CAAE,CAAA,OAAA,CAAQ,UAAU,CAAA;AAAA,MAC9D,GAAK,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MAC9B,QAAU,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MACnC,MAAQ,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS,EAAA;AAAA,MAClC,OAAS,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS,EAAA;AAAA,MACnC,IAAA,EAAM,OAAK,CAAE,CAAA,KAAA,CAAM,EAAE,MAAO,EAAC,EAAE,QAAS;AAAA;AAC1C,GACF;AAAA,EACA,OAAS,EAAA,CAAC,eAAiB,EAAA,EAAE,QAAa,KAAA;AACxC,IAAA,OAAO,eAAgB,CAAA;AAAA,MACrB,SAAS,aAAc,iBAAA,GAAA,CAAC,qBAAuB,EAAA,EAAA,GAAG,QAAQ,CAAE;AAAA,KAC7D,CAAA;AAAA;AAEL,CAAC;;;;"}
1
+ {"version":3,"file":"banner.esm.js","sources":["../../src/alpha/banner.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { compatWrapper } from '@backstage/core-compat-api';\nimport { AppRootElementBlueprint } from '@backstage/frontend-plugin-api';\nimport { NewAnnouncementBanner } from '../components/NewAnnouncementBanner';\n\n/**\n * @alpha\n */\nexport const announcementsBanner = AppRootElementBlueprint.makeWithOverrides({\n name: 'banner',\n config: {\n schema: {\n max: z => z.number().optional().default(1),\n category: z => z.string().optional(),\n active: z => z.boolean().optional(),\n current: z => z.boolean().optional(),\n tags: z => z.array(z.string()).optional(),\n },\n },\n factory: (originalFactory, { config }) => {\n return originalFactory({\n element: compatWrapper(<NewAnnouncementBanner {...config} />),\n });\n },\n});\n"],"names":[],"mappings":";;;;;AAuBa,MAAA,mBAAA,GAAsB,wBAAwB,iBAAkB,CAAA;AAAA,EAC3E,IAAM,EAAA,QAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,GAAA,EAAK,OAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA,CAAE,QAAQ,CAAC,CAAA;AAAA,MACzC,QAAU,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MACnC,MAAQ,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS,EAAA;AAAA,MAClC,OAAS,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS,EAAA;AAAA,MACnC,IAAA,EAAM,OAAK,CAAE,CAAA,KAAA,CAAM,EAAE,MAAO,EAAC,EAAE,QAAS;AAAA;AAC1C,GACF;AAAA,EACA,OAAS,EAAA,CAAC,eAAiB,EAAA,EAAE,QAAa,KAAA;AACxC,IAAA,OAAO,eAAgB,CAAA;AAAA,MACrB,SAAS,aAAc,iBAAA,GAAA,CAAC,qBAAuB,EAAA,EAAA,GAAG,QAAQ,CAAE;AAAA,KAC7D,CAAA;AAAA;AAEL,CAAC;;;;"}
@@ -1,13 +1,13 @@
1
1
  import { NavItemBlueprint } from '@backstage/frontend-plugin-api';
2
2
  import { convertLegacyRouteRef } from '@backstage/core-compat-api';
3
3
  import { rootRouteRef } from '../routes.esm.js';
4
- import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';
4
+ import { RiMegaphoneLine } from '@remixicon/react';
5
5
 
6
6
  const announcementsNavItem = NavItemBlueprint.make({
7
7
  params: {
8
8
  title: "Announcements",
9
9
  routeRef: convertLegacyRouteRef(rootRouteRef),
10
- icon: RecordVoiceOverIcon
10
+ icon: RiMegaphoneLine
11
11
  }
12
12
  });
13
13
 
@@ -1 +1 @@
1
- {"version":3,"file":"navItems.esm.js","sources":["../../src/alpha/navItems.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { NavItemBlueprint } from '@backstage/frontend-plugin-api';\nimport { convertLegacyRouteRef } from '@backstage/core-compat-api';\nimport { rootRouteRef } from '../routes';\nimport RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';\n\n/**\n * @alpha\n */\nexport const announcementsNavItem = NavItemBlueprint.make({\n params: {\n title: 'Announcements',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n icon: RecordVoiceOverIcon,\n },\n});\n\nexport default [announcementsNavItem];\n"],"names":[],"mappings":";;;;;AAuBa,MAAA,oBAAA,GAAuB,iBAAiB,IAAK,CAAA;AAAA,EACxD,MAAQ,EAAA;AAAA,IACN,KAAO,EAAA,eAAA;AAAA,IACP,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,IAC5C,IAAM,EAAA;AAAA;AAEV,CAAC;;;;"}
1
+ {"version":3,"file":"navItems.esm.js","sources":["../../src/alpha/navItems.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n IconComponent,\n NavItemBlueprint,\n} from '@backstage/frontend-plugin-api';\nimport { convertLegacyRouteRef } from '@backstage/core-compat-api';\nimport { rootRouteRef } from '../routes';\nimport { RiMegaphoneLine } from '@remixicon/react';\n/**\n * @alpha\n */\nexport const announcementsNavItem = NavItemBlueprint.make({\n params: {\n title: 'Announcements',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n icon: RiMegaphoneLine as IconComponent,\n },\n});\n\nexport default [announcementsNavItem];\n"],"names":[],"mappings":";;;;;AAyBa,MAAA,oBAAA,GAAuB,iBAAiB,IAAK,CAAA;AAAA,EACxD,MAAQ,EAAA;AAAA,IACN,KAAO,EAAA,eAAA;AAAA,IACP,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,IAC5C,IAAM,EAAA;AAAA;AAEV,CAAC;;;;"}
@@ -6,7 +6,6 @@ import { rootRouteRef } from '../routes.esm.js';
6
6
  const announcementsPage = PageBlueprint.makeWithOverrides({
7
7
  config: {
8
8
  schema: {
9
- title: (z) => z.string().optional(),
10
9
  /**
11
10
  * @deprecated Filter by category using URL state (e.g. ?category=...). This option will be removed.
12
11
  */
@@ -1 +1 @@
1
- {"version":3,"file":"pages.esm.js","sources":["../../src/alpha/pages.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport { PageBlueprint } from '@backstage/frontend-plugin-api';\nimport { rootRouteRef } from '../routes';\n\n/**\n * @alpha\n */\nexport const announcementsPage = PageBlueprint.makeWithOverrides({\n config: {\n schema: {\n title: z => z.string().optional(),\n /**\n * @deprecated Filter by category using URL state (e.g. ?category=...). This option will be removed.\n */\n category: z => z.string().optional(),\n hideStartAt: z => z.boolean().optional(),\n markdownRenderer: z => z.enum(['backstage', 'md-editor']).optional(),\n /**\n * @deprecated Inactive announcement are hidden by default. This option will be removed.\n */\n defaultInactive: z => z.boolean().optional(),\n },\n },\n factory: (originalFactory, { config }) =>\n originalFactory({\n path: '/announcements',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n loader: async () =>\n import('../Router').then(m =>\n compatWrapper(\n <m.Router\n title={config.title}\n category={config.category}\n hideStartAt={config.hideStartAt}\n markdownRenderer={config.markdownRenderer}\n defaultInactive={config.defaultInactive}\n />,\n ),\n ),\n }),\n});\n"],"names":[],"mappings":";;;;;AAyBa,MAAA,iBAAA,GAAoB,cAAc,iBAAkB,CAAA;AAAA,EAC/D,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA,MACN,KAAO,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA;AAAA;AAAA;AAAA,MAIhC,QAAU,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MACnC,WAAa,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS,EAAA;AAAA,MACvC,gBAAA,EAAkB,OAAK,CAAE,CAAA,IAAA,CAAK,CAAC,WAAa,EAAA,WAAW,CAAC,CAAA,CAAE,QAAS,EAAA;AAAA;AAAA;AAAA;AAAA,MAInE,eAAiB,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS;AAAA;AAC7C,GACF;AAAA,EACA,SAAS,CAAC,eAAA,EAAiB,EAAE,MAAA,OAC3B,eAAgB,CAAA;AAAA,IACd,IAAM,EAAA,gBAAA;AAAA,IACN,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,IAC5C,MAAQ,EAAA,YACN,OAAO,kBAAW,CAAE,CAAA,IAAA;AAAA,MAAK,CACvB,CAAA,KAAA,aAAA;AAAA,wBACE,GAAA;AAAA,UAAC,CAAE,CAAA,MAAA;AAAA,UAAF;AAAA,YACC,OAAO,MAAO,CAAA,KAAA;AAAA,YACd,UAAU,MAAO,CAAA,QAAA;AAAA,YACjB,aAAa,MAAO,CAAA,WAAA;AAAA,YACpB,kBAAkB,MAAO,CAAA,gBAAA;AAAA,YACzB,iBAAiB,MAAO,CAAA;AAAA;AAAA;AAC1B;AACF;AACF,GACH;AACL,CAAC;;;;"}
1
+ {"version":3,"file":"pages.esm.js","sources":["../../src/alpha/pages.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n compatWrapper,\n convertLegacyRouteRef,\n} from '@backstage/core-compat-api';\nimport { PageBlueprint } from '@backstage/frontend-plugin-api';\nimport { rootRouteRef } from '../routes';\n\n/**\n * @alpha\n */\nexport const announcementsPage = PageBlueprint.makeWithOverrides({\n config: {\n schema: {\n /**\n * @deprecated Filter by category using URL state (e.g. ?category=...). This option will be removed.\n */\n category: z => z.string().optional(),\n hideStartAt: z => z.boolean().optional(),\n markdownRenderer: z => z.enum(['backstage', 'md-editor']).optional(),\n /**\n * @deprecated Inactive announcement are hidden by default. This option will be removed.\n */\n defaultInactive: z => z.boolean().optional(),\n },\n },\n factory: (originalFactory, { config }) =>\n originalFactory({\n path: '/announcements',\n routeRef: convertLegacyRouteRef(rootRouteRef),\n loader: async () =>\n import('../Router').then(m =>\n compatWrapper(\n <m.Router\n title={config.title}\n category={config.category}\n hideStartAt={config.hideStartAt}\n markdownRenderer={config.markdownRenderer}\n defaultInactive={config.defaultInactive}\n />,\n ),\n ),\n }),\n});\n"],"names":[],"mappings":";;;;;AAyBa,MAAA,iBAAA,GAAoB,cAAc,iBAAkB,CAAA;AAAA,EAC/D,MAAQ,EAAA;AAAA,IACN,MAAQ,EAAA;AAAA;AAAA;AAAA;AAAA,MAIN,QAAU,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,QAAS,EAAA;AAAA,MACnC,WAAa,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS,EAAA;AAAA,MACvC,gBAAA,EAAkB,OAAK,CAAE,CAAA,IAAA,CAAK,CAAC,WAAa,EAAA,WAAW,CAAC,CAAA,CAAE,QAAS,EAAA;AAAA;AAAA;AAAA;AAAA,MAInE,eAAiB,EAAA,CAAA,CAAA,KAAK,CAAE,CAAA,OAAA,GAAU,QAAS;AAAA;AAC7C,GACF;AAAA,EACA,SAAS,CAAC,eAAA,EAAiB,EAAE,MAAA,OAC3B,eAAgB,CAAA;AAAA,IACd,IAAM,EAAA,gBAAA;AAAA,IACN,QAAA,EAAU,sBAAsB,YAAY,CAAA;AAAA,IAC5C,MAAQ,EAAA,YACN,OAAO,kBAAW,CAAE,CAAA,IAAA;AAAA,MAAK,CACvB,CAAA,KAAA,aAAA;AAAA,wBACE,GAAA;AAAA,UAAC,CAAE,CAAA,MAAA;AAAA,UAAF;AAAA,YACC,OAAO,MAAO,CAAA,KAAA;AAAA,YACd,UAAU,MAAO,CAAA,QAAA;AAAA,YACjB,aAAa,MAAO,CAAA,WAAA;AAAA,YACpB,kBAAkB,MAAO,CAAA,gBAAA;AAAA,YACzB,iBAAiB,MAAO,CAAA;AAAA;AAAA;AAC1B;AACF;AACF,GACH;AACL,CAAC;;;;"}
@@ -1,6 +1,6 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { SearchResultListItemBlueprint, SearchFilterResultTypeBlueprint } from '@backstage/plugin-search-react/alpha';
3
- import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';
3
+ import { RiMegaphoneLine } from '@remixicon/react';
4
4
 
5
5
  const announcementsSearchResultListItem = SearchResultListItemBlueprint.make({
6
6
  params: {
@@ -8,7 +8,7 @@ const announcementsSearchResultListItem = SearchResultListItemBlueprint.make({
8
8
  (m) => m.AnnouncementSearchResultListItem
9
9
  ),
10
10
  predicate: (result) => result.type === "announcements",
11
- icon: /* @__PURE__ */ jsx(RecordVoiceOverIcon, {})
11
+ icon: /* @__PURE__ */ jsx(RiMegaphoneLine, {})
12
12
  }
13
13
  });
14
14
  const announcementsSearchFilterResultType = SearchFilterResultTypeBlueprint.make({
@@ -16,7 +16,7 @@ const announcementsSearchFilterResultType = SearchFilterResultTypeBlueprint.make
16
16
  params: {
17
17
  name: "Announcements",
18
18
  value: "announcements",
19
- icon: /* @__PURE__ */ jsx(RecordVoiceOverIcon, {})
19
+ icon: /* @__PURE__ */ jsx(RiMegaphoneLine, {})
20
20
  }
21
21
  });
22
22
 
@@ -1 +1 @@
1
- {"version":3,"file":"search.esm.js","sources":["../../src/alpha/search.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n SearchFilterResultTypeBlueprint,\n SearchResultListItemBlueprint,\n} from '@backstage/plugin-search-react/alpha';\nimport RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';\n\nexport const announcementsSearchResultListItem =\n SearchResultListItemBlueprint.make({\n params: {\n component: () =>\n import('../components/AnnouncementSearchResultListItem').then(\n m => m.AnnouncementSearchResultListItem,\n ),\n predicate: result => result.type === 'announcements',\n icon: <RecordVoiceOverIcon />,\n },\n });\n\nexport const announcementsSearchFilterResultType =\n SearchFilterResultTypeBlueprint.make({\n name: 'announcements-results-type',\n params: {\n name: 'Announcements',\n value: 'announcements',\n icon: <RecordVoiceOverIcon />,\n },\n });\n"],"names":[],"mappings":";;;;AAqBa,MAAA,iCAAA,GACX,8BAA8B,IAAK,CAAA;AAAA,EACjC,MAAQ,EAAA;AAAA,IACN,SAAW,EAAA,MACT,OAAO,6DAAgD,CAAE,CAAA,IAAA;AAAA,MACvD,OAAK,CAAE,CAAA;AAAA,KACT;AAAA,IACF,SAAA,EAAW,CAAU,MAAA,KAAA,MAAA,CAAO,IAAS,KAAA,eAAA;AAAA,IACrC,IAAA,sBAAO,mBAAoB,EAAA,EAAA;AAAA;AAE/B,CAAC;AAEU,MAAA,mCAAA,GACX,gCAAgC,IAAK,CAAA;AAAA,EACnC,IAAM,EAAA,4BAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,eAAA;AAAA,IACN,KAAO,EAAA,eAAA;AAAA,IACP,IAAA,sBAAO,mBAAoB,EAAA,EAAA;AAAA;AAE/B,CAAC;;;;"}
1
+ {"version":3,"file":"search.esm.js","sources":["../../src/alpha/search.tsx"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport {\n SearchFilterResultTypeBlueprint,\n SearchResultListItemBlueprint,\n} from '@backstage/plugin-search-react/alpha';\nimport { RiMegaphoneLine } from '@remixicon/react';\n\nexport const announcementsSearchResultListItem =\n SearchResultListItemBlueprint.make({\n params: {\n component: () =>\n import('../components/AnnouncementSearchResultListItem').then(\n m => m.AnnouncementSearchResultListItem,\n ),\n predicate: result => result.type === 'announcements',\n icon: <RiMegaphoneLine />,\n },\n });\n\nexport const announcementsSearchFilterResultType =\n SearchFilterResultTypeBlueprint.make({\n name: 'announcements-results-type',\n params: {\n name: 'Announcements',\n value: 'announcements',\n icon: <RiMegaphoneLine />,\n },\n });\n"],"names":[],"mappings":";;;;AAqBa,MAAA,iCAAA,GACX,8BAA8B,IAAK,CAAA;AAAA,EACjC,MAAQ,EAAA;AAAA,IACN,SAAW,EAAA,MACT,OAAO,6DAAgD,CAAE,CAAA,IAAA;AAAA,MACvD,OAAK,CAAE,CAAA;AAAA,KACT;AAAA,IACF,SAAA,EAAW,CAAU,MAAA,KAAA,MAAA,CAAO,IAAS,KAAA,eAAA;AAAA,IACrC,IAAA,sBAAO,eAAgB,EAAA,EAAA;AAAA;AAE3B,CAAC;AAEU,MAAA,mCAAA,GACX,gCAAgC,IAAK,CAAA;AAAA,EACnC,IAAM,EAAA,4BAAA;AAAA,EACN,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,eAAA;AAAA,IACN,KAAO,EAAA,eAAA;AAAA,IACP,IAAA,sBAAO,eAAgB,EAAA,EAAA;AAAA;AAE3B,CAAC;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  import * as _backstage_plugin_search_react_alpha from '@backstage/plugin-search-react/alpha';
3
- import * as _backstage_catalog_model from '@backstage/catalog-model';
4
3
  import * as _backstage_plugin_catalog_react_alpha from '@backstage/plugin-catalog-react/alpha';
4
+ import * as _backstage_catalog_model from '@backstage/catalog-model';
5
+ import * as _backstage_filter_predicates from '@backstage/filter-predicates';
5
6
  import * as react from 'react';
6
7
  import * as _backstage_frontend_plugin_api from '@backstage/frontend-plugin-api';
7
8
 
@@ -24,15 +25,13 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
24
25
  }>;
25
26
  "app-root-element:announcements/banner": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
26
27
  config: {
27
- variant: "block" | "floating";
28
- max: number | undefined;
28
+ max: number;
29
29
  category: string | undefined;
30
30
  active: boolean | undefined;
31
31
  current: boolean | undefined;
32
32
  tags: string[] | undefined;
33
33
  };
34
34
  configInput: {
35
- variant?: "block" | "floating" | undefined;
36
35
  max?: number | undefined;
37
36
  active?: boolean | undefined;
38
37
  current?: boolean | undefined;
@@ -51,12 +50,12 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
51
50
  kind: "entity-card";
52
51
  name: "announcements";
53
52
  config: {
54
- filter: _backstage_plugin_catalog_react_alpha.EntityPredicate | undefined;
55
- type: "content" | "summary" | "info" | undefined;
53
+ filter: _backstage_filter_predicates.FilterPredicate | undefined;
54
+ type: "content" | "info" | undefined;
56
55
  };
57
56
  configInput: {
58
- filter?: _backstage_plugin_catalog_react_alpha.EntityPredicate | undefined;
59
- type?: "content" | "summary" | "info" | undefined;
57
+ filter?: _backstage_filter_predicates.FilterPredicate | undefined;
58
+ type?: "content" | "info" | undefined;
60
59
  };
61
60
  output: _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<(entity: _backstage_catalog_model.Entity) => boolean, "catalog.entity-filter-function", {
62
61
  optional: true;
@@ -68,7 +67,7 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
68
67
  inputs: {};
69
68
  params: {
70
69
  loader: () => Promise<JSX.Element>;
71
- filter?: _backstage_plugin_catalog_react_alpha.EntityPredicate | ((entity: _backstage_catalog_model.Entity) => boolean) | undefined;
70
+ filter?: _backstage_filter_predicates.FilterPredicate | ((entity: _backstage_catalog_model.Entity) => boolean) | undefined;
72
71
  type?: _backstage_plugin_catalog_react_alpha.EntityCardType | undefined;
73
72
  };
74
73
  }>;
@@ -91,32 +90,51 @@ declare const _default: _backstage_frontend_plugin_api.OverridableFrontendPlugin
91
90
  }>;
92
91
  "page:announcements": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
93
92
  config: {
94
- title: string | undefined;
95
93
  category: string | undefined;
96
94
  hideStartAt: boolean | undefined;
97
95
  markdownRenderer: "backstage" | "md-editor" | undefined;
98
96
  defaultInactive: boolean | undefined;
99
97
  path: string | undefined;
98
+ title: string | undefined;
100
99
  };
101
100
  configInput: {
102
- title?: string | undefined;
103
101
  category?: string | undefined;
104
102
  defaultInactive?: boolean | undefined;
105
103
  hideStartAt?: boolean | undefined;
106
104
  markdownRenderer?: "backstage" | "md-editor" | undefined;
105
+ title?: string | undefined;
107
106
  path?: string | undefined;
108
107
  };
109
108
  output: _backstage_frontend_plugin_api.ExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
110
109
  optional: true;
110
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<string, "core.title", {
111
+ optional: true;
112
+ }> | _backstage_frontend_plugin_api.ExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
113
+ optional: true;
111
114
  }>;
112
- inputs: {};
115
+ inputs: {
116
+ pages: _backstage_frontend_plugin_api.ExtensionInput<_backstage_frontend_plugin_api.ConfigurableExtensionDataRef<react.JSX.Element, "core.reactElement", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.routing.path", {}> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams>, "core.routing.ref", {
117
+ optional: true;
118
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<string, "core.title", {
119
+ optional: true;
120
+ }> | _backstage_frontend_plugin_api.ConfigurableExtensionDataRef<_backstage_frontend_plugin_api.IconElement, "core.icon", {
121
+ optional: true;
122
+ }>, {
123
+ singleton: false;
124
+ optional: false;
125
+ internal: false;
126
+ }>;
127
+ };
113
128
  kind: "page";
114
129
  name: undefined;
115
130
  params: {
116
131
  defaultPath?: [Error: "Use the 'path' param instead"] | undefined;
117
132
  path: string;
118
- loader: () => Promise<JSX.Element>;
133
+ title?: string | undefined;
134
+ icon?: _backstage_frontend_plugin_api.IconElement | undefined;
135
+ loader?: (() => Promise<react.JSX.Element>) | undefined;
119
136
  routeRef?: _backstage_frontend_plugin_api.RouteRef<_backstage_frontend_plugin_api.AnyRouteRefParams> | undefined;
137
+ noHeader?: boolean | undefined;
120
138
  };
121
139
  }>;
122
140
  "search-filter-result-type:announcements/announcements-results-type": _backstage_frontend_plugin_api.OverridableExtensionDefinition<{
@@ -4,7 +4,7 @@ import { Link } from '@backstage/core-components';
4
4
  import { HighlightedSearchResultText } from '@backstage/plugin-search-react';
5
5
  import { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
6
6
  import { makeStyles, Typography, ListItem, ListItemIcon, ListItemText } from '@material-ui/core';
7
- import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';
7
+ import { RiMegaphoneLine } from '@remixicon/react';
8
8
 
9
9
  const useStyles = makeStyles({
10
10
  createdAt: {
@@ -52,7 +52,7 @@ const AnnouncementSearchResultListItem = ({
52
52
  ) : result.text })
53
53
  ] });
54
54
  return /* @__PURE__ */ jsxs(ListItem, { alignItems: "center", children: [
55
- /* @__PURE__ */ jsx(ListItemIcon, { title: t("announcementSearchResultListItem.announcement"), children: /* @__PURE__ */ jsx(RecordVoiceOverIcon, {}) }),
55
+ /* @__PURE__ */ jsx(ListItemIcon, { title: t("announcementSearchResultListItem.announcement"), children: /* @__PURE__ */ jsx(RiMegaphoneLine, {}) }),
56
56
  /* @__PURE__ */ jsx(
57
57
  ListItemText,
58
58
  {
@@ -1 +1 @@
1
- {"version":3,"file":"AnnouncementSearchResultListItem.esm.js","sources":["../../../src/components/AnnouncementSearchResultListItem/AnnouncementSearchResultListItem.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { DateTime } from 'luxon';\nimport { Link } from '@backstage/core-components';\nimport {\n IndexableDocument,\n ResultHighlight,\n} from '@backstage/plugin-search-common';\nimport { HighlightedSearchResultText } from '@backstage/plugin-search-react';\nimport { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';\nimport {\n makeStyles,\n ListItem,\n ListItemIcon,\n ListItemText,\n Typography,\n} from '@material-ui/core';\nimport RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';\n\nconst useStyles = makeStyles({\n createdAt: {\n display: 'block',\n marginTop: '0.2rem',\n marginBottom: '0.8rem',\n },\n excerpt: {\n lineHeight: '1.55',\n },\n itemText: {\n wordBreak: 'break-all',\n },\n});\n\ntype IndexableAnnouncement = IndexableDocument & {\n createdAt: string;\n};\n\n/** @public */\nexport interface AnnouncementSearchResultProps {\n result?: IndexableDocument;\n highlight?: ResultHighlight;\n rank?: number;\n}\n\nexport const AnnouncementSearchResultListItem = ({\n result,\n highlight,\n}: AnnouncementSearchResultProps) => {\n const classes = useStyles();\n const { t } = useAnnouncementsTranslation();\n\n if (!result) {\n return null;\n }\n\n const document = result as IndexableAnnouncement;\n\n const title = (\n <Link noTrack to={result.location}>\n {highlight?.fields.title ? (\n <HighlightedSearchResultText\n text={highlight.fields.title}\n preTag={highlight.preTag}\n postTag={highlight.postTag}\n />\n ) : (\n result.title\n )}\n </Link>\n );\n\n const excerpt = (\n <>\n <Typography component=\"span\" className={classes.createdAt}>\n {`${t('announcementSearchResultListItem.published')} `}\n <Typography component=\"span\" title={document.createdAt}>\n {DateTime.fromISO(document.createdAt).toRelative()}\n </Typography>\n </Typography>\n <>\n {highlight?.fields.text ? (\n <HighlightedSearchResultText\n text={highlight.fields.text}\n preTag={highlight.preTag}\n postTag={highlight.postTag}\n />\n ) : (\n result.text\n )}\n </>\n </>\n );\n\n return (\n <ListItem alignItems=\"center\">\n <ListItemIcon title={t('announcementSearchResultListItem.announcement')}>\n <RecordVoiceOverIcon />\n </ListItemIcon>\n <ListItemText\n primary={title}\n secondary={excerpt}\n className={classes.itemText}\n primaryTypographyProps={{ variant: 'h6' }}\n />\n </ListItem>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAgCA,MAAM,YAAY,UAAW,CAAA;AAAA,EAC3B,SAAW,EAAA;AAAA,IACT,OAAS,EAAA,OAAA;AAAA,IACT,SAAW,EAAA,QAAA;AAAA,IACX,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,OAAS,EAAA;AAAA,IACP,UAAY,EAAA;AAAA,GACd;AAAA,EACA,QAAU,EAAA;AAAA,IACR,SAAW,EAAA;AAAA;AAEf,CAAC,CAAA;AAaM,MAAM,mCAAmC,CAAC;AAAA,EAC/C,MAAA;AAAA,EACA;AACF,CAAqC,KAAA;AACnC,EAAA,MAAM,UAAU,SAAU,EAAA;AAC1B,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,2BAA4B,EAAA;AAE1C,EAAA,IAAI,CAAC,MAAQ,EAAA;AACX,IAAO,OAAA,IAAA;AAAA;AAGT,EAAA,MAAM,QAAW,GAAA,MAAA;AAEjB,EAAM,MAAA,KAAA,mBACH,GAAA,CAAA,IAAA,EAAA,EAAK,OAAO,EAAA,IAAA,EAAC,IAAI,MAAO,CAAA,QAAA,EACtB,QAAW,EAAA,SAAA,EAAA,MAAA,CAAO,KACjB,mBAAA,GAAA;AAAA,IAAC,2BAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,UAAU,MAAO,CAAA,KAAA;AAAA,MACvB,QAAQ,SAAU,CAAA,MAAA;AAAA,MAClB,SAAS,SAAU,CAAA;AAAA;AAAA,GACrB,GAEA,OAAO,KAEX,EAAA,CAAA;AAGF,EAAA,MAAM,0BAEF,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAU,MAAO,EAAA,SAAA,EAAW,QAAQ,SAC7C,EAAA,QAAA,EAAA;AAAA,MAAG,CAAA,EAAA,CAAA,CAAE,4CAA4C,CAAC,CAAA,CAAA,CAAA;AAAA,sBAClD,GAAA,CAAA,UAAA,EAAA,EAAW,SAAU,EAAA,MAAA,EAAO,KAAO,EAAA,QAAA,CAAS,SAC1C,EAAA,QAAA,EAAA,QAAA,CAAS,OAAQ,CAAA,QAAA,CAAS,SAAS,CAAA,CAAE,YACxC,EAAA;AAAA,KACF,EAAA,CAAA;AAAA,oBACA,GAAA,CAAA,QAAA,EAAA,EACG,QAAW,EAAA,SAAA,EAAA,MAAA,CAAO,IACjB,mBAAA,GAAA;AAAA,MAAC,2BAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,UAAU,MAAO,CAAA,IAAA;AAAA,QACvB,QAAQ,SAAU,CAAA,MAAA;AAAA,QAClB,SAAS,SAAU,CAAA;AAAA;AAAA,KACrB,GAEA,OAAO,IAEX,EAAA;AAAA,GACF,EAAA,CAAA;AAGF,EACE,uBAAA,IAAA,CAAC,QAAS,EAAA,EAAA,UAAA,EAAW,QACnB,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,gBAAa,KAAO,EAAA,CAAA,CAAE,+CAA+C,CACpE,EAAA,QAAA,kBAAA,GAAA,CAAC,uBAAoB,CACvB,EAAA,CAAA;AAAA,oBACA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA,KAAA;AAAA,QACT,SAAW,EAAA,OAAA;AAAA,QACX,WAAW,OAAQ,CAAA,QAAA;AAAA,QACnB,sBAAA,EAAwB,EAAE,OAAA,EAAS,IAAK;AAAA;AAAA;AAC1C,GACF,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"AnnouncementSearchResultListItem.esm.js","sources":["../../../src/components/AnnouncementSearchResultListItem/AnnouncementSearchResultListItem.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { DateTime } from 'luxon';\nimport { Link } from '@backstage/core-components';\nimport {\n IndexableDocument,\n ResultHighlight,\n} from '@backstage/plugin-search-common';\nimport { HighlightedSearchResultText } from '@backstage/plugin-search-react';\nimport { useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';\nimport {\n makeStyles,\n ListItem,\n ListItemIcon,\n ListItemText,\n Typography,\n} from '@material-ui/core';\nimport { RiMegaphoneLine } from '@remixicon/react';\n\nconst useStyles = makeStyles({\n createdAt: {\n display: 'block',\n marginTop: '0.2rem',\n marginBottom: '0.8rem',\n },\n excerpt: {\n lineHeight: '1.55',\n },\n itemText: {\n wordBreak: 'break-all',\n },\n});\n\ntype IndexableAnnouncement = IndexableDocument & {\n createdAt: string;\n};\n\n/** @public */\nexport interface AnnouncementSearchResultProps {\n result?: IndexableDocument;\n highlight?: ResultHighlight;\n rank?: number;\n}\n\nexport const AnnouncementSearchResultListItem = ({\n result,\n highlight,\n}: AnnouncementSearchResultProps) => {\n const classes = useStyles();\n const { t } = useAnnouncementsTranslation();\n\n if (!result) {\n return null;\n }\n\n const document = result as IndexableAnnouncement;\n\n const title = (\n <Link noTrack to={result.location}>\n {highlight?.fields.title ? (\n <HighlightedSearchResultText\n text={highlight.fields.title}\n preTag={highlight.preTag}\n postTag={highlight.postTag}\n />\n ) : (\n result.title\n )}\n </Link>\n );\n\n const excerpt = (\n <>\n <Typography component=\"span\" className={classes.createdAt}>\n {`${t('announcementSearchResultListItem.published')} `}\n <Typography component=\"span\" title={document.createdAt}>\n {DateTime.fromISO(document.createdAt).toRelative()}\n </Typography>\n </Typography>\n <>\n {highlight?.fields.text ? (\n <HighlightedSearchResultText\n text={highlight.fields.text}\n preTag={highlight.preTag}\n postTag={highlight.postTag}\n />\n ) : (\n result.text\n )}\n </>\n </>\n );\n\n return (\n <ListItem alignItems=\"center\">\n <ListItemIcon title={t('announcementSearchResultListItem.announcement')}>\n <RiMegaphoneLine />\n </ListItemIcon>\n <ListItemText\n primary={title}\n secondary={excerpt}\n className={classes.itemText}\n primaryTypographyProps={{ variant: 'h6' }}\n />\n </ListItem>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAgCA,MAAM,YAAY,UAAW,CAAA;AAAA,EAC3B,SAAW,EAAA;AAAA,IACT,OAAS,EAAA,OAAA;AAAA,IACT,SAAW,EAAA,QAAA;AAAA,IACX,YAAc,EAAA;AAAA,GAChB;AAAA,EACA,OAAS,EAAA;AAAA,IACP,UAAY,EAAA;AAAA,GACd;AAAA,EACA,QAAU,EAAA;AAAA,IACR,SAAW,EAAA;AAAA;AAEf,CAAC,CAAA;AAaM,MAAM,mCAAmC,CAAC;AAAA,EAC/C,MAAA;AAAA,EACA;AACF,CAAqC,KAAA;AACnC,EAAA,MAAM,UAAU,SAAU,EAAA;AAC1B,EAAM,MAAA,EAAE,CAAE,EAAA,GAAI,2BAA4B,EAAA;AAE1C,EAAA,IAAI,CAAC,MAAQ,EAAA;AACX,IAAO,OAAA,IAAA;AAAA;AAGT,EAAA,MAAM,QAAW,GAAA,MAAA;AAEjB,EAAM,MAAA,KAAA,mBACH,GAAA,CAAA,IAAA,EAAA,EAAK,OAAO,EAAA,IAAA,EAAC,IAAI,MAAO,CAAA,QAAA,EACtB,QAAW,EAAA,SAAA,EAAA,MAAA,CAAO,KACjB,mBAAA,GAAA;AAAA,IAAC,2BAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,UAAU,MAAO,CAAA,KAAA;AAAA,MACvB,QAAQ,SAAU,CAAA,MAAA;AAAA,MAClB,SAAS,SAAU,CAAA;AAAA;AAAA,GACrB,GAEA,OAAO,KAEX,EAAA,CAAA;AAGF,EAAA,MAAM,0BAEF,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,UAAW,EAAA,EAAA,SAAA,EAAU,MAAO,EAAA,SAAA,EAAW,QAAQ,SAC7C,EAAA,QAAA,EAAA;AAAA,MAAG,CAAA,EAAA,CAAA,CAAE,4CAA4C,CAAC,CAAA,CAAA,CAAA;AAAA,sBAClD,GAAA,CAAA,UAAA,EAAA,EAAW,SAAU,EAAA,MAAA,EAAO,KAAO,EAAA,QAAA,CAAS,SAC1C,EAAA,QAAA,EAAA,QAAA,CAAS,OAAQ,CAAA,QAAA,CAAS,SAAS,CAAA,CAAE,YACxC,EAAA;AAAA,KACF,EAAA,CAAA;AAAA,oBACA,GAAA,CAAA,QAAA,EAAA,EACG,QAAW,EAAA,SAAA,EAAA,MAAA,CAAO,IACjB,mBAAA,GAAA;AAAA,MAAC,2BAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,UAAU,MAAO,CAAA,IAAA;AAAA,QACvB,QAAQ,SAAU,CAAA,MAAA;AAAA,QAClB,SAAS,SAAU,CAAA;AAAA;AAAA,KACrB,GAEA,OAAO,IAEX,EAAA;AAAA,GACF,EAAA,CAAA;AAGF,EACE,uBAAA,IAAA,CAAC,QAAS,EAAA,EAAA,UAAA,EAAW,QACnB,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,gBAAa,KAAO,EAAA,CAAA,CAAE,+CAA+C,CACpE,EAAA,QAAA,kBAAA,GAAA,CAAC,mBAAgB,CACnB,EAAA,CAAA;AAAA,oBACA,GAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,OAAS,EAAA,KAAA;AAAA,QACT,SAAW,EAAA,OAAA;AAAA,QACX,WAAW,OAAQ,CAAA,QAAA;AAAA,QACnB,sBAAA,EAAwB,EAAE,OAAA,EAAS,IAAK;AAAA;AAAA;AAC1C,GACF,EAAA,CAAA;AAEJ;;;;"}
@@ -1,58 +1,33 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import { useState, useEffect } from 'react';
3
3
  import { DateTime } from 'luxon';
4
- import { Link } from '@backstage/core-components';
4
+ import { Alert, Box, Link, ButtonIcon } from '@backstage/ui';
5
5
  import { useApi, useRouteRef, useAnalytics } from '@backstage/core-plugin-api';
6
6
  import { announcementsApiRef, useAnnouncements, useAnnouncementsTranslation } from '@backstage-community/plugin-announcements-react';
7
7
  import { SIGNALS_CHANNEL_ANNOUNCEMENTS, MAX_TITLE_LENGTH, MAX_EXCERPT_LENGTH } from '@backstage-community/plugin-announcements-common';
8
8
  import { useSignal } from '@backstage/plugin-signals-react';
9
- import { makeStyles, Typography, Snackbar, SnackbarContent, IconButton } from '@material-ui/core';
10
- import Close from '@material-ui/icons/Close';
11
- import { Alert } from '@material-ui/lab';
9
+ import { RiExternalLinkLine, RiCloseLine, RiMegaphoneLine } from '@remixicon/react';
12
10
  import { announcementViewRouteRef } from '../../routes.esm.js';
13
11
  import { truncate } from '../utils/truncateUtils.esm.js';
14
12
 
15
- const useStyles = makeStyles((theme) => {
16
- return {
17
- // showing on top, as a block
18
- blockPositioning: {
19
- padding: theme?.spacing?.(0) ?? 0,
20
- position: "relative",
21
- marginBottom: theme?.spacing?.(4) ?? 32,
22
- marginTop: theme?.spacing?.(3) ?? -24,
23
- zIndex: "unset"
24
- },
25
- // showing on top, as a floating alert
26
- floatingPositioning: {},
27
- icon: {
28
- fontSize: 20
29
- },
30
- bannerIcon: {
31
- fontSize: 20,
32
- marginRight: "0.5rem"
33
- },
34
- content: {
35
- width: "100%",
36
- maxWidth: "inherit",
37
- flexWrap: "nowrap",
38
- backgroundColor: theme?.palette?.banner?.info ?? "#f0f0f0",
39
- display: "flex",
40
- alignItems: "center",
41
- color: theme?.palette?.banner?.text ?? "#000000",
42
- "& a": {
43
- color: theme?.palette?.banner?.link ?? "#0068c8"
44
- }
45
- }
46
- };
47
- });
13
+ const floatingStyle = {
14
+ position: "fixed",
15
+ top: 20,
16
+ left: "50%",
17
+ transform: "translateX(-50%)"
18
+ };
19
+ const externalLinkIconStyle = {
20
+ width: "0.85em",
21
+ height: "0.85em",
22
+ verticalAlign: "middle",
23
+ marginLeft: 5
24
+ };
48
25
  const AnnouncementBanner = (props) => {
49
- const classes = useStyles();
50
26
  const announcementsApi = useApi(announcementsApiRef);
51
27
  const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);
52
28
  const analytics = useAnalytics();
53
29
  const { t } = useAnnouncementsTranslation();
54
30
  const [bannerOpen, setBannerOpen] = useState(true);
55
- const variant = props.variant || "block";
56
31
  const announcement = props.announcement;
57
32
  const titleLength = props.cardOptions?.titleLength;
58
33
  const excerptLength = props.cardOptions?.excerptLength;
@@ -82,28 +57,27 @@ const AnnouncementBanner = (props) => {
82
57
  };
83
58
  const title = titleLength ? truncate(announcement.title, titleLength) : announcement.title;
84
59
  const excerpt = excerptLength ? truncate(announcement.excerpt, excerptLength) : announcement.excerpt;
85
- const message = /* @__PURE__ */ jsxs(Fragment, { children: [
86
- /* @__PURE__ */ jsx(
87
- Typography,
88
- {
89
- component: "span",
90
- className: classes.bannerIcon,
91
- variant: "inherit",
92
- children: "\u{1F4E3}"
93
- }
94
- ),
60
+ const bannerTitle = /* @__PURE__ */ jsxs(Box, { children: [
61
+ title,
95
62
  /* @__PURE__ */ jsx(
96
63
  Link,
97
64
  {
98
- to: viewAnnouncementLink({ id: announcement.id }),
99
- variant: "inherit",
65
+ href: viewAnnouncementLink({ id: announcement.id }),
100
66
  onClick: handleLinkClick,
101
- children: title
67
+ variant: "body-large",
68
+ children: /* @__PURE__ */ jsx(RiExternalLinkLine, { "aria-hidden": true, style: externalLinkIconStyle })
102
69
  }
103
- ),
104
- "\xA0\u2013 ",
105
- excerpt
70
+ )
106
71
  ] });
72
+ const closeButton = /* @__PURE__ */ jsx(
73
+ ButtonIcon,
74
+ {
75
+ icon: /* @__PURE__ */ jsx(RiCloseLine, {}),
76
+ "aria-label": t("newAnnouncementBanner.markAsSeen"),
77
+ onPress: handleDismiss,
78
+ variant: "tertiary"
79
+ }
80
+ );
107
81
  useEffect(() => {
108
82
  if (!bannerOpen) {
109
83
  return;
@@ -115,31 +89,19 @@ const AnnouncementBanner = (props) => {
115
89
  }
116
90
  });
117
91
  }, [analytics, announcement.id, announcement.title, bannerOpen]);
92
+ if (!bannerOpen) {
93
+ return null;
94
+ }
118
95
  return /* @__PURE__ */ jsx(
119
- Snackbar,
96
+ Alert,
120
97
  {
121
- anchorOrigin: { vertical: "top", horizontal: "center" },
122
- open: bannerOpen,
123
- className: variant === "block" ? classes.blockPositioning : classes.floatingPositioning,
124
- children: /* @__PURE__ */ jsx(
125
- SnackbarContent,
126
- {
127
- className: classes.content,
128
- message,
129
- action: [
130
- /* @__PURE__ */ jsx(
131
- IconButton,
132
- {
133
- title: t("newAnnouncementBanner.markAsSeen"),
134
- color: "inherit",
135
- onClick: handleDismiss,
136
- children: /* @__PURE__ */ jsx(Close, { className: classes.icon })
137
- },
138
- "dismiss"
139
- )
140
- ]
141
- }
142
- )
98
+ style: floatingStyle,
99
+ status: "info",
100
+ icon: /* @__PURE__ */ jsx(RiMegaphoneLine, {}),
101
+ title: bannerTitle,
102
+ description: excerpt,
103
+ customActions: closeButton,
104
+ mb: "4"
143
105
  }
144
106
  );
145
107
  };
@@ -149,7 +111,6 @@ const NewAnnouncementBanner = (props) => {
149
111
  category,
150
112
  tags,
151
113
  active,
152
- variant,
153
114
  current,
154
115
  sortBy,
155
116
  cardOptions = {
@@ -180,7 +141,7 @@ const NewAnnouncementBanner = (props) => {
180
141
  if (loading) {
181
142
  return null;
182
143
  } else if (error) {
183
- return /* @__PURE__ */ jsx(Alert, { severity: "error", children: error.message });
144
+ return /* @__PURE__ */ jsx(Alert, { status: "danger", title: error.message });
184
145
  }
185
146
  if (announcements.count === 0) {
186
147
  return null;
@@ -198,7 +159,6 @@ const NewAnnouncementBanner = (props) => {
198
159
  AnnouncementBanner,
199
160
  {
200
161
  announcement,
201
- variant,
202
162
  cardOptions
203
163
  },
204
164
  announcement.id
@@ -1 +1 @@
1
- {"version":3,"file":"NewAnnouncementBanner.esm.js","sources":["../../../src/components/NewAnnouncementBanner/NewAnnouncementBanner.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect, useState } from 'react';\nimport { DateTime } from 'luxon';\nimport { Link } from '@backstage/core-components';\nimport { useApi, useRouteRef, useAnalytics } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n AnnouncementSignal,\n MAX_EXCERPT_LENGTH,\n MAX_TITLE_LENGTH,\n SIGNALS_CHANNEL_ANNOUNCEMENTS,\n} from '@backstage-community/plugin-announcements-common';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport {\n makeStyles,\n Snackbar,\n SnackbarContent,\n IconButton,\n Typography,\n} from '@material-ui/core';\nimport Close from '@material-ui/icons/Close';\nimport { Alert } from '@material-ui/lab';\n\nimport { announcementViewRouteRef } from '../../routes';\nimport { truncate } from '../utils/truncateUtils';\n\nconst useStyles = makeStyles(theme => {\n return {\n // showing on top, as a block\n blockPositioning: {\n padding: theme?.spacing?.(0) ?? 0,\n position: 'relative',\n marginBottom: theme?.spacing?.(4) ?? 32,\n marginTop: theme?.spacing?.(3) ?? -24,\n zIndex: 'unset',\n },\n // showing on top, as a floating alert\n floatingPositioning: {},\n icon: {\n fontSize: 20,\n },\n bannerIcon: {\n fontSize: 20,\n marginRight: '0.5rem',\n },\n content: {\n width: '100%',\n maxWidth: 'inherit',\n flexWrap: 'nowrap',\n backgroundColor: theme?.palette?.banner?.info ?? '#f0f0f0',\n display: 'flex',\n alignItems: 'center',\n color: theme?.palette?.banner?.text ?? '#000000',\n '& a': {\n color: theme?.palette?.banner?.link ?? '#0068c8',\n },\n },\n };\n});\n\ntype CardOptions = {\n titleLength?: number;\n excerptLength?: number;\n};\n\ntype AnnouncementBannerProps = {\n announcement: Announcement;\n variant?: 'block' | 'floating';\n cardOptions?: CardOptions;\n};\n\nconst AnnouncementBanner = (props: AnnouncementBannerProps) => {\n const classes = useStyles();\n const announcementsApi = useApi(announcementsApiRef);\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n const analytics = useAnalytics();\n const { t } = useAnnouncementsTranslation();\n const [bannerOpen, setBannerOpen] = useState(true);\n const variant = props.variant || 'block';\n const announcement = props.announcement;\n const titleLength = props.cardOptions?.titleLength;\n const excerptLength = props.cardOptions?.excerptLength;\n\n const markSeen = () => {\n announcementsApi.markLastSeenDate(\n DateTime.fromISO(announcement.created_at),\n );\n setBannerOpen(false);\n };\n\n const handleLinkClick = () => {\n analytics.captureEvent('click', announcement.title, {\n attributes: {\n announcementId: announcement.id,\n location: 'NewAnnouncementBanner',\n },\n });\n\n markSeen();\n };\n\n const handleDismiss = () => {\n analytics.captureEvent('dismiss', announcement.title, {\n attributes: {\n announcementId: announcement.id,\n location: 'NewAnnouncementBanner',\n },\n });\n\n markSeen();\n };\n\n const title = titleLength\n ? truncate(announcement.title, titleLength)\n : announcement.title;\n const excerpt = excerptLength\n ? truncate(announcement.excerpt, excerptLength)\n : announcement.excerpt;\n\n const message = (\n <>\n <Typography\n component=\"span\"\n className={classes.bannerIcon}\n variant=\"inherit\"\n >\n 📣\n </Typography>\n <Link\n to={viewAnnouncementLink({ id: announcement.id })}\n variant=\"inherit\"\n onClick={handleLinkClick}\n >\n {title}\n </Link>\n &nbsp;– {excerpt}\n </>\n );\n\n useEffect(() => {\n if (!bannerOpen) {\n return;\n }\n\n analytics.captureEvent('view', announcement.title, {\n attributes: {\n announcementId: announcement.id,\n location: 'NewAnnouncementBanner',\n },\n });\n }, [analytics, announcement.id, announcement.title, bannerOpen]);\n\n return (\n <Snackbar\n anchorOrigin={{ vertical: 'top', horizontal: 'center' }}\n open={bannerOpen}\n className={\n variant === 'block'\n ? classes.blockPositioning\n : classes.floatingPositioning\n }\n >\n <SnackbarContent\n className={classes.content}\n message={message}\n action={[\n <IconButton\n key=\"dismiss\"\n title={t('newAnnouncementBanner.markAsSeen')}\n color=\"inherit\"\n onClick={handleDismiss}\n >\n <Close className={classes.icon} />\n </IconButton>,\n ]}\n />\n </Snackbar>\n );\n};\n\ntype NewAnnouncementBannerProps = {\n variant?: 'block' | 'floating';\n max?: number;\n category?: string;\n active?: boolean;\n current?: boolean;\n tags?: string[];\n sortBy?: 'created_at' | 'updated_at';\n cardOptions?: CardOptions;\n};\n\nexport const NewAnnouncementBanner = (props: NewAnnouncementBannerProps) => {\n const {\n max,\n category,\n tags,\n active,\n variant,\n current,\n sortBy,\n cardOptions = {\n titleLength: MAX_TITLE_LENGTH,\n excerptLength: MAX_EXCERPT_LENGTH,\n },\n } = props;\n\n const announcementsApi = useApi(announcementsApiRef);\n\n const [signaledAnnouncement, setSignaledAnnouncement] = useState<\n AnnouncementSignal['data'] | undefined\n >();\n\n const { announcements, loading, error } = useAnnouncements({\n max: max ?? 1,\n category,\n tags,\n active,\n current,\n sortBy,\n });\n const lastSeen = announcementsApi.lastSeenDate();\n\n const { lastSignal } = useSignal<AnnouncementSignal>(\n SIGNALS_CHANNEL_ANNOUNCEMENTS,\n );\n\n useEffect(() => {\n if (!lastSignal) {\n return;\n }\n\n setSignaledAnnouncement(lastSignal?.data);\n }, [lastSignal]);\n\n if (loading) {\n return null;\n } else if (error) {\n return <Alert severity=\"error\">{error.message}</Alert>;\n }\n\n if (announcements.count === 0) {\n return null;\n }\n\n const unseenAnnouncements = announcements.results.filter(announcement => {\n return lastSeen < DateTime.fromISO(announcement.created_at);\n });\n\n if (signaledAnnouncement) {\n unseenAnnouncements.push(signaledAnnouncement);\n }\n\n if (unseenAnnouncements?.length === 0) {\n return null;\n }\n\n return (\n <>\n {unseenAnnouncements.map(announcement => (\n <AnnouncementBanner\n key={announcement.id}\n announcement={announcement}\n variant={variant}\n cardOptions={cardOptions}\n />\n ))}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"NewAnnouncementBanner.esm.js","sources":["../../../src/components/NewAnnouncementBanner/NewAnnouncementBanner.tsx"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\nimport { useEffect, useState } from 'react';\nimport { DateTime } from 'luxon';\nimport { Link, Alert, ButtonIcon, Box } from '@backstage/ui';\nimport { useApi, useRouteRef, useAnalytics } from '@backstage/core-plugin-api';\nimport {\n announcementsApiRef,\n useAnnouncements,\n useAnnouncementsTranslation,\n} from '@backstage-community/plugin-announcements-react';\nimport {\n Announcement,\n AnnouncementSignal,\n MAX_EXCERPT_LENGTH,\n MAX_TITLE_LENGTH,\n SIGNALS_CHANNEL_ANNOUNCEMENTS,\n} from '@backstage-community/plugin-announcements-common';\nimport { useSignal } from '@backstage/plugin-signals-react';\nimport {\n RiCloseLine,\n RiMegaphoneLine,\n RiExternalLinkLine,\n} from '@remixicon/react';\n\nimport { announcementViewRouteRef } from '../../routes';\nimport { truncate } from '../utils/truncateUtils';\n\ntype CardOptions = {\n titleLength?: number;\n excerptLength?: number;\n};\n\ntype AnnouncementBannerProps = {\n announcement: Announcement;\n cardOptions?: CardOptions;\n};\n\nconst floatingStyle: React.CSSProperties = {\n position: 'fixed',\n top: 20,\n left: '50%',\n transform: 'translateX(-50%)',\n};\n\nconst externalLinkIconStyle: React.CSSProperties = {\n width: '0.85em',\n height: '0.85em',\n verticalAlign: 'middle',\n marginLeft: 5,\n};\n\nconst AnnouncementBanner = (props: AnnouncementBannerProps) => {\n const announcementsApi = useApi(announcementsApiRef);\n const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);\n const analytics = useAnalytics();\n const { t } = useAnnouncementsTranslation();\n const [bannerOpen, setBannerOpen] = useState(true);\n const announcement = props.announcement;\n const titleLength = props.cardOptions?.titleLength;\n const excerptLength = props.cardOptions?.excerptLength;\n\n const markSeen = () => {\n announcementsApi.markLastSeenDate(\n DateTime.fromISO(announcement.created_at),\n );\n setBannerOpen(false);\n };\n\n const handleLinkClick = () => {\n analytics.captureEvent('click', announcement.title, {\n attributes: {\n announcementId: announcement.id,\n location: 'NewAnnouncementBanner',\n },\n });\n\n markSeen();\n };\n\n const handleDismiss = () => {\n analytics.captureEvent('dismiss', announcement.title, {\n attributes: {\n announcementId: announcement.id,\n location: 'NewAnnouncementBanner',\n },\n });\n\n markSeen();\n };\n\n const title = titleLength\n ? truncate(announcement.title, titleLength)\n : announcement.title;\n const excerpt = excerptLength\n ? truncate(announcement.excerpt, excerptLength)\n : announcement.excerpt;\n\n const bannerTitle = (\n <Box>\n {title}\n <Link\n href={viewAnnouncementLink({ id: announcement.id })}\n onClick={handleLinkClick}\n variant=\"body-large\"\n >\n <RiExternalLinkLine aria-hidden style={externalLinkIconStyle} />\n </Link>\n </Box>\n );\n\n const closeButton = (\n <ButtonIcon\n icon={<RiCloseLine />}\n aria-label={t('newAnnouncementBanner.markAsSeen')}\n onPress={handleDismiss}\n variant=\"tertiary\"\n />\n );\n\n useEffect(() => {\n if (!bannerOpen) {\n return;\n }\n\n analytics.captureEvent('view', announcement.title, {\n attributes: {\n announcementId: announcement.id,\n location: 'NewAnnouncementBanner',\n },\n });\n }, [analytics, announcement.id, announcement.title, bannerOpen]);\n\n if (!bannerOpen) {\n return null;\n }\n\n return (\n <Alert\n style={floatingStyle}\n status=\"info\"\n icon={<RiMegaphoneLine />}\n title={bannerTitle}\n description={excerpt}\n customActions={closeButton}\n mb=\"4\"\n />\n );\n};\n\ntype NewAnnouncementBannerProps = {\n max?: number;\n category?: string;\n active?: boolean;\n current?: boolean;\n tags?: string[];\n sortBy?: 'created_at' | 'updated_at';\n cardOptions?: CardOptions;\n};\n\nexport const NewAnnouncementBanner = (props: NewAnnouncementBannerProps) => {\n const {\n max,\n category,\n tags,\n active,\n current,\n sortBy,\n cardOptions = {\n titleLength: MAX_TITLE_LENGTH,\n excerptLength: MAX_EXCERPT_LENGTH,\n },\n } = props;\n\n const announcementsApi = useApi(announcementsApiRef);\n\n const [signaledAnnouncement, setSignaledAnnouncement] = useState<\n AnnouncementSignal['data'] | undefined\n >();\n\n const { announcements, loading, error } = useAnnouncements({\n max: max ?? 1,\n category,\n tags,\n active,\n current,\n sortBy,\n });\n const lastSeen = announcementsApi.lastSeenDate();\n\n const { lastSignal } = useSignal<AnnouncementSignal>(\n SIGNALS_CHANNEL_ANNOUNCEMENTS,\n );\n\n useEffect(() => {\n if (!lastSignal) {\n return;\n }\n\n setSignaledAnnouncement(lastSignal?.data);\n }, [lastSignal]);\n\n if (loading) {\n return null;\n } else if (error) {\n return <Alert status=\"danger\" title={error.message} />;\n }\n\n if (announcements.count === 0) {\n return null;\n }\n\n const unseenAnnouncements = announcements.results.filter(announcement => {\n return lastSeen < DateTime.fromISO(announcement.created_at);\n });\n\n if (signaledAnnouncement) {\n unseenAnnouncements.push(signaledAnnouncement);\n }\n\n if (unseenAnnouncements?.length === 0) {\n return null;\n }\n\n return (\n <>\n {unseenAnnouncements.map(announcement => (\n <AnnouncementBanner\n key={announcement.id}\n announcement={announcement}\n cardOptions={cardOptions}\n />\n ))}\n </>\n );\n};\n"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -56,7 +56,6 @@ declare const AnnouncementsCard: ({ title, max, category, active, variant, sortB
56
56
  * @public
57
57
  */
58
58
  declare const NewAnnouncementBanner: (props: {
59
- variant?: "block" | "floating" | undefined;
60
59
  max?: number | undefined;
61
60
  category?: string | undefined;
62
61
  active?: boolean | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage-community/plugin-announcements",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "main": "./dist/index.esm.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -61,26 +61,24 @@
61
61
  "postpack": "backstage-cli package postpack"
62
62
  },
63
63
  "dependencies": {
64
- "@backstage-community/plugin-announcements-common": "^0.17.0",
65
- "@backstage-community/plugin-announcements-react": "^0.21.0",
64
+ "@backstage-community/plugin-announcements-common": "^0.18.0",
65
+ "@backstage-community/plugin-announcements-react": "^0.22.0",
66
66
  "@backstage/catalog-model": "^1.7.6",
67
- "@backstage/core-app-api": "^1.19.4",
68
- "@backstage/core-compat-api": "^0.5.7",
69
- "@backstage/core-components": "^0.18.6",
70
- "@backstage/core-plugin-api": "^1.12.2",
67
+ "@backstage/core-compat-api": "^0.5.8",
68
+ "@backstage/core-components": "^0.18.7",
69
+ "@backstage/core-plugin-api": "^1.12.3",
71
70
  "@backstage/errors": "^1.2.7",
72
- "@backstage/frontend-plugin-api": "^0.13.4",
73
- "@backstage/plugin-catalog-react": "^1.21.6",
74
- "@backstage/plugin-permission-react": "^0.4.39",
75
- "@backstage/plugin-search-common": "^1.2.21",
76
- "@backstage/plugin-search-react": "^1.10.2",
77
- "@backstage/plugin-signals-react": "^0.0.18",
78
- "@backstage/theme": "^0.7.1",
79
- "@backstage/ui": "^0.11.2",
71
+ "@backstage/frontend-plugin-api": "^0.14.1",
72
+ "@backstage/plugin-catalog-react": "^2.0.0",
73
+ "@backstage/plugin-permission-react": "^0.4.40",
74
+ "@backstage/plugin-search-common": "^1.2.22",
75
+ "@backstage/plugin-search-react": "^1.10.4",
76
+ "@backstage/plugin-signals-react": "^0.0.19",
77
+ "@backstage/theme": "^0.7.2",
78
+ "@backstage/ui": "^0.12.0",
80
79
  "@material-ui/core": "^4.12.2",
81
80
  "@material-ui/icons": "^4.11.3",
82
81
  "@material-ui/lab": "4.0.0-alpha.61",
83
- "@mui/icons-material": "^5.15.6",
84
82
  "@mui/material": "^5.15.6",
85
83
  "@remixicon/react": "^4.7.0",
86
84
  "@types/react": "^17.0.0 || ^18.0.0",
@@ -95,11 +93,11 @@
95
93
  "react-router-dom": "^6.3.0"
96
94
  },
97
95
  "devDependencies": {
98
- "@backstage/cli": "^0.35.3",
99
- "@backstage/dev-utils": "^1.1.19",
100
- "@backstage/frontend-test-utils": "^0.4.5",
101
- "@backstage/plugin-signals": "^0.0.27",
102
- "@backstage/test-utils": "^1.7.14",
96
+ "@backstage/cli": "^0.35.4",
97
+ "@backstage/dev-utils": "^1.1.20",
98
+ "@backstage/frontend-test-utils": "^0.5.0",
99
+ "@backstage/plugin-signals": "^0.0.28",
100
+ "@backstage/test-utils": "^1.7.15",
103
101
  "@testing-library/jest-dom": "^6.3.0",
104
102
  "@testing-library/react": "^14.0.0",
105
103
  "@testing-library/user-event": "^14.5.1",