UNPKG

mongo-express

Version:
552 lines (526 loc) 20 kB
{% extends 'layout.html' %} {% block title %}{{ collectionName }}{% endblock %} {% block breadcrumb %} <li class="nav-item"> <a class="nav-link px-1" href="{{ dbUrl }}">Database:</a> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle px-1" href="#" role="button" aria-controls="navbarDatabaseDropdown" data-bs-target="#navbarDatabaseDropdown" data-bs-toggle="dropdown" aria-expanded="false"> {{ dbName }} </a> <ul id="navbarDatabaseDropdown" class="dropdown-menu scrollable-ul"> {% for db in databases %} <li><a class="dropdown-item" href="{{ baseHref }}db/{{ db | url_encode }}/">{{ db }}</a></li> {% endfor %} </ul> </li> <li class="nav-item"> <a class="nav-link px-1" href="{{ collectionUrl }}">Collection:</a> </li> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle px-1" href="#" role="button" aria-controls="navbarCollectionDropdown" data-bs-target="#navbarCollectionDropdown" data-bs-toggle="dropdown" aria-expanded="false"> {{ collectionName }} </a> <ul id="navbarCollectionDropdown" class="dropdown-menu scrollable-ul"> {% for collection in collections %} <li><a class="dropdown-item" href="{{ dbUrl }}/{{ collection | url_encode }}">{{ collection }}</a></li> {% endfor %} </ul> </li> {% endblock %} {% block content %} {% if !settings.read_only %} <div class="btn-toolbar my-3" role="toolbar"> <button type="button" data-bs-toggle="modal" data-bs-target="#addDocument" class="btn btn-success btn-large me-1 m-1"> <i class="fas fa-plus"></i> New Document </button> <button type="button" data-bs-toggle="modal" data-bs-target="#addIndex" class="btn btn-success btn-large m-1"> <i class="fas fa-plus"></i> New Index </button> </div> {% endif %} <ul id="tabs" class="nav nav-pills nav-fill" role="tablist"> <li class="nav-item"> <a href="#simple" class="nav-link active" data-bs-toggle="tab"><i class="fa fa-tag"></i> Simple</a> </li> <li class="nav-item"> <a href="#advanced" class="nav-link" data-bs-toggle="tab"><i class="fa fa-tag"></i> Advanced</a> </li> </ul> <div id="my-tab-content" class="tab-content p-3"> <div class="tab-pane active" id="simple"> <form method="get" action="{{ collectionUrl }}"> {% for column in columns %} <input type="checkbox" name="sort[{{column}}]" class="d-none sort-{{column}}" {% if sort[column] %}value="{{sort[column]}}" checked="checked" {% endif %} /> {% endfor %} <div class="row"> <div class="col-sm-6 col-md-4 py-1"> <input style="width:100%;" class="input-medium form-control" type="text" id="key" name="key" placeholder="Key" title="Key" value="{{ key }}"> </div> <div class="col-sm-6 col-md-4 py-1"> <input style="width:100%;" class="input-medium form-control" type="text" id="value" name="value" placeholder="Value" title="Value" value="{{ value }}"> </div> <div class="col-sm-6 col-md-2 py-1"> <select name="type" class="form-control"> <option value="S" {% if type=='S' %}selected {% endif %}>String</option> <option value="R" {% if type=='R' %}selected {% endif %}>Regex</option> <option value="J" {% if type=='J' %}selected {% endif %}>JSON, bool</option> <option value="N" {% if type=='N' %}selected {% endif %}>Number</option> <option value="O" {% if type=='O' %}selected {% endif %}>ObjectId</option> <option value="U" {% if type=='U' %}selected {% endif %}>UUID (v4)</option> </select> </div> <div class="col-sm-6 col-md-2 d-grid py-1"> <button type="submit" class="btn btn-primary btn-block"> <i class="fa fa-search"></i> Find </button> </div> </div> </form> </div> <div class="tab-pane" id="advanced"> <form method="get" action="{{ collectionUrl }}"> {% for column in columns %} <input type="checkbox" name="sort[{{column}}]" class="d-none sort-{{column}}" {% if sort[column] %}value="{{sort[column]}}" checked="checked" {% endif %} /> {% endfor %} <div class="row"> <div class="col-sm-6 col-md-5 py-1"> <textarea class="input-medium form-control" style="width: 100%; height: 150px" id="query" name="query" placeholder="Query" title="Query">{{ query }}</textarea> </div> <div class="col-sm-6 col-md-5 py-1"> <textarea class="input-medium form-control" style="width: 100%; height: 150px" id="projection" name="projection" placeholder="Projection" title="Projection">{{ projection }}</textarea> </div> <div class="col-md-2 d-grid py-1"> <div class="form-check"> <input type="checkbox" class="form-check-input" id="runAggregate" name="runAggregate" title="Run Aggregate" {% if runAggregate %} checked="checked" {% endif %}> <label class="form-check-label" for="runAggregate">Aggregate query</label> </div> <button type="submit" class="btn btn-primary btn-block"> <i class="fa fa-search"></i> Find </button> </div> </div> </form> </div> </div> {% if !settings.read_only && !settings.no_delete && count > 0 %} <form id="deleteListForm" method="POST" class="my-3" action="{{ collectionUrl }}?key={{ key }}&value={{ value }}&type={{ type }}&query={{ query|default('{}') }}&projection={{ projection }}&runAggregate={{ runAggregate }}"> {# Router is smart enough to transform method=POST + _method=delete into actual HTTP DELETE, which is what we want #} <input type="hidden" name="_csrf" value="{{ csrfToken }}"> <input type="hidden" name="_method" value="delete"> <button type="button" data-bs-toggle="modal" data-bs-target="#deleteListModal" class="btn btn-danger btn-large btn-block"> <i class="fa fa-trash"></i> Delete all {{count}} documents retrieved </button> </form> {% endif %} <br /> <!-- Add Document Modal --> <div class="modal fade" id="addDocument" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <form id="addDocumentForm" method="post" action="{{ collectionUrl }}"> <input type="hidden" name="_csrf" value="{{ csrfToken }}"> <div class="modal-header"> <h2 class="modal-title">Add Document</h2> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body" id="document-modal-body"> <textarea id="document" name="document">{ "_id": ObjectId() }</textarea> </div> <div class="modal-footer"> <button type="submit" class="btn btn-success" onclick="return checkValidJSON({{ csrfToken }})"> <i class="fa fa-save"></i> Save </button> </div> </form> </div> </div> </div> <!-- End Add Document Modal --> <!-- Add Index Modal --> <div class="modal fade" id="addIndex" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <form id="addIndexForm" method="post" action="{{ dbUrl }}/addIndex/{{ collectionName | url_encode }}"> <input type="hidden" name="_csrf" value="{{ csrfToken }}"> <div class="modal-header"> <h2 class="modal-title">Add Indexes</h2> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body" id="index-modal-body"> <p> A document that contains the field and value pairs where the field is the index key. 1 for an ascending and -1 for a descending index. </p> <textarea id="index" name="index">{ "key": 1 }</textarea> </div> <div class="modal-footer"> <button type="submit" class="btn btn-success" onclick="return checkValidIndexJSON()"> <i class="fa fa-save"></i> Save </button> </div> </form> </div> </div> </div> <!-- End Add Index Modal --> {% if documents.length == 0 %} <p class="card"> No documents found. </p> {% else %} {% if pagination %} <nav class="navbar" aria-label="Page navigation"> <div class="nav navbar-nav mx-auto"> <div id="paginator-top"></div> </div> </nav> {% endif %} <div style="position: relative;"> <div class="fadeToWhite" id="fadeToWhiteID"></div> <div class="table-responsive tableWrapper"> <table class="table table-striped tableHeaderFooterBars"> <thead> {% for column in columns %} <th class="sorting-button" data-column="{{column}}" data-direction="{{sort[column]}}" title="Sort by {{column}}"> {{column}} {% if sort[column] == 1 %} <i class="fas fa-sort-up"></i> {% elseif sort[column] == -1 %} <i class="fas fa-sort-down"></i> {% endif %} </th> {% endfor %} </thead> {% for index, document in docs %} {% if document._id._bsontype == 'Binary' %} <tr id="doc-{{ index }}" onclick="loadDocument('{{ collectionUrl }}/{{ document._id | json | safe | url_encode }}?subtype={{ document._id.sub_type }}&skip={{skip}}')"> {% elseif document._id._bsontype == 'Long' %} <tr id="doc-{{ index }}" onclick="loadDocument('{{ collectionUrl }}/{{ document._id | longToString | safe | url_encode }}?skip={{skip}}')"> {% else %} <tr id="doc-{{ index }}" onclick="loadDocument('{{ collectionUrl }}/{{ document._id | json | safe | url_encode }}?skip={{skip}}')"> {% endif %} {% for column in columns %} <td> <div class="tableContent"> {% if !settings.read_only && !settings.no_delete && column === '_id' && collectionName !== 'system.indexes' %} <button class="btn btn-info" onclick="loadDocument('{{ collectionUrl }}/{{ document._id | json | safe | url_encode }}')"> <i class="fa fa-link"></i> </button> <form class="deleteButtonDocument" method="POST" style="display:inline;" action="{{ collectionUrl }}/{{ document._id | json | safe | url_encode }}?subtype={{ document._id.sub_type }}&skip={{ skip }}&key={{ key }}&value={{ value }}&type={{ type }}&query={{ query }}&projection= {{ projection }}"> <input type="hidden" name="_method" value="delete"> <input type="hidden" name="_csrf" value="{{ csrfToken }}"> <button type="submit" class="btn btn-danger"> <i class="fa fa-trash"></i> </button> </form> {% endif %} {% if document[column] | is_URL %} <a href="{{ document[column] }}" target="_blank" rel="noopener noreferrer">{{ document[column] }}</a> {% else %} {{ document[column] | stringDocIDs | to_display | safe }} {% endif %} </div> </td> {% endfor %} </tr> {% endfor %} </table> </div> </div> {% if pagination %} <nav class="navbar" aria-label="Page navigation"> <div class="nav navbar-nav mx-auto"> <div id="paginator-bottom"></div> </div> </nav> {% endif %} {% endif %} {% if !settings.read_only %} <div class="card mb-3"> <h2 class="card-header">Rename Collection</h2> <div class="card-body"> <form method="POST" action="{{ collectionUrl }}" class="form-inline"> <input type="hidden" name="_csrf" value="{{ csrfToken }}"> <input type="hidden" name="_method" value="put"> <div class="input-group"> <div class="input-group-prepend"> <span class="input-group-text">{{ dbName }} . </span> </div> <input type="text" class="form-control" id="collection" name="collection" placeholder="{{ collectionName }}"> <div class="input-group-append"> <button class="btn btn-primary" type="button"> <i class="fa fa-pen"></i> Rename </button> </div> </div> </form> </div> </div> {% endif %} <div class="card mb-3"> <h2 class="card-header">Tools</h2> <div class="card-body"> <div class="row"> {% if !settings.me_no_export %} <div class="col-sm-4 p-2 d-grid "> <a href="{{ dbUrl }}/export/{{ collectionName | url_encode }}?key={{ key }}&value={{ value }}&type={{ type }}&query={{ query | url_encode }}&projection= {{ projection | url_encode }}{% for k, v in sort %}&sort[{{ k }}]={{ v }}{% endfor %}" class="btn btn-warning btn-block text-white"> <i class="fa fa-download d-block"></i>Export Standard </a> </div> <div class="col-sm-4 p-2 d-grid "> <a href="{{ dbUrl }}/expArr/{{ collectionName | url_encode }}?key={{ key }}&value={{ value }}&type={{ type }}&query={{ query | url_encode }}&projection= {{ projection | url_encode }}{% for k, v in sort %}&sort[{{ k }}]={{ v }}{% endfor %}" class="btn btn-warning btn-block text-white"> <i class="fa fa-download d-block"></i>Export --jsonArray </a> </div> <div class="col-sm-4 p-2 d-grid "> <a href="{{ dbUrl }}/expCsv/{{ collectionName | url_encode }}?key={{ key }}&value={{ value }}&type={{ type }}&query={{ query | url_encode }}&projection= {{ projection | url_encode }}{% for k, v in sort %}&sort[{{ k }}]={{ v }}{% endfor %}" class="btn btn-warning btn-block text-white"> <i class="fa fa-download d-block"></i>Export --csv </a> </div> {% endif %} <div class="col-sm-4 p-2 d-grid "> <a href="{{ dbUrl }}/reIndex/{{ collectionName | url_encode }}" class="btn btn-warning btn-block text-white"> <i class="fa fa-sync d-block"></i>Reindex </a> </div> <div class="col-sm-4 p-2 d-grid "> <a class="btn btn-warning btn-block text-white import-file-link"> <i class="fa fa-upload d-block"></i>Import --mongoexport json </a> <input class="d-none import-input-file" type="file" name="import-file" collection-name="{{ collectionName | url_encode }}" /> </div> {% if !settings.read_only %} <div class="col-sm-4 p-2 d-grid "> <a href="{{ dbUrl }}/compact/{{ collectionName | url_encode }}" class="btn btn-danger btn-block"> <i class="fa fa-compress d-block"></i>Compact </a> </div> {% if !settings.no_delete %} <div class="col-sm-4 p-2 d-grid "> <form method="POST" class="d-grid" action="{{ baseHref }}db/{{ dbName }}/{{ collectionName | url_encode }}" id="db-{{ dbName }}-{{ collectionName }}"> <input type="hidden" name="_csrf" value="{{ csrfToken }}"> <input type="hidden" name="_method" value="delete"> <button type="submit" class="btn btn-danger d-grid deleteButtonCollection btn-block" data-collection-name="{{ collectionName }}"> <i class="fa fa-trash d-block"></i>Delete </button> </form> </div> {% endif %} {% endif %} </div> </div> </div> {% if !settings.no_delete %} <div class="modal fade" id="confirm-deletion-document" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-body"> Are you sure? </div> <div class="modal-footer"> <button type="button" data-bs-dismiss="modal" class="btn btn-danger" id="delete">Delete</button> <button type="button" data-bs-dismiss="modal" class="btn">Cancel</button> </div> </div> </div> </div> <div class="modal fade" id="deleteListModal" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-body"> Are you sure you want to delete all {{count}} documents? </div> <div class="modal-footer"> <button type="button" data-bs-dismiss="modal" class="btn btn btn-danger" id="deleteListConfirmButton">Delete</button> <button type="button" data-bs-dismiss="modal" class="btn">Cancel</button> </div> </div> </div> </div> <div class="modal fade" id="confirm-deletion-collection" tabindex="-1" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Delete collection</h5> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <p> Be careful! You are about to delete whole <strong><span id="modal-collection-name"></span></strong> collection. </p> <p> <label for="confirmation-input">Type the database name to proceed:</label> <input type="text" id="confirmation-input" name="confirmation-input" shouldbe="" value="" /> </p> </div> <div class="modal-footer"> <button type="button" data-bs-dismiss="modal" class="btn btn btn-danger" id="deleteCollectionConfirmation">Delete</button> <button type="button" data-bs-dismiss="modal" class="btn">Cancel</button> </div> </div> </div> </div> {% endif %} {% if stats != false %} <div class="card mb-3"> <h2 class="card-header">Collection stats</h2> <table class="table table-bordered table-striped"> <tr> <td> <strong>Documents</strong> </td> <td> {{ stats.count }} </td> </tr> <tr> <td> <strong>Total doc size</strong> </td> <td> {{ stats.size|convertBytes }} </td> </tr> <tr> <td> <strong>Average doc size</strong> </td> <td> {{ stats.avgObjSize|convertBytes }} </td> </tr> <tr> <td> <strong>Pre-allocated size</strong> </td> <td> {{ stats.storageSize|convertBytes }} </td> </tr> <tr> <td> <strong>Indexes</strong> </td> <td> {{ stats.nindexes }} </td> </tr> <tr> <td> <strong>Total index size</strong> </td> <td> {{ stats.totalIndexSize|convertBytes }} </td> </tr> <tr> <td> <strong>Padding factor</strong> </td> <td> {{ stats.paddingFactor }} </td> </tr> <tr> <td> <strong>Extents</strong> </td> <td> {{ stats.numExtents }} </td> </tr> </table> </div> <div class="card mb-3"> <h2 class="card-header">Indexes</h2> <table class="table table-bordered table-striped"> <tr> <th>Name</th> <th>Columns</th> <th>Size</th> <th>Attributes</th> <th>Actions</th> </tr> {% for index in indexes %} <tr> <td> {{ index.name }} </td> <td> {% for sort in index.key %} <div>{{ loop.key }} &nbsp; {% if sort == 1 %} ASC {% else %} DSC {% endif %}</div> {% endfor %} </td> <td> {{ index.size|convertBytes }} </td> <td> {% for k,v in index %} <div> {% if k != 'key' && k != 'v' && k != 'name' && k != 'ns' && k != 'size' %} {{ k }}: {% if k == 'partialFilterExpression' %} <pre>{{ v | json | safe }}</pre> {% else %} &nbsp;{{ v }} {% endif %} {% endif %} </div> {% endfor %} </td> {% if !settings.read_only && !settings.no_delete %} <td> <a class="btn btn-danger" href="{{ dbUrl }}/dropIndex/{{ collectionName | url_encode }}?name={{ index.name }}"> <i class="fa fa-trash"></i> Delete </a> </td> {% else %} <td> </td> {% endif %} </tr> {% endfor %} </table> </div> {% endif %} {% endblock %} {% block scripts %} <script src="{{ baseHref }}{{assets.codemirror.js}}"></script> <script src="{{ baseHref }}{{assets.collection.js}}"></script> {% endblock %}