> ## Documentation Index
> Fetch the complete documentation index at: https://doc.lucidworks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FAQ

export const LwTemplate = ({title = "Key questions to get you started", icon = "sparkles", cta = "Powered by Agent Studio", linkHref = "https://lucidworks.com/demo/?utm_source=docs&utm_medium=referral&utm_campaign=docs_cta_ai"}) => {
  const [isLoaded, setIsLoaded] = useState(false);
  useEffect(() => {
    const timer = setTimeout(() => {
      setIsLoaded(true);
    }, 500);
    return () => clearTimeout(timer);
  }, []);
  return <div className="lw-template-container">
      <Card title={title} icon={icon}>
        {isLoaded && <span dangerouslySetInnerHTML={{
    __html: `<lw-template id="a029c1a9-28be-427e-b0e1-5d918920246a"></lw-template
            >`
  }} />}
        <Link href={linkHref} className="agent-studio-link text-left text-gray-600 gap-2 dark:text-gray-400 text-sm font-medium flex flex-row items-center hover:text-primary dark:hover:text-primary-light group-hover:text-primary group-hover:dark:text-primary-light">Powered by Lucidworks Agent Studio</Link>
      </Card>
    </div>;
};

[old doc.lw link]: https//doc.lucidworks.com/app-studio/4.2/3133

[localhost link]: http://localhost:3000/docs/5/app-studio/reference/faq/overview

[mintlify link]: https://doc.lucidworks.com/docs/5/app-studio/reference/faq/overview

The articles in this section answer frequently asked questions about various aspects and functionality of App Studio.

<LwTemplate />

## More information

See the following how-to articles:

* **Adding Twitter and YouTube Results**
* **Changing the Color Scheme**
* **Changing the Logo**
* **Dynamically Adding Icons to Fields**
* **Removing the Security Module**
* **Setting Up a Mock Platform Response**

