App Marketplace
Expand Liferay's portfolio through apps from our partner and developer ecosystems to enhance your digital transformation.
No facets were found.
An error occurred while processing the template.
The following has evaluated to null or missing: ==> channel.items[0] [in template "3192443#3192485#18426537" at line 113, column 30] ---- Tip: It's the final [] step that caused this error, not those before it. ---- Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?? ---- ---- FTL stack trace ("~" means nesting-related): - Failed at: #assign channelId = channel.items[0].id [in template "3192443#3192485#18426537" at line 113, column 9] ----
1<style type="text/css">
2 color: var(--black);
3 }
4
5 .lfr-layout-structure-item-com-liferay-site-navigation-breadcrumb-web-portlet-sitenavigationbreadcrumbportlet {
6 background: #ffffff;
7 border-radius: 10px;
8 height: 40px;
9 padding: 0px 16px;
10 }
11
12 .adt-apps-search-results .card-image-title-container .image-container {
13 height: 3rem;
14 }
15
16 .adt-apps-search-results .card-image-title-container .title-container {
17 word-break: break-word;
18 word-wrap: break-word;
19 }
20
21 .adt-apps-search-results .cards-container .app-search-results-card .card-image-title-container .image-container .app-search-image {
22 height: 48px;
23 object-fit: contain;
24 width: 48px;
25 }
26
27 .adt-apps-search-results .labels .category-label-remainder:hover .category-names {
28 display: block;
29 }
30
31 .app-search-results-card {
32 border-radius: 10px;
33 border: 1px solid #E7EFFF;
34 display: flex;
35 height: 298px;
36 padding: 16px;
37 }
38
39 .banner__product-tag {
40 background-color: #e6ebf5;
41 color: #1c3667;
42 font-size: 0.8125rem;
43 white-space: nowrap;
44 width: fit-content;
45 }
46
47 .cards-container {
48 display: grid;
49 grid-column-gap: 1rem;
50 grid-row-gap: 1.5rem;
51 grid-template-columns: repeat(3, minmax(0, 1fr));
52 }
53
54 .card-image-title-container {
55 height: 48px;
56 margin-bottom: 18px;
57 }
58
59 .developer-name {
60 color: #54555F;
61 font-size: 13px;
62 font-weight: 400;
63 line-height: 16px;
64 }
65
66 .title-container {
67 font-size: 18px;
68 font-weight: 600;
69 line-height: 20px;
70 }
71
72 @media screen and (max-width: 599px) {
73 .adt-apps-search-results .cards-container {
74 grid-column-gap: .5rem;
75 grid-row-gap: .5rem;
76 grid-template-columns: 293px;
77 justify-content: center;
78 }
79
80 .adt-apps-search-results .app-search-results-card {
81 height: 281px;
82 }
83 }
84
85 @media screen and (min-width:600px) and (max-width: 899px) {
86 .adt-apps-search-results .cards-container {
87 grid-column-gap: .5rem;
88 grid-row-gap: 1.5rem;
89 grid-template-columns: repeat(2, minmax(0, 1fr));
90 }
91 }
92</style>
93
94<#if searchContainer?has_content>
95 <div class="color-neutral-3 d-md-block d-none pb-4 pt-2">
96 <strong class="color-black">
97 ${searchContainer.getTotal()}
98 </strong>
99 Applications Available
100 </div>
101</#if>
102
103<#if themeDisplay?has_content>
104 <#assign scopeGroupId = themeDisplay.getScopeGroupId() />
105</#if>
106
107<#assign
108 channel = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?accountId=-1&filter=name eq 'Marketplace Channel' and siteGroupId eq '${scopeGroupId}'")
109 productThumbnail1 ="/o/commerce-media/default/?groupId=${scopeGroupId}"
110/>
111
112<#if channel?has_content>
113 <#assign channelId = channel.items[0].id />
114</#if>
115
116<div class="adt-apps-search-results">
117 <div class="cards-container pb-6">
118 <#if entries?has_content>
119 <#list entries as entry>
120 <#if entry?has_content>
121 <#assign
122 portalURL=portalUtil.getLayoutURL(themeDisplay)
123 productId=entry.getClassPK() + 1
124 product=restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/"+ channelId +"/products/"+ productId +"?accountId=-1&images.accountId=-1&nestedFields=productSpecifications,categories,images")
125 productImage=(product.images![]
126 )?filter(item -> item.tags?seq_contains("app icon"))![]
127 remainingCategoriesText = []
128 />
129 <#if product.categories?has_content && product.productSpecifications?has_content>
130 <#assign
131 productCategories = product.categories?filter(productCategory -> productCategory.vocabulary=="marketplace-app-category")![]
132 categoriesListSize = productCategories?size-1
133 productSpecifications = product.productSpecifications![]
134 />
135 </#if>
136
137 <#if product.name?has_content>
138 <#assign productName = product.name />
139 <#else>
140 <#assign productName ="" />
141 </#if>
142
143 <#if product.description?has_content>
144 <#assign productDescription = stringUtil.shorten(htmlUtil.stripHtml(product.description!""), 150, "...") />
145 <#else>
146 <#assign productDescription = "" />
147 </#if>
148
149 <#if product.urls?has_content>
150 <#assign productURL = portalURL?replace("home", "p") + "/" + product.urls.en_US />
151 <#else>
152 <#assign productURL = "" />
153 </#if>
154
155 <#if productImage?has_content>
156 <#assign productThumbnail = productImage[0].src?split("/o") />
157 <#if productThumbnail?has_content && productThumbnail?size gte 2>
158 <#assign productThumbnail1 = "/o/${productThumbnail[1]}" !"" />
159 </#if>
160
161 <#else>
162 <#if product.urlImage?has_content>
163 <#assign productThumbnail = product.urlImage?split("/o") />
164 <#if productThumbnail?has_content && productThumbnail?size gte 2>
165 <#assign productThumbnail1 = "/o/${productThumbnail[1]}" !"" />
166 </#if>
167 </#if>
168 </#if>
169
170 <a class="app-search-results-card bg-white border-radius-medium d-flex flex-column mb-0 text-dark text-decoration-none" href=${productURL}>
171 <div class="align-items-center card-image-title-container d-flex">
172 <div class="image-container mr-2 rounded">
173 <img alt="${productName}" class="app-search-image" src="${productThumbnail1}" />
174 </div>
175
176 <div>
177 <div class="title-container">
178 ${productName}
179 </div>
180
181 <#if productSpecifications?has_content>
182 <#assign productDeveloperName = productSpecifications?filter(item -> item.specificationKey == "developer-name") />
183 <#list productDeveloperName as developerNameItem>
184 <#if developerNameItem.value?has_content>
185 <#assign developerName = developerNameItem.value />
186 <#else>
187 <#assign developerName = "" />
188 </#if>
189
190 <div class="developer-name mt-1">
191 ${developerName}
192 </div>
193 </#list>
194 </#if>
195 </div>
196 </div>
197
198 <div class="d-flex flex-column font-size-paragraph-small h-100 justify-content-between">
199 <div class="font-weight-normal mb-2 text-break">
200 ${productDescription}
201 </div>
202
203 <div class="d-flex flex-column">
204 <#if productSpecifications?has_content>
205 <#assign productPriceModels = productSpecifications?filter(item -> item.specificationKey == "price-model") />
206 <#list productPriceModels as productPriceModel>
207 <#if productPriceModel.value?has_content>
208 <#assign priceModel = productPriceModel.value />
209 <#else>
210 <#assign priceModel = "" />
211 </#if>
212
213 <div class="font-weight-semi-bold mb-2 mt-1 text-capitalize">
214 ${priceModel}
215 </div>
216 </#list>
217 </#if>
218
219 <#if productCategories?has_content>
220 <#assign
221 principalCategory = productCategories[0]
222 remainingCategories = productCategories?filter(category -> category.name != principalCategory.name)
223 />
224
225 <#list remainingCategories as category>
226 <#assign remainingCategoriesText = remainingCategoriesText + [category.name] />
227 </#list>
228 </#if>
229
230 <#if principalCategory?has_content >
231 <div class="d-flex">
232 <span class="banner__product-tag rounded py-1 px-2 mr-2" title="${principalCategory.name}">
233 ${principalCategory.name}
234 </span>
235 <#if categoriesListSize?has_content && remainingCategoriesText?has_content>
236 <span class="banner__product-tag rounded py-1 px-2" title="${remainingCategoriesText?join('\n')}">
237 + ${categoriesListSize}
238 </span>
239 </#if>
240 </div>
241 </#if>
242 </div>
243 </div>
244 </a>
245 </#if>
246 </#list>
247 </#if>
248 </div>
249</div>
Welcome, you are now a member of