Driftsmeddelelser på forsiden med PnP Modern Search
En kompakt liste over nedbrud og driftsarbejde, hvor kritiske sager får et rødt skjold og løste et grønt flueben — bygget med en egen skabelon i PnP Modern Search.
Jeg har bygget den samme lille løsning et par gange: en liste med driftsmeddelelser — nedbrud, planlagt arbejde, ting der driller — vist som en kort liste på intranettets forside. Kritiske meddelelser, der ikke er løst, får et rødt skjold. Løste meddelelser får et grønt flueben, og er de ikke kritiske, også teksten “(Løst)”. Resuméet er foldet sammen, så listen kan læses på et øjeblik, og den ansvarlige står nederst, når man folder ud.
Det er PnP Modern Search, der gør arbejdet. Resten er en indholdstype og en Handlebars-skabelon.
Fremgangsmåde#
- Installer PnP Modern Search-webdelene.
- Opret en indholdstype til meddelelserne. Skabelonen forventer en startdato, et emne, et ja/nej-felt for kritisk, et ja/nej-felt for løst, en titel, et resumé og en ansvarlig (et personfelt).
- Sæt en Search Results-webdel op, der henter meddelelserne, og giv felterne slots med de navne, skabelonen bruger:
StartDate,Topic,Critical,Solved,Title,SummaryogResponsible. - Vælg et custom layout, og indsæt skabelonen herunder.
1<content id="data-content">
2
3 <style>
4
5 /* Insert your CSS overrides here */
6 .example-themePrimary a {
7 color: {{@root.theme.palette.themePrimary}};
8 }
9
10 /* .icon {
11 width: 20px;
12 height: 16px;
13 } */
14
15 ul.template--itdrift {
16 list-style: none;
17 padding-left: 0px;
18 margin-block-start: -2em;
19 margin-left: 3px;
20 }
21
22 ul.template--itdrift li {
23 display: inline-grid;
24 padding: 15px 0px;
25 border-bottom: 1px solid rgb(11, 36, 64);
26 min-width: 100%;
27 }
28 ul.template--itdrift .themeMeta{
29 font-size: 12px;
30 font-weight: 600;
31 margin-bottom:5px;
32 color: {{@root.theme.palette.themeblack}};
33 }
34 ul.template--itdrift .themeTitle{
35 color: {{@root.theme.palette.themeDarker}};
36 }
37 ul.template--itdrift .themeTitleRed{
38 display: flex;
39 margin-bottom: 5px;
40 color: {{@root.theme.palette.redDark}};
41 }
42 ul.template--itdrift .themeTitleGreen{
43 display: flex;
44 /* font-size: 16px;
45 font-weight: bold; */
46 margin-bottom: 5px;
47 color: {{@root.theme.palette.green}};
48 }
49 ul.template--itdrift .themeTitleIcon {
50 margin-top: 3px;
51 margin-right: 7px;
52 }
53 ul.template--itdrift .themeContent {
54 margin-bottom: 5px;
55 color: {{@root.theme.palette.themeDarker}};
56 }
57 span.themeTitleRed + pnp-collapsible div[role="rowgroup"] span.themeContent, span.themeTitleRed + pnp-collapsible span.themeUser,
58 span.themeTitleGreen + pnp-collapsible div[role="rowgroup"] span.themeContent, span.themeTitleGreen + pnp-collapsible span.themeUser
59 {
60 margin-left:-24px;
61 display: block;
62 }
63 span.themeTitleRed + pnp-collapsible {
64 margin-left: 24px;
65 margin-top: -24px;
66 }
67 span.themeTitleGreen + pnp-collapsible {
68 margin-left: 70px;
69 margin-top: -26px;
70 }
71 span.themeTitleGreen + pnp-collapsible span.themeContent, span.themeTitleGreen + pnp-collapsible span.themeUser {
72 margin-left: -70px;
73 }
74 span.themeTitleRed, span.themeTitleRed + pnp-collapsible{
75 color: {{@root.theme.palette.redDark}};
76 }
77
78 span.themeTitleGreen, span.themeTitleGreen + pnp-collapsible{
79 color: {{@root.theme.palette.green}};
80 }
81 div[role="menubar"] > span, .solvedprefix {
82 font-size: 16px;
83 font-weight: bold;
84 }
85 div[role="rowgroup"] span.themeContent, span.themeUser{
86 font-size: 14px;
87 font-weight: normal;
88 }
89 .template--header{
90 font-size: 20px;
91 color: {{@root.theme.palette.themePrimary}};
92 font-weight: 600;
93 }
94
95
96 </style>
97<!--<h4 class="template--header">Aktuelt på kontoret</h4>-->
98
99 <div class="template">
100
101 {{#if @root.properties.showSelectedFilters}}
102 <pnp-selectedfilters
103 data-filters="{{JSONstringify filters.selectedFilters 2}}"
104 data-filters-configuration="{{JSONstringify filters.filtersConfiguration 2}}"
105 data-instance-id="{{filters.instanceId}}"
106 data-operator="{{filters.filterOperator}}"
107 data-theme-variant="{{JSONstringify @root.theme}}"
108 ></pnp-selectedfilters>
109 {{/if}}
110<!--
111 <div class="template--header">
112 {{#if @root.properties.showResultsCount}}
113 <div class="template--resultCount">
114 <label class="ms-fontWeight-semibold">{{getCountMessage @root.data.totalItemsCount @root.inputQueryText}}</label>
115 </div>
116 {{/if}}
117
118 <div class="template--sort">
119 <pnp-sortfield
120 data-fields="{{JSONstringify @root.properties.dataSourceProperties.sortList}}"
121 data-default-selected-field="{{sort.selectedSortFieldName}}"
122 data-default-direction="{{sort.selectedSortDirection}}"
123 data-theme-variant="{{JSONstringify @root.theme}}">
124 </pnp-sortfield>
125 </div>
126 </div> -->
127
128
129 <ul class="template--itdrift">
130 {{#each data.items as |item|}}
131
132 <pnp-select
133 data-enabled="{{@root.properties.itemSelectionProps.allowItemSelection}}"
134 data-index="{{@index}}"
135 data-is-selected="{{isItemSelected @root.selectedKeys @index}}">
136
137 <template id="content">
138 <li>
139 <span class="themeMeta">{{getDate (slot item @root.slots.StartDate) "D. MMMM HH:mm" 0 true}} | {{slot item @root.slots.Topic}}</span>
140
141 {{#eq (slot item @root.slots.Critical) 'True;1'}}
142 {{#eq (slot item @root.slots.Solved) '0'}}
143 <span class="themeTitleRed"><span class="themeTitleIcon"> <pnp-icon data-name="shieldalert" aria-hidden="true"></pnp-icon></span></span>
144
145 {{/eq}}
146 {{#eq (slot item @root.slots.Solved) '1'}}
147 <span class="themeTitleGreen"><span class="themeTitleIcon"> <pnp-icon data-name="SkypeCircleCheck" aria-hidden="true"></pnp-icon></span></span>
148 {{/eq}}
149 {{/eq}}
150
151 {{#eq (slot item @root.slots.Critical) 'False;0'}}
152 {{#eq (slot item @root.slots.Solved) '0'}}
153 <span class="themeTitle"> </span>
154 {{/eq}}
155 {{#eq (slot item @root.slots.Solved) '1'}}
156 <span class="themeTitleGreen"><span class="themeTitleIcon"> <pnp-icon data-name="SkypeCircleCheck" aria-hidden="true"></pnp-icon></span><span class="solvedprefix">(Løst)</span></span>
157 {{/eq}}
158 {{/eq}}
159 <pnp-collapsible data-group-name="{{slot item @root.slots.Title}}" data-default-collapsed="true">
160 <template id="collapsible-content">
161 <span class="themeContent">{{{slot item @root.slots.Summary}}}</span>
162 </template>
163 <template id="collapsible-footer">
164 <span class="themeUser"><strong>Ansvarlig: </strong> {{itemAt (split (slot item @root.slots.Responsible) "|") 1}}</span>
165 </template>
166 </pnp-collapsible>
167 <!-- <span class="themeContent">{{slot item @root.slots.Summary}}</span>
168 <span class="themeUser"><strong>Ansvarlig: </strong> {{itemAt (split (slot item @root.slots.Responsible) "|") 1}}</span> -->
169 </li>
170 <!-- {{#> resultTypes item=item}}
171 {{!-- The block below will be used as default item template if no result types matched --}}
172 <li>
173 <pnp-iconfile class="icon" data-extension="{{slot item @root.slots.FileType}}" data-theme-variant="{{JSONstringify @root.theme}}"></pnp-iconfile>
174 <span class="example-themePrimary">{{slot item @root.slots.Title}}</span>
175 </li>
176 {{/resultTypes}} -->
177 </template>
178
179 </pnp-select>
180
181 {{/each}}
182 </ul>
183 </div>
184
185 {{#if @root.properties.paging.showPaging}}
186 <pnp-pagination
187 data-total-items="{{@root.data.totalItemsCount}}"
188 data-hide-first-last-pages="{{@root.properties.paging.hideFirstLastPages}}"
189 data-hide-disabled="{{@root.properties.paging.hideDisabled}}"
190 data-hide-navigation="{{@root.properties.paging.hideNavigation}}"
191 data-range="{{@root.properties.paging.pagingRange}}"
192 data-items-count-per-page="{{@root.properties.paging.itemsCountPerPage}}"
193 data-current-page-number="{{@root.paging.currentPageNumber}}"
194 >
195 </pnp-pagination>
196 {{/if}}
197
198</content>
199
200<content id="placeholder-content">
201
202 <style>
203
204 .placeholder .icon {
205 width: 20px;
206 height: 16px;
207 margin-right: 5px;
208 }
209
210 .placeholder ul {
211 list-style: none;
212 }
213
214 .placeholder ul li {
215 display: flex;
216 align-items: center;
217 padding: 8px;
218 }
219 </style>
220
221 <div class="placeholder">
222 <ul>
223 {{#times @root.properties.paging.itemsCountPerPage}}
224 <li>
225 <div class="icon placeholder--shimmer"></div>
226 <span class="placeholder--shimmer placeholder--line" style="width: 60%"></span>
227 </li>
228 {{/times}}
229 </ul>
230 </div>
231</content>
Det der driller#
- Ja/nej-felter kommer ikke ud som true og false. Skabelonen sammenligner
Criticalmed'True;1'og'False;0'ogSolvedmed'1'og'0', fordi det var de værdier, mine slots gav. Kommer der ingen ikoner frem, er det værd at se efter, hvad slottene faktisk returnerer. - Et personfelt er én lang streng. Værdierne er adskilt af
|, og visningsnavnet er andet led. DerforitemAt (split ... "|") 1. - En ikke-kritisk, uløst meddelelse får intet ikon — bare titlen. Det er med vilje: den skal ikke råbe.
- Margenerne er skruet på plads i hånden. De negative
margin-leftpå -24px og -70px passer til ikonet og til teksten “(Løst)”. Skiftes ikon eller tekst ud, flytter teksten sig.