<AccordionGroup>
  <Accordion title="Adding Twitter and YouTube Results">
    {/* // Update how-to header information */}

    {/* // formatted */}

    To add Twitter and Youtube results to the page, you must follow five steps.

    ### 1. Get the platform authentication keys

    To get Twitter oAuth keys visit the [Twitter dev site](https://docs.x.com/fundamentals/developer-apps#overview) for Single User OAuth tokens.
    To get a Youtube API key visit [the Google Developers Console](https://console.cloud.google.com/apis/library/youtube.googleapis.com?project=lw-support-team), register an application and generate keys.

    ### 2. Add the dependencies of the YouTube and Twitter platform.

    Add the following dependencies to the `/pom.xml` file at the root of your project

    ```xml theme={"dark"}
    <dependency>
        <groupId>twigkit</groupId>
        <artifactId>twigkit.youtube</artifactId>
        <version>${project.parent.version}</version>
        <exclusions>
            <exclusion>
                <groupId>com.fasterxml.jackson.core</groupId>
                <artifactId>jackson-core</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>twigkit</groupId>
        <artifactId>twigkit.twitter</artifactId>
        <version>${project.parent.version}</version>
    </dependency>
    ```

    If you are running a local server, then you must restart. Restarting the app-studio script pulls down any new library dependencies.

    ### 3. Add configuration files

    Because both the Youtube and Twitter platforms take various oAuth and API keys, it is advised to keep these in centralized configuration files. Create these files:

    #### src/main/resources/conf/platforms/twitter.conf

    ```yaml theme={"dark"}
    name: twigkit.search.twitter.Twitter
    oAuthConsumerKey: XXXXXXXXXX
    oAuthConsumerSecret: XXXXXXXXXX
    oAuthAccessToken: XXXXXXXXXX
    oAuthAccessSecret: XXXXXXXXXX
    ```

    #### src/main/resources/conf/platforms/youtube.conf

    ```yaml theme={"dark"}
    name: twigkit.web.youtube.YouTube
    apiKey: XXXXXXXXXX
    channelId: XXXXXXXXXX
    ```

    ### 4. Configure platform, query and response in your View

    Next configure a platform, query, and response at the top of the page, as you would do with a standard search. You can copy/paste the below:

    ```html theme={"dark"}
    <!-- YouTube -->
    <search:platform var="youtubePlatform" conf="platforms.fusion.youtube"></search:platform>
    <search:query var="youtubeQuery" parameters="*" results-per-page="12"></search:query>
    <search:response var="youtubeResponse" platform="youtubePlatform" query="youtubeQuery"></search:response>
    <!-- Twitter -->
    <search:platform var="twitterPlatform" conf="platforms.fusion.twitter"></search:platform>
    <search:query var="twitterQuery" parameters="*" results-per-page="12"></search:query>
    <search:response var="twitterResponse" platform="twitterPlatform" query="twitterQuery"></search:response>
    ```

    You can adjust the `results-per-page` to taste based on the number of results you want.
    Currently both queries are set to search based on the current query (`parameters="*"`). Set this to an empty string to return just the latest videos/tweets accordingly.

    ### 5. Show results on the page

    Add the following code to the same page where the platform, query and response were defined in the previous step:

    ```html theme={"dark"}
    <!-- YouTube results -->
    <search:result-list response="youtubeResponse">
        <search:result>
            <search:field name="snippet.title" styling="title"></search:field>
            <iframe width="400" height="300" id="player" ng-src="{{'https://www.youtube.com/embed/' + result.id }}" frameborder="0" ></iframe>
        </search:result>
    </search:result-list>
    <!-- Twitter results -->
    <search:result-list response="twitterResponse">
        <search:result>
            <search:field name="text" styling="title"></search:field>
            <search:field name="user.screen_name" styling="description"></search:field>
        </search:result>
    </search:result-list>
    ```

    **If embedding a YouTube video player** like in the above example, you must also add the YouTube domain as a trusted site. To do this, add the following code to the `/src/main/webapp/search/app/app.js` file after the controller definitions:

    ```javascript theme={"dark"}
    .config(function($sceDelegateProvider) {
        $sceDelegateProvider.resourceUrlWhitelist([
            'self',
            'https://www.youtube.com/embed/**']);
    });
    ```

    After adding the above block, the entire `/src/main/webapp/search/app/app.js` file should look similar to the following:

    ```javascript theme={"dark"}
    'use strict';
    const BUILD_PATH = '/dist/';
    const basePath = (document.getElementsByTagName('base')[0] || {href: ''}).href;
    __webpack_public_path__ = window.__webpack_public_path__ = basePath.replace(/\/$/, '') + BUILD_PATH;
    import '../../styles/twigkit.less';
    import {RoutesModule} from './routes/routes.module.js';
    import {SearchController} from './controllers/search.controller';
    import {LoginController} from "./controllers/login.controller";
    import {ServicesModule} from "./services/services.module";
    import {DirectivesModule} from "./directives/directives.module.js";
    let appModule = angular
        .module('appStudioSearch', [
            , 'ui.router'
            , 'ngAnimate'
            , 'lightning'
            , RoutesModule.name
            , DirectivesModule.name
            , ServicesModule.name
        ])
        .run(['$rootScope', '$window', '$twigkit', '$location', function ($rootScope, $window, $twigkit, $location ) {
            $rootScope.$on('response_response_error', function (response) {
                $rootScope.showErrorModal = true;
            });
            $rootScope.closeErrorModal = function () {
                $rootScope.showErrorModal = false;
            }
            $rootScope.$on('httpInterceptorError', function (event, error) {
                /**
                 * The tests here must match the tests in
                 * twigkit.security.springsecurity.matchers.NonAjaxRequestMatcher::matches
                 */
                if ((error.status == '401' || error.status == '403') &&
                    (error.config.url.indexOf('twigkit/api') !== -1 ||
                        error.config.url.indexOf('twigkit/services') !== -1 ||
                        error.config.url.indexOf('twigkit/secure/services') !== -1 ||
                        error.config.url.indexOf('views/') !== -1
                    )) {
    {/*                 // Error was a 403 and URL was a non-user facing path - redirect to login */}
                    $rootScope.$broadcast('twigkitApi403', { error: error, url: $location.url() });
                    var loginPath = $twigkit.getContextPath('/') + $twigkit.getConstant('loginPage', 'login/');
    {/*                 // If we are already on the login page, do not redirect */}
                    if ($window.location.pathname !== loginPath ) {
                        $window.location.href = loginPath;
                    }
                }
            });
        }])
        .controller('searchCtrl', SearchController)
        .controller('loginCtrl', LoginController)
        .config(function($sceDelegateProvider) {
            $sceDelegateProvider.resourceUrlWhitelist([
                'self',
                'https://www.youtube.com/embed/**']);
        });
    angular.bootstrap(document, ['appStudioSearch']);
    ```
  </Accordion>

  <Accordion title="Changing the Color Scheme">
    {/* // Update how-to header information */}

    {/* // formatted */}

    The principle colors used in the theme are define at the top of `styles/includes/theme.less`:

    ```css theme={"dark"}
    @color-primary: #273142; // Brand Primary

    @color-secondary: #202020; // Utility Black (Non selectable)
    @color-tertiary: #4CAF50; // Utility Green Links (Non selectable)
    @color-quaternary: #f7f7f7; // Utility Grey page bg
    @color-quinary: #d9d9d9; // Utility Grey borders

    @color-white: #fff;
    @color-black: #000;

    @link-color: #498fe2;
    ```

    Change the `@color-primary`, `@color-secondary`, and `@color-tertiary` variables to the desired color.

    For more precise control, the color of individual elements can be controlled in the styling partial stylesheets found in `styles/includes/`.
  </Accordion>

  <Accordion title="Changing the Logo">
    {/* // Update how-to header information */}

    {/* // formatted */}

    **To change the logo**

    1. Prepare both a large and a small version of the logo. The large version should be at least 400 pixels wide; the small version should be 42 pixels tall, and no wider than 225 pixels. It is recommended to save the logos as transparent 24-bit PNGs. Place the two image files in the `assets` folder.
    2. Update the image path in `webapp/login.jsp` (if present) for the large version of the logo. You can also adjust the width of the image tag at the same time.
    3. Update the path in the `<layout:logo>` tag which is usually placed within `webapp/views/partials/header.tpl.html` for the small version of the logo.
  </Accordion>

  <Accordion title="Dynamically Adding Icons to Fields">
    ## Dynamically Adding An Icon To A Field

    Sometimes you might want to dynamically prepend a field with an image or an icon depending on the value of a field or variable.

    This can easily be accomplished using a `class` attribute referencing a little bit of CSS, defined in your styles/includes/custom.less.

    For example, to dynamically add a 'type' image before a field:

    ```css theme={"dark"}
        [class*="field-icon-"] {
            position: relative;
            margin-left: 2em;
        }

        [class*="field-icon-"]:before {
            position: absolute;
            left: -30px;
            bottom: 14px;
            background-size: 20px 20px;
            display: inline-block;
            width: 20px;
            height: 20px;
            content: " ";
        }

        .field-icon-pdf:before {
            background-image: url('../assets/icon-pdf.png');
        }

        .field-icon-doc:before {
            background-image: url('../assets/icon-doc.png');
        }
    ```

    And in your view, use:

    ```xml wrap theme={"dark"}
    <search:field name="type" ng-class="field-icon-{{result | fields:'type' | actual}}"></search:field>
    ```

    The CSS can easily be extended or adapted to add more icon types or change the position and size of the icon.
  </Accordion>

  <Accordion title="Removing the Security Module">
    These steps are required to remove the [security module](/docs/5/fusion/dev-portal/appkit/reference/modules/security/authentication/overview) from a project.

    <Check>You must also remove any other module that depends on the security module such as the [Collaboration module](/docs/5/fusion/dev-portal/appkit/reference/modules/collaboration/overview).</Check>

    ### 1. POM

    Remove the security module dependency (and any other module that requires security) from `pom.xml`:

    ```xml theme={"dark"}
    <dependency>
        <groupId>twigkit</groupId>
        <artifactId>twigkit.security.provider.spring-security</artifactId>
        <version>${project.parent.version}</version>
    </dependency>
    ```

    ### 2. Configuration

    Replace the security module specified in conf/resources/security/security.conf with `type: generic`

    ### 3. Web.xml application descriptor

    You must remove any reference to the Spring security filters and listeners from your `web.xml` application descriptor. For example:

    ```xml theme={"dark"}
    <!-- Spring Security -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-security.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    ```

    ### 4. Java code

    If you are using any classes from the security Module in Java code, remove references to these. For example, if the `SecurityModule` is installed in a custom module, you would remove these references:

    ```java theme={"dark"}
    import twigkit.security.springsecurity.SpringSecurityModule;

    install(new SpringSecurityModule());
    ```

    ### 5. Security configuration files

    Optionally, remove the `spring-security.xml` configuration file.
  </Accordion>

  <Accordion title="Setting Up a Mock Platform Response">
    In some cases it can be difficult to access a search platform. In these situations, it can be useful to work against a static response in the form of a file containing a typical search response (usually as XML).

    This is not a recommended method for developing a fully featured search application from start to finish, because it is impossible to emulate the dynamic nature of a live platform. However this is useful in a number of situations including:

    * Where networking or security considerations prevent access to the platform
    * Debugging issues in an application where it is necessary to recreate a specific type of response
    * Initial development phases where access to a live platform with realistic data is unavailable
    * Deterministic test conditions (this could be for unit tests as well as any other form of manual or automated testing)

    ### How to set up a mock platform

    A few simple steps are required to run an application against a 'mock' response:

    1. Create a mock response file by saving the XML from a query issued directly against the platform, or request one from someone who can access a platform instance. This should represent the type of response you want to mock. See this example of a Solr XML response:
       ```xml expandable theme={"dark"}
       <?xml version="1.0" encoding="UTF-8"?>
       <response>
           <lst name="responseHeader">
               <int name="status">0</int>
               <int name="QTime">24</int>
               <lst name="params">
               <str name="spellcheck">true</str>
               <str name="facet">true</str>
               <str name="indent">true</str>
               <str name="facet.limit">10</str>
               <str name="wt">xmk</str>
               <str name="rows">5</str>
               <str name="fl">*,score</str>
               <str name="start">0</str>
               <arr name="q">
                   <str>*:*</str>
               </arr>
               <str name="q.op">OR</str>
               <str name="facet.field">month</str>
               <str name="qt">/prodover</str>
               <str name="fq">category:Clothing</str>
               </lst>
           </lst>
           <result name="response" numFound="21111" start="0" maxScore="1.0">
               <doc>
               <str name="category">Clothing</str>
               <str name="p_image_path_1_s">/s/c/sc1402sep26pictga10015.jpg</str>
               <int name="p_id_i">356980</int>
               <date name="p_date">2014-10-07T00:00:00Z</date>
               <str name="p_name">Generic T-Shirt</str>
               <float name="p_price">552.63</float>
               <arr name="colors">
                   <str>Black</str>
                   <str>White</str>
                   <str>Green</str>
               </arr>
               <long name="_version_">1486360119259168768</long>
               <float name="score">1.0</float>
               </doc>
               <doc>
               <str name="category">Clothing</str>
               <str name="p_image_path_1_s">/s/c/sc1402sep26pictga10015.jpg</str>
               <int name="p_id_i">356980</int>
               <date name="p_date">2014-10-07T00:00:00Z</date>
               <str name="p_name">Generic T-Shirt</str>
               <float name="p_price">552.63</float>
               <arr name="colors">
                   <str>Black</str>
                   <str>White</str>
                   <str>Green</str>
               </arr>
               <long name="_version_">1486360119259168768</long>
               <float name="score">1.0</float>
               </doc>
               <doc>
               <str name="category">Clothing</str>
               <str name="p_image_path_1_s">/s/c/sc1402sep26pictga10015.jpg</str>
               <int name="p_id_i">356980</int>
               <date name="p_date">2014-10-07T00:00:00Z</date>
               <str name="p_name">Generic T-Shirt</str>
               <float name="p_price">552.63</float>
               <arr name="colors">
                   <str>Black</str>
                   <str>White</str>
                   <str>Green</str>
               </arr>
               <long name="_version_">1486360119259168768</long>
               <float name="score">1.0</float>
               </doc>
               <doc>
               <str name="category">Clothing</str>
               <str name="p_image_path_1_s">/s/c/sc1402sep26pictga10015.jpg</str>
               <int name="p_id_i">356980</int>
               <date name="p_date">2014-10-07T00:00:00Z</date>
               <str name="p_name">Generic T-Shirt</str>
               <float name="p_price">552.63</float>
               <arr name="colors">
                   <str>Black</str>
                   <str>White</str>
                   <str>Green</str>
               </arr>
               <long name="_version_">1486360119259168768</long>
               <float name="score">1.0</float>
               </doc>
               <doc>
               <str name="category">Clothing</str>
               <str name="p_image_path_1_s">/s/c/sc1402sep26pictga10015.jpg</str>
               <int name="p_id_i">356980</int>
               <date name="p_date">2014-10-07T00:00:00Z</date>
               <str name="p_name">Generic T-Shirt</str>
               <float name="p_price">552.63</float>
               <arr name="colors">
                   <str>Black</str>
                   <str>White</str>
                   <str>Green</str>
               </arr>
               <long name="_version_">1486360119259168768</long>
               <float name="score">1.0</float>
               </doc>
           </result>
           <lst name="facet_counts">
               <lst name="facet_queries"/>
               <lst name="facet_fields">
               <lst name="month">
                   <int name="November">9140</int>
                   <int name="October">7936</int>
                   <int name="September">7215</int>
                   <int name="August">7088</int>
                   <int name="July">6878</int>
                   <int name="June">5238</int>
                   <int name="May">4351</int>
                   <int name="April">4207</int>
                   <int name="March">3593</int>
                   <int name="February">3002</int>
               </lst>
               </lst>
               <lst name="facet_dates"/>
               <lst name="facet_ranges"/>
               <lst name="facet_intervals"/>
           </lst>
       </response>
       ```
    2. Copy the XML file into your project to:
       ```
       src/main/webapp/WEB-INF/pages/mock-response.xml
       ```
    3. Modify the [URL rules configuration](/docs/4/app-studio/concepts/overview/routing-and-url-rules) to add a rule that emulates the path at which the search platform interface exists. For example:
       ```xml theme={"dark"}
           <rule>
               <from>^/login/</from>
               <to last="true">/login.jsp</to>
           </rule>

           <rule>
               <from>^/login</from>
               <to last="true">/login.jsp</to>
           </rule>

           <rule match-type="wildcard">
               <name>Ignore files on URL path.</name>
               <from>/**.*</from>
               <to last="true">/$0</to>
           </rule>
           <rule>
               <from>^/mock-response/</from>
               <to last="true">/WEB-INF/pages/mock-response.xml</to>
           </rule>
           <rule match-type="wildcard">
               <name>HTML 5 URL Rewrite</name>
               <from>/**</from>
               <to last="true">/index.jsp</to>
           </rule>
       ```
    4. Configure the platform host to point to the relevant URL:
       ```
       name: twigkit.search.solr.Solr
       result-id-field: url
       host: http://localhost:8080/mock-response
       defaultQuery: test
       ```

    The application is now configured to use this response XML file instead of a live platform whenever a query is issued. Obviously this will mean the same result set is retrieved no matter how the query is modified through the user interface. It is possible to mock different result sets by adding more complex URL rules to intercept the different parameters modified by interacting with Appkit UI components, however this is generally not recommended.
  </Accordion>
</AccordionGroup>